c_cpp 控制平面:推送命令和获取结果

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c_cpp 控制平面:推送命令和获取结果相关的知识,希望对你有一定的参考价值。

/* For sockaddr_in */
#include <netinet/in.h>
/* For socket functions */
#include <sys/socket.h>
/* For fcntl */
#include <fcntl.h>
/* for select */
#include <sys/select.h>

#include <assert.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>

#include "live-cmd.h"

#define MAX_LINE 16384

#ifdef DEBUG
#define COMMENT(x) printf("%s\n", x)
#else
#define COMMENT(x) {}
#endif

static struct fd_state *states[FD_SETSIZE];
static int log[LIVE_TYPE_MAX]; /* store activated fd */

struct fd_state {
    char buffer[MAX_LINE];
    size_t buffer_used;

	FILE *fp;
	int done;

    int writing;
    size_t n_written;
    size_t write_upto;
};

struct fd_state *
alloc_fd_state(void)
{
    struct fd_state *state = malloc(sizeof(struct fd_state));
    if (!state)
        return NULL;
    state->buffer_used = state->n_written = state->writing =
        state->write_upto = state->done = 0;
    return state;
}

void
free_fd_state(struct fd_state *state)
{
    free(state);
}

void
make_nonblocking(int fd)
{
    fcntl(fd, F_SETFL, O_NONBLOCK);
}

int
do_read(int fd, struct fd_state *state)
{
    int i;
    ssize_t result;

	if(state->fp)
	{
		int ret;
		
		COMMENT("Data plane");
		ret = read(fd, state->buffer+state->buffer_used, sizeof(state->buffer)-state->buffer_used);
		
		if(ret > 0)
		{
			state->buffer_used += ret;
		}
		else if(ret == 0)
		{
			state->done = 1;
#if 1
			result = sprintf(state->buffer+state->buffer_used, "\n\nFinished\n\0");
			state->buffer_used += result;
#endif
		}
	}
	else
	{
		LiveCmd cmd;
		
		COMMENT("Ctrl plane");
		result = recv(fd, &cmd, sizeof(cmd), MSG_WAITALL);

		if(result > 0)
		{
			if(cmd.op == LIVE_SET)
			{
				char cmd_string[1024]; /* FIXME */
				int act_fd = log[cmd.type];
				FILE *fp = NULL;
				
				*cmd_string = '\0';

				if(act_fd != -1)
				{
					COMMENT("First, stop existing process");
					COMMENT("Close data plane");
					if(states[act_fd]->fp)
						pclose(states[act_fd]->fp);
					free_fd_state(states[act_fd]);
					states[act_fd] = NULL;
				}

				if(cmd.type == LIVE_PING)
				{
					char count_opt[128];
					char interval_opt[128];
					char timeout_opt[128];

					*count_opt = *interval_opt = *timeout_opt = '\0';

					if(cmd.ping.count)
					{
						sprintf(count_opt, " -c %d ", cmd.ping.count);
					}
					if(cmd.ping.interval)
					{
#if LINUX
						sprintf(interval_opt, " -i %d ", cmd.ping.interval);
#endif
					}
					if(cmd.ping.timeout)
					{
#if LINUX
						sprintf(timeout_opt, " -t %d ", cmd.ping.timeout);
#else
						sprintf(timeout_opt, " -i %d ", cmd.ping.timeout);
#endif
					}
					if(strlen(cmd.target))
					{
						sprintf(cmd_string, "ping %s %s %s %s", count_opt, interval_opt, timeout_opt, cmd.target);
					}
				}
				else if(cmd.type == LIVE_TRACERT)
				{
					char wait_opt[128];
					char ttl_opt[128];

					*wait_opt = *ttl_opt = '\0';

					if(cmd.tracert.wait)
					{
						sprintf(wait_opt, " -w %d ", cmd.tracert.wait);
					}
					if(cmd.tracert.ttl)
					{
						sprintf(ttl_opt, " -m %d ", cmd.tracert.ttl);
					}
					if(strlen(cmd.target))
					{
						sprintf(cmd_string, "traceroute %s %s %s", ttl_opt, wait_opt, cmd.target);
					}
				}

				if(strlen(cmd_string))
				{
					COMMENT(cmd_string);
					fp = popen(cmd_string, "r");
				}

				if(fp)
				{
					int popen_fd;

					popen_fd = fileno(fp);
					states[popen_fd] = alloc_fd_state();
					states[popen_fd]->fp = fp;

					log[cmd.type] = popen_fd;
				}
			}
			else if(cmd.op == LIVE_GET)
			{
				int act_fd = log[cmd.type];

				if(act_fd != -1)
				{
					COMMENT("Prepare data to write");
					memcpy(state->buffer, states[act_fd], states[act_fd]->buffer_used);
					state->writing = 1;
					state->write_upto = states[act_fd]->buffer_used;

					COMMENT("Clear existing data");
					states[act_fd]->buffer_used = 0;

					COMMENT("Close finished data plane");
					if(states[act_fd]->done)
					{
						if(states[act_fd]->fp)
							pclose(states[act_fd]->fp);
						free_fd_state(states[act_fd]);
						states[act_fd] = NULL;
						log[cmd.type] = -1;
					}
				}
				else
				{
					COMMENT("There is no existing process");
					return -1;
				}
			}
		}
		else if(result == 0)
		{
			COMMENT("End of receiving data");
			return 1;
		}
	}

    return 0;
}

int
do_write(int fd, struct fd_state *state)
{
    while (state->n_written < state->write_upto) {
        ssize_t result = send(fd, state->buffer + state->n_written,
                              state->write_upto - state->n_written, 0);
        if (result < 0) {
            if (errno == EAGAIN)
                return 0;
            return -1;
        }
        assert(result != 0);

        state->n_written += result;
    }

    if (state->n_written == state->buffer_used)
        state->n_written = state->write_upto = state->buffer_used = 0;

    state->writing = 0;

	COMMENT("End of transfering data");
    return 1;
}

void
run(void)
{
    int listener;
    struct sockaddr_in sin;
    int i, maxfd;
    fd_set readset, writeset, exset;

    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = 0;
    sin.sin_port = htons(40713);

    for (i = 0; i < FD_SETSIZE; ++i)
        states[i] = NULL;
	for (i = 0; i < LIVE_TYPE_MAX; ++i)
		log[i] = -1;

    listener = socket(AF_INET, SOCK_STREAM, 0);
    make_nonblocking(listener);

#ifndef WIN32
    {
        int one = 1;
        setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
    }
#endif

    if (bind(listener, (struct sockaddr*)&sin, sizeof(sin)) < 0) {
        perror("bind");
        return;
    }

    if (listen(listener, 16)<0) {
        perror("listen");
        return;
    }

    FD_ZERO(&readset);
    FD_ZERO(&writeset);
    FD_ZERO(&exset);

    while (1) {
        maxfd = listener;

        FD_ZERO(&readset);
        FD_ZERO(&writeset);
        FD_ZERO(&exset);

        FD_SET(listener, &readset);

        for (i=0; i < FD_SETSIZE; ++i) {
            if (states[i]) {
                if (i > maxfd)
                    maxfd = i;
				if(!states[i]->done) {
                	FD_SET(i, &readset);
				}
                if (states[i]->writing) {
                    FD_SET(i, &writeset);
                }
            }
        }

        if (select(maxfd+1, &readset, &writeset, &exset, NULL) < 0) {
            perror("select");
            return;
        }

        if (FD_ISSET(listener, &readset)) {
            struct sockaddr_storage ss;
            socklen_t slen = sizeof(ss);
            int fd = accept(listener, (struct sockaddr*)&ss, &slen);
            if (fd < 0) {
                perror("accept");
            } else if (fd > FD_SETSIZE) {
                close(fd);
            } else {
                make_nonblocking(fd);
                states[fd] = alloc_fd_state();
                assert(states[fd]);/*XXX*/
            }
        }

        for (i=0; i < maxfd+1; ++i) {
            int r = 0;
            if (i == listener)
                continue;

            if (FD_ISSET(i, &readset)) {
                r = do_read(i, states[i]);
            }
            if (FD_ISSET(i, &writeset)) {
                r = do_write(i, states[i]);
            }
			if(r)
			{
				COMMENT("Close ctrl plane");
				free_fd_state(states[i]);
				states[i] = NULL;
				close(i);
			}
        }
    }
}

int
main(int c, char **v)
{
    setvbuf(stdout, NULL, _IONBF, 0);

    run();
    return 0;
}

以上是关于c_cpp 控制平面:推送命令和获取结果的主要内容,如果未能解决你的问题,请参考以下文章

docker学习之——获取和推送镜像

c_cpp 在执行命令之前设置控制台模式

求教CAD命令,高手不吝赐教!!!验证后可追加分

c_cpp 执行命令并获取输出

c_cpp 给定2D平面上的n个点,找到位于同一直线上的最大点数

获取在控制台输入命令后的结果