/* * Copyright 2019 Olaf Wintermann * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include "srvctrl.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define TIMEOUT_IDLE -1 #define TIMEOUT_CLIENT 1000 #define CLIENT_UPDATE_INTERVALL 1 static char *socket_path; static int srvctrl; int create_control_socket(void) { const char *copydir = mzcp_get_copydir(); // create unix domain socket char *random_str = util_random_str(); sstr_t socketp = ucx_sprintf("%s/%.*s", copydir, 8, random_str); free(random_str); socket_path = socketp.ptr; struct sockaddr_un addr; if(socketp.length > sizeof(addr.sun_path)-1) { fprintf(stderr, "path '%s' too long for unix domain socket", socketp.ptr); return 1; } memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; memcpy(addr.sun_path, socketp.ptr, socketp.length); srvctrl = socket(AF_UNIX, SOCK_STREAM, 0); if(srvctrl == -1) { fprintf(stderr, "Cannot create server control socket: %s", strerror(errno)); return 1; } if(bind(srvctrl, (struct sockaddr*)&addr, sizeof(addr))) { fprintf(stderr, "srvctrl socket bind failed: %s", strerror(errno)); return 1; } listen(srvctrl, 4); return 0; } const char* mzcp_get_socketpath(void) { return socket_path; } int mzcp_srvctrl(CPSettings *settings) { size_t allocfds = 8; size_t numfds = 1; struct pollfd *fds = calloc(allocfds, sizeof(struct pollfd)); CtrlClient **clients = calloc(allocfds, sizeof(void*)); int timeout = TIMEOUT_IDLE; fds[0].fd = srvctrl; fds[0].events = POLLIN; int abort = 0; time_t tbegin = time(NULL); while(poll(fds, numfds, 1000) >= 0) { time_t tend = time(NULL); time_t diff = tend - tbegin; tbegin = tend; if((fds[0].revents & POLLIN) == POLLIN) { printf("accept\n"); int fd = accept(srvctrl, NULL, 0); if(fd < 0) { break; } //int flags = fcntl(fd, F_GETFL, 0); //flags = flags & ~O_NONBLOCK; //fcntl(fd, F_SETFL, flags); CtrlClient *client = malloc(sizeof(CtrlClient)); memset(client, 0, sizeof(CtrlClient)); client->fd = fd; printf("add client: %d\n", client->fd); fds[numfds].fd = client->fd; fds[numfds].events = POLLIN; fds[numfds].revents = 0; clients[numfds] = client; numfds++; } // check clients int remove = 0; for(int i=1;ibuf + client->pos, CLIENT_MSG_BUFSIZE - client->pos); if(r <= 0) { printf("remove client: %d\n", fds[i].fd); fds[i].events = 0; remove = 1; } else { client->pos += r; int msgret = handle_messages(client); if(msgret == 1) { fds[i].events = 0; remove = 1; } else if(msgret == -1) { abort = 1; } } } } if(remove) { int j = 1; for(int i=1;i= CLIENT_UPDATE_INTERVALL) { for(int i=1;i 1 ? TIMEOUT_CLIENT : TIMEOUT_IDLE; } unlink(socket_path); return 0; } void client_free(CtrlClient *client) { free(client); } int handle_messages(CtrlClient *client) { if(client->pos == CLIENT_MSG_BUFSIZE) { return 1; } int msgstart = 0; for(int i=0;ipos;i++) { if(client->buf[i] == '\n') { sstr_t msg; msg.ptr = &client->buf[msgstart]; msg.length = i - msgstart; msgstart = i+1; int msgret = handle_client_msg(client, msg); if(msgret) return msgret; } } if(msgstart < client->pos) { // incomplete message memmove(client->buf, client->buf + msgstart, client->pos - msgstart); client->pos -= msgstart; } else { client->pos = 0; } return 0; } int handle_client_msg(CtrlClient *client, sstr_t msg) { printf("msg: %.*s\n", (int)msg.length, msg.ptr); if(!sstrcmp(msg, S("abort"))) { return -1; } return 0; } void client_send_status(CtrlClient *client) { char *msg = "s 0\n"; write(client->fd, msg, strlen(msg)); }