1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <sys/socket.h>
33 #include <sys/un.h>
34
35 #include "log.h"
36 #include "webserver.h"
37
38 #include "../util/systhr.h"
39
40 #include <cx/utils.h>
41 #include <cx/buffer.h>
42 #include <cx/printf.h>
43
44 #include "srvctrl.h"
45
46 #define SRVCTRL_THREAD_STACKSIZE 262144
47
48 static int srvctrl;
49 static cxmutstr srvctrl_path;
50
51 static WSBool srv_shutdown;
52
53 int srvctrl_init(ServerConfiguration *cfg) {
54
55
56 srvctrl_path = cx_asprintf(
"%s/private/srvctrl.sock", cfg->tmp.ptr);
57 struct sockaddr_un addr;
58 if(srvctrl_path.length >
sizeof(addr.sun_path)-
1) {
59 log_ereport(
60 LOG_CATASTROPHE,
61 "path ''%s'' too long for unix domain socket",
62 srvctrl_path.ptr);
63 return -
1;
64 }
65
66
67
68 if(unlink(srvctrl_path.ptr)) {
69 if(errno !=
ENOENT) {
70 log_ereport(
71 LOG_CATASTROPHE,
72 "cannot unlink old srvctrl socket ''%s'': %s",
73 srvctrl_path.ptr,
74 strerror(errno));
75 return -
1;
76 }
77 }
78
79 ZERO(&addr,
sizeof(addr));
80 addr.sun_family =
AF_UNIX;
81 memcpy(addr.sun_path, srvctrl_path.ptr, srvctrl_path.length);
82
83 srvctrl = socket(
AF_UNIX,
SOCK_STREAM,
0);
84 if(srvctrl == -
1) {
85 log_ereport(
86 LOG_CATASTROPHE,
87 "Cannot create server control socket: %s",
88 strerror(errno));
89 return -
1;
90 }
91 if(bind(srvctrl, (
struct sockaddr*)&addr,
sizeof(addr))) {
92 log_ereport(
93 LOG_CATASTROPHE,
94 "srvctrl socket bind failed: %s",
95 strerror(errno));
96 return -
1;
97 }
98
99 return 0;
100 }
101
102 int srvctrl_wait() {
103 listen(srvctrl,
8);
104
105 for(;;) {
106 int fd = accept(srvctrl,
NULL,
0);
107 if(fd <
0) {
108 if(srv_shutdown)
break;
109 log_ereport(
110 LOG_FAILURE,
111 "srvctrl: accept failed: %s",
112 strerror(errno));
113 break;
114 }
115
116 SrvCtrlClient *client = srvctrl_create_client(fd);
117 SYS_THREAD t = systhread_start(
118 SYSTHREAD_DEFAULT_PRIORITY,
119 SRVCTRL_THREAD_STACKSIZE,
120 (thrstartfunc)srvctrl_thread,
121 client);
122 systhread_detach(t);
123
124 }
125
126 close(srvctrl);
127 unlink(srvctrl_path.ptr);
128 free(srvctrl_path.ptr);
129
130 return 0;
131 }
132
133 void srvctrl_shutdown() {
134 srv_shutdown =
TRUE;
135 shutdown(srvctrl,
SHUT_RDWR);
136 }
137
138 SrvCtrlClient* srvctrl_create_client(
int fd) {
139 SrvCtrlClient *client = malloc(
sizeof(SrvCtrlClient));
140 ZERO(client,
sizeof(SrvCtrlClient));
141 client->fd = fd;
142 return client;
143 }
144
145 void* srvctrl_thread(SrvCtrlClient *client) {
146 LogDup log;
147 log.write = (log_writefunc)srvctrl_log;
148 log.cookie = client;
149 log_add_logdup(&log);
150
151 char buf[
64];
152 CxBuffer line;
153 cxBufferInit(&line,
NULL,
32, cxDefaultAllocator,
CX_BUFFER_AUTO_EXTEND|
CX_BUFFER_FREE_CONTENTS);
154
155 ssize_t r;
156 WSBool br =
FALSE;
157 while((r = read(client->fd, buf,
64)) >
0) {
158 for(
int i=
0;i<r;i++) {
159 char c = buf[i];
160 if(c ==
'\n') {
161 cxmutstr ln = cx_mutstrn(line.space, line.pos);
162 if(srvctrl_handle_cmd(client, ln)) {
163 br =
TRUE;
164 break;
165 }
166 }
else {
167 cxBufferPut(&line, c);
168 }
169 }
170 if(br) {
171 break;
172 }
173 }
174 log_remove_logdup(&log);
175
176 cxBufferDestroy(&line);
177 close(client->fd);
178 free(client);
179 return NULL;
180 }
181
182 int srvctrl_handle_cmd(SrvCtrlClient *client, cxmutstr cmd) {
183 if(!cx_strcmp(cx_strcast(cmd), cx_str(
"reconfig"))) {
184 log_ereport(
LOG_INFORM,
"reconfigure server");
185 if(!webserver_reconfig()) {
186 log_ereport(
LOG_INFORM,
"reconfig: success");
187 }
188 }
else if(!cx_strcmp(cx_strcast(cmd), cx_str(
"shutdown"))) {
189 webserver_shutdown();
190 }
else if(!cx_strcmp(cx_strcast(cmd), cx_str(
"stat"))) {
191
192 }
else if(!cx_strcmp(cx_strcast(cmd), cx_str(
"log"))) {
193 return 0;
194 }
else {
195 log_ereport(
196 LOG_FAILURE,
197 "unknown srvctrl command: %.*s",
198 (
int)cmd.length,
199 cmd.ptr);
200 }
201 return 1;
202 }
203
204 void srvctrl_log(SrvCtrlClient *client,
char *msg,
size_t len) {
205 char msgheader[
4];
206 msgheader[
0] =
SRV_MSG_LOG;
207 uint16_t msglen = len;
208 memcpy(&msgheader[
1], &msglen,
2);
209 write(client->fd, msgheader,
3);
210
211 size_t pos =
0;
212 ssize_t w =
0;
213 while(pos < len) {
214 w = write(client->fd, msg + pos, len - pos);
215 if(w <=
0) {
216 break;
217 }
218 pos += w;
219 }
220 }
221