/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2021 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #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)); }