2 * Copyright 2019 Olaf Wintermann
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
32 #include <sys/socket.h>
34 #include <sys/fcntl.h>
38 #include <ucx/utils.h>
39 #include <libidav/utils.h>
41 #define TIMEOUT_IDLE -1
42 #define TIMEOUT_CLIENT 1000
43 #define CLIENT_UPDATE_INTERVALL 1
45 static char *socket_path;
50 int create_control_socket(void) {
51 const char *copydir = mzcp_get_copydir();
53 // create unix domain socket
54 char *random_str = util_random_str();
55 sstr_t socketp = ucx_sprintf("%s/%.*s", copydir, 8, random_str);
57 socket_path = socketp.ptr;
59 struct sockaddr_un addr;
60 if(socketp.length > sizeof(addr.sun_path)-1) {
62 "path '%s' too long for unix domain socket",
67 memset(&addr, 0, sizeof(addr));
68 addr.sun_family = AF_UNIX;
69 memcpy(addr.sun_path, socketp.ptr, socketp.length);
71 srvctrl = socket(AF_UNIX, SOCK_STREAM, 0);
74 "Cannot create server control socket: %s",
78 if(bind(srvctrl, (struct sockaddr*)&addr, sizeof(addr))) {
80 "srvctrl socket bind failed: %s",
90 const char* mzcp_get_socketpath(void) {
94 int mzcp_srvctrl(CPSettings *settings) {
99 struct pollfd *fds = calloc(allocfds, sizeof(struct pollfd));
100 CtrlClient **clients = calloc(allocfds, sizeof(void*));
102 int timeout = TIMEOUT_IDLE;
105 fds[0].events = POLLIN;
109 time_t tbegin = time(NULL);
111 while(poll(fds, numfds, 1000) >= 0) {
112 time_t tend = time(NULL);
113 time_t diff = tend - tbegin;
116 if((fds[0].revents & POLLIN) == POLLIN) {
118 int fd = accept(srvctrl, NULL, 0);
123 //int flags = fcntl(fd, F_GETFL, 0);
124 //flags = flags & ~O_NONBLOCK;
125 //fcntl(fd, F_SETFL, flags);
127 CtrlClient *client = malloc(sizeof(CtrlClient));
128 memset(client, 0, sizeof(CtrlClient));
131 printf("add client: %d\n", client->fd);
133 fds[numfds].fd = client->fd;
134 fds[numfds].events = POLLIN;
135 fds[numfds].revents = 0;
136 clients[numfds] = client;
142 for(int i=1;i<numfds;i++) {
143 if((fds[i].revents & POLLIN) == POLLIN) {
144 CtrlClient *client = clients[i];
145 ssize_t r = read(fds[i].fd, client->buf + client->pos, CLIENT_MSG_BUFSIZE - client->pos);
147 printf("remove client: %d\n", fds[i].fd);
153 int msgret = handle_messages(client);
157 } else if(msgret == -1) {
166 for(int i=1;i<numfds;i++) {
167 if(fds[i].events != 0) {
169 clients[j] = clients[j];
172 client_free(clients[i]);
179 if(diff >= CLIENT_UPDATE_INTERVALL) {
180 for(int i=1;i<numfds;i++) {
181 client_send_status(clients[i]);
187 timeout = numfds > 1 ? TIMEOUT_CLIENT : TIMEOUT_IDLE;
196 void client_free(CtrlClient *client) {
200 int handle_messages(CtrlClient *client) {
201 if(client->pos == CLIENT_MSG_BUFSIZE) {
206 for(int i=0;i<client->pos;i++) {
207 if(client->buf[i] == '\n') {
209 msg.ptr = &client->buf[msgstart];
210 msg.length = i - msgstart;
213 int msgret = handle_client_msg(client, msg);
214 if(msgret) return msgret;
218 if(msgstart < client->pos) {
219 // incomplete message
220 memmove(client->buf, client->buf + msgstart, client->pos - msgstart);
221 client->pos -= msgstart;
229 int handle_client_msg(CtrlClient *client, sstr_t msg) {
230 printf("msg: %.*s\n", (int)msg.length, msg.ptr);
232 if(!sstrcmp(msg, S("abort"))) {
239 void client_send_status(CtrlClient *client) {
241 write(client->fd, msg, strlen(msg));