| | varnish-cache/bin/varnishtest/vtc_server.c |
0 |
|
/*- |
1 |
|
* Copyright (c) 2008-2010 Varnish Software AS |
2 |
|
* All rights reserved. |
3 |
|
* |
4 |
|
* Author: Poul-Henning Kamp <phk@phk.freebsd.dk> |
5 |
|
* |
6 |
|
* SPDX-License-Identifier: BSD-2-Clause |
7 |
|
* |
8 |
|
* Redistribution and use in source and binary forms, with or without |
9 |
|
* modification, are permitted provided that the following conditions |
10 |
|
* are met: |
11 |
|
* 1. Redistributions of source code must retain the above copyright |
12 |
|
* notice, this list of conditions and the following disclaimer. |
13 |
|
* 2. Redistributions in binary form must reproduce the above copyright |
14 |
|
* notice, this list of conditions and the following disclaimer in the |
15 |
|
* documentation and/or other materials provided with the distribution. |
16 |
|
* |
17 |
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
18 |
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
19 |
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
20 |
|
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE |
21 |
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
22 |
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
23 |
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
24 |
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
25 |
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
26 |
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
27 |
|
* SUCH DAMAGE. |
28 |
|
*/ |
29 |
|
|
30 |
|
#include "config.h" |
31 |
|
|
32 |
|
#include <sys/socket.h> |
33 |
|
#include <sys/types.h> |
34 |
|
#include <sys/stat.h> |
35 |
|
|
36 |
|
#include <stdio.h> |
37 |
|
#include <stdlib.h> |
38 |
|
#include <string.h> |
39 |
|
#include <unistd.h> |
40 |
|
|
41 |
|
#include "vsa.h" |
42 |
|
#include "vtc.h" |
43 |
|
|
44 |
|
#include "vtcp.h" |
45 |
|
#include "vus.h" |
46 |
|
|
47 |
|
struct server { |
48 |
|
unsigned magic; |
49 |
|
#define SERVER_MAGIC 0x55286619 |
50 |
|
char *name; |
51 |
|
struct vtclog *vl; |
52 |
|
VTAILQ_ENTRY(server) list; |
53 |
|
struct vtc_sess *vsp; |
54 |
|
char run; |
55 |
|
|
56 |
|
char *spec; |
57 |
|
|
58 |
|
int depth; |
59 |
|
int sock; |
60 |
|
int fd; |
61 |
|
unsigned is_dispatch; |
62 |
|
char listen[256]; |
63 |
|
char aaddr[VTCP_ADDRBUFSIZE]; |
64 |
|
char aport[VTCP_PORTBUFSIZE]; |
65 |
|
|
66 |
|
pthread_t tp; |
67 |
|
}; |
68 |
|
|
69 |
|
static pthread_mutex_t server_mtx; |
70 |
|
|
71 |
|
static VTAILQ_HEAD(, server) servers = |
72 |
|
VTAILQ_HEAD_INITIALIZER(servers); |
73 |
|
|
74 |
|
/********************************************************************** |
75 |
|
* Allocate and initialize a server |
76 |
|
*/ |
77 |
|
|
78 |
|
static struct server * |
79 |
41930 |
server_new(const char *name, struct vtclog *vl) |
80 |
|
{ |
81 |
|
struct server *s; |
82 |
|
|
83 |
41930 |
VTC_CHECK_NAME(vl, name, "Server", 's'); |
84 |
41930 |
ALLOC_OBJ(s, SERVER_MAGIC); |
85 |
41930 |
AN(s); |
86 |
41930 |
REPLACE(s->name, name); |
87 |
41930 |
s->vl = vtc_logopen("%s", s->name); |
88 |
41930 |
AN(s->vl); |
89 |
41930 |
s->vsp = Sess_New(s->vl, name); |
90 |
41930 |
AN(s->vsp); |
91 |
|
|
92 |
41930 |
bprintf(s->listen, "%s", default_listen_addr); |
93 |
41930 |
s->depth = 10; |
94 |
41930 |
s->sock = -1; |
95 |
41930 |
s->fd = -1; |
96 |
41930 |
PTOK(pthread_mutex_lock(&server_mtx)); |
97 |
41930 |
VTAILQ_INSERT_TAIL(&servers, s, list); |
98 |
41930 |
PTOK(pthread_mutex_unlock(&server_mtx)); |
99 |
41930 |
return (s); |
100 |
|
} |
101 |
|
|
102 |
|
/********************************************************************** |
103 |
|
* Clean up a server |
104 |
|
*/ |
105 |
|
|
106 |
|
static void |
107 |
41930 |
server_delete(struct server *s) |
108 |
|
{ |
109 |
|
|
110 |
41930 |
CHECK_OBJ_NOTNULL(s, SERVER_MAGIC); |
111 |
41930 |
Sess_Destroy(&s->vsp); |
112 |
41930 |
macro_undef(s->vl, s->name, "addr"); |
113 |
41930 |
macro_undef(s->vl, s->name, "port"); |
114 |
41930 |
macro_undef(s->vl, s->name, "sock"); |
115 |
41930 |
vtc_logclose(s->vl); |
116 |
41930 |
free(s->name); |
117 |
|
/* XXX: MEMLEAK (?) (VSS ??) */ |
118 |
41930 |
FREE_OBJ(s); |
119 |
41930 |
} |
120 |
|
|
121 |
|
/********************************************************************** |
122 |
|
* Server listen |
123 |
|
*/ |
124 |
|
|
125 |
|
struct helper { |
126 |
|
int depth; |
127 |
|
const char **errp; |
128 |
|
}; |
129 |
|
|
130 |
|
/* cf. VTCP_listen_on() */ |
131 |
|
static int v_matchproto_(vus_resolved_f) |
132 |
2360 |
uds_listen(void *priv, const struct sockaddr_un *uds) |
133 |
|
{ |
134 |
|
int sock, e; |
135 |
2360 |
struct helper *hp = priv; |
136 |
|
|
137 |
2360 |
sock = VUS_bind(uds, hp->errp); |
138 |
2360 |
if (sock >= 0) { |
139 |
2360 |
if (listen(sock, hp->depth) != 0) { |
140 |
0 |
e = errno; |
141 |
0 |
closefd(&sock); |
142 |
0 |
errno = e; |
143 |
0 |
if (hp->errp != NULL) |
144 |
0 |
*hp->errp = "listen(2)"; |
145 |
0 |
return (-1); |
146 |
|
} |
147 |
2360 |
} |
148 |
2360 |
if (sock > 0) { |
149 |
2360 |
*hp->errp = NULL; |
150 |
2360 |
return (sock); |
151 |
|
} |
152 |
0 |
AN(*hp->errp); |
153 |
0 |
return (0); |
154 |
2360 |
} |
155 |
|
|
156 |
|
static void |
157 |
2360 |
server_listen_uds(struct server *s, const char **errp) |
158 |
|
{ |
159 |
|
mode_t m; |
160 |
|
struct helper h; |
161 |
|
|
162 |
2360 |
h.depth = s->depth; |
163 |
2360 |
h.errp = errp; |
164 |
|
|
165 |
2360 |
errno = 0; |
166 |
2360 |
if (unlink(s->listen) != 0 && errno != ENOENT) |
167 |
0 |
vtc_fatal(s->vl, "Could not unlink %s before bind: %s", |
168 |
0 |
s->listen, strerror(errno)); |
169 |
|
/* |
170 |
|
* Temporarily set the umask to 0 to avoid issues with |
171 |
|
* permissions. |
172 |
|
*/ |
173 |
2360 |
m = umask(0); |
174 |
2360 |
s->sock = VUS_resolver(s->listen, uds_listen, &h, errp); |
175 |
2360 |
(void)umask(m); |
176 |
2360 |
if (*errp != NULL) |
177 |
0 |
return; |
178 |
2360 |
assert(s->sock > 0); |
179 |
2360 |
macro_def(s->vl, s->name, "addr", "0.0.0.0"); |
180 |
2360 |
macro_def(s->vl, s->name, "port", "0"); |
181 |
2360 |
macro_def(s->vl, s->name, "sock", "%s", s->listen); |
182 |
2360 |
} |
183 |
|
|
184 |
|
static void |
185 |
40600 |
server_listen_tcp(struct server *s, const char **errp) |
186 |
|
{ |
187 |
40600 |
char buf[vsa_suckaddr_len]; |
188 |
|
const struct suckaddr *sua; |
189 |
|
|
190 |
40600 |
s->sock = VTCP_listen_on(s->listen, "0", s->depth, errp); |
191 |
40600 |
if (*errp != NULL) |
192 |
0 |
return; |
193 |
40600 |
assert(s->sock > 0); |
194 |
40600 |
sua = VSA_getsockname(s->sock, buf, sizeof buf); |
195 |
40600 |
AN(sua); |
196 |
81200 |
VTCP_name(sua, s->aaddr, sizeof s->aaddr, |
197 |
40600 |
s->aport, sizeof s->aport); |
198 |
|
|
199 |
|
/* Record the actual port, and reuse it on subsequent starts */ |
200 |
40600 |
if (VSA_Get_Proto(sua) == AF_INET) |
201 |
40440 |
bprintf(s->listen, "%s:%s", s->aaddr, s->aport); |
202 |
|
else |
203 |
160 |
bprintf(s->listen, "[%s]:%s", s->aaddr, s->aport); |
204 |
|
|
205 |
40600 |
macro_def(s->vl, s->name, "addr", "%s", s->aaddr); |
206 |
40600 |
macro_def(s->vl, s->name, "port", "%s", s->aport); |
207 |
40600 |
macro_def(s->vl, s->name, "sock", "%s", s->listen); |
208 |
40600 |
} |
209 |
|
|
210 |
|
static void |
211 |
42960 |
server_listen(struct server *s) |
212 |
|
{ |
213 |
|
const char *err; |
214 |
|
|
215 |
42960 |
CHECK_OBJ_NOTNULL(s, SERVER_MAGIC); |
216 |
|
|
217 |
42960 |
if (s->sock >= 0) |
218 |
3520 |
VTCP_close(&s->sock); |
219 |
42960 |
if (VUS_is(s->listen)) |
220 |
2360 |
server_listen_uds(s, &err); |
221 |
|
else |
222 |
40600 |
server_listen_tcp(s, &err); |
223 |
42960 |
if (err != NULL) |
224 |
0 |
vtc_fatal(s->vl, |
225 |
|
"Server listen address (%s) cannot be resolved: %s", |
226 |
0 |
s->listen, err); |
227 |
42960 |
} |
228 |
|
|
229 |
|
/********************************************************************** |
230 |
|
* Server thread |
231 |
|
*/ |
232 |
|
|
233 |
|
static int |
234 |
53821 |
server_conn(void *priv, struct vtclog *vl) |
235 |
|
{ |
236 |
|
struct server *s; |
237 |
|
struct sockaddr_storage addr_s; |
238 |
|
struct sockaddr *addr; |
239 |
|
char abuf[VTCP_ADDRBUFSIZE]; |
240 |
|
char pbuf[VTCP_PORTBUFSIZE]; |
241 |
|
socklen_t l; |
242 |
|
int fd; |
243 |
|
|
244 |
53821 |
CAST_OBJ_NOTNULL(s, priv, SERVER_MAGIC); |
245 |
|
|
246 |
53821 |
addr = (void*)&addr_s; |
247 |
53821 |
l = sizeof addr_s; |
248 |
53821 |
fd = accept(s->sock, addr, &l); |
249 |
53821 |
if (fd < 0) |
250 |
0 |
vtc_fatal(vl, "Accept failed: %s", strerror(errno)); |
251 |
53821 |
if (VUS_is(s->listen)) |
252 |
2360 |
vtc_log(vl, 3, "accepted fd %d 0.0.0.0 0", fd); |
253 |
|
else { |
254 |
51461 |
VTCP_hisname(fd, abuf, sizeof abuf, pbuf, sizeof pbuf); |
255 |
51461 |
vtc_log(vl, 3, "accepted fd %d %s %s", fd, abuf, pbuf); |
256 |
|
} |
257 |
53821 |
return (fd); |
258 |
|
} |
259 |
|
|
260 |
|
static void |
261 |
52855 |
server_disc(void *priv, struct vtclog *vl, int *fdp) |
262 |
|
{ |
263 |
|
int j; |
264 |
|
struct server *s; |
265 |
|
|
266 |
52855 |
CAST_OBJ_NOTNULL(s, priv, SERVER_MAGIC); |
267 |
52855 |
vtc_log(vl, 3, "shutting fd %d", *fdp); |
268 |
52855 |
j = shutdown(*fdp, SHUT_WR); |
269 |
52855 |
if (!vtc_stop && !VTCP_Check(j)) |
270 |
0 |
vtc_fatal(vl, "Shutdown failed: %s", strerror(errno)); |
271 |
52863 |
VTCP_close(fdp); |
272 |
52863 |
} |
273 |
|
|
274 |
|
static void |
275 |
42440 |
server_start_thread(struct server *s) |
276 |
|
{ |
277 |
|
|
278 |
42440 |
s->run = 1; |
279 |
42440 |
s->tp = Sess_Start_Thread( |
280 |
42440 |
s, |
281 |
42440 |
s->vsp, |
282 |
|
server_conn, |
283 |
|
server_disc, |
284 |
42440 |
s->listen, |
285 |
42440 |
&s->sock, |
286 |
42440 |
s->spec |
287 |
|
); |
288 |
42440 |
} |
289 |
|
|
290 |
|
/********************************************************************** |
291 |
|
* Start the server thread |
292 |
|
*/ |
293 |
|
|
294 |
|
static void |
295 |
42440 |
server_start(struct server *s) |
296 |
|
{ |
297 |
42440 |
CHECK_OBJ_NOTNULL(s, SERVER_MAGIC); |
298 |
42440 |
vtc_log(s->vl, 2, "Starting server"); |
299 |
42440 |
server_listen(s); |
300 |
42440 |
vtc_log(s->vl, 1, "Listen on %s", s->listen); |
301 |
42440 |
server_start_thread(s); |
302 |
42440 |
} |
303 |
|
|
304 |
|
/********************************************************************** |
305 |
|
*/ |
306 |
|
|
307 |
|
static void * |
308 |
2610 |
server_dispatch_wrk(void *priv) |
309 |
|
{ |
310 |
|
struct server *s; |
311 |
|
struct vtclog *vl; |
312 |
|
int j, fd; |
313 |
|
|
314 |
2610 |
CAST_OBJ_NOTNULL(s, priv, SERVER_MAGIC); |
315 |
2610 |
assert(s->sock < 0); |
316 |
|
|
317 |
2610 |
vl = vtc_logopen("%s", s->name); |
318 |
2610 |
pthread_cleanup_push(vtc_logclose, vl); |
319 |
|
|
320 |
2610 |
fd = s->fd; |
321 |
|
|
322 |
2610 |
vtc_log(vl, 3, "start with fd %d", fd); |
323 |
2610 |
fd = sess_process(vl, s->vsp, s->spec, fd, &s->sock, s->listen); |
324 |
2610 |
vtc_log(vl, 3, "shutting fd %d", fd); |
325 |
2610 |
j = shutdown(fd, SHUT_WR); |
326 |
2610 |
if (!VTCP_Check(j)) |
327 |
0 |
vtc_fatal(vl, "Shutdown failed: %s", strerror(errno)); |
328 |
2610 |
VTCP_close(&s->fd); |
329 |
2610 |
vtc_log(vl, 2, "Ending"); |
330 |
2610 |
pthread_cleanup_pop(0); |
331 |
2610 |
vtc_logclose(vl); |
332 |
2610 |
return (NULL); |
333 |
|
} |
334 |
|
|
335 |
|
static void * |
336 |
520 |
server_dispatch_thread(void *priv) |
337 |
|
{ |
338 |
|
struct server *s, *s2; |
339 |
|
static int sn = 1; |
340 |
|
int fd; |
341 |
|
char snbuf[8]; |
342 |
|
struct vtclog *vl; |
343 |
|
struct sockaddr_storage addr_s; |
344 |
|
struct sockaddr *addr; |
345 |
|
socklen_t l; |
346 |
|
|
347 |
520 |
CAST_OBJ_NOTNULL(s, priv, SERVER_MAGIC); |
348 |
520 |
assert(s->sock >= 0); |
349 |
|
|
350 |
520 |
vl = vtc_logopen("%s", s->name); |
351 |
520 |
pthread_cleanup_push(vtc_logclose, vl); |
352 |
|
|
353 |
520 |
vtc_log(vl, 2, "Dispatch started on %s", s->listen); |
354 |
|
|
355 |
3130 |
while (!vtc_stop) { |
356 |
2610 |
addr = (void*)&addr_s; |
357 |
2610 |
l = sizeof addr_s; |
358 |
2610 |
fd = accept(s->sock, addr, &l); |
359 |
2610 |
if (fd < 0) |
360 |
0 |
vtc_fatal(vl, "Accepted failed: %s", strerror(errno)); |
361 |
2610 |
bprintf(snbuf, "s%d", sn++); |
362 |
2610 |
vtc_log(vl, 3, "dispatch fd %d -> %s", fd, snbuf); |
363 |
2610 |
s2 = server_new(snbuf, vl); |
364 |
2610 |
s2->is_dispatch = 1; |
365 |
2610 |
s2->spec = s->spec; |
366 |
2610 |
bstrcpy(s2->listen, s->listen); |
367 |
2610 |
s2->fd = fd; |
368 |
2610 |
s2->run = 1; |
369 |
2610 |
PTOK(pthread_create(&s2->tp, NULL, server_dispatch_wrk, s2)); |
370 |
|
} |
371 |
520 |
pthread_cleanup_pop(0); |
372 |
520 |
vtc_logclose(vl); |
373 |
520 |
NEEDLESS(return (NULL)); |
374 |
|
} |
375 |
|
|
376 |
|
static void |
377 |
520 |
server_dispatch(struct server *s) |
378 |
|
{ |
379 |
520 |
CHECK_OBJ_NOTNULL(s, SERVER_MAGIC); |
380 |
520 |
server_listen(s); |
381 |
520 |
vtc_log(s->vl, 2, "Starting dispatch server"); |
382 |
520 |
s->run = 1; |
383 |
520 |
PTOK(pthread_create(&s->tp, NULL, server_dispatch_thread, s)); |
384 |
520 |
} |
385 |
|
|
386 |
|
/********************************************************************** |
387 |
|
* Force stop the server thread |
388 |
|
*/ |
389 |
|
|
390 |
|
static void |
391 |
120 |
server_break(struct server *s) |
392 |
|
{ |
393 |
|
void *res; |
394 |
|
|
395 |
120 |
CHECK_OBJ_NOTNULL(s, SERVER_MAGIC); |
396 |
120 |
vtc_log(s->vl, 2, "Breaking for server"); |
397 |
120 |
(void)pthread_cancel(s->tp); |
398 |
120 |
PTOK(pthread_join(s->tp, &res)); |
399 |
120 |
VTCP_close(&s->sock); |
400 |
120 |
s->tp = 0; |
401 |
120 |
s->run = 0; |
402 |
120 |
} |
403 |
|
|
404 |
|
/********************************************************************** |
405 |
|
* Wait for server thread to stop |
406 |
|
*/ |
407 |
|
|
408 |
|
static void |
409 |
45450 |
server_wait(struct server *s) |
410 |
|
{ |
411 |
|
void *res; |
412 |
|
|
413 |
45450 |
CHECK_OBJ_NOTNULL(s, SERVER_MAGIC); |
414 |
45450 |
vtc_log(s->vl, 2, "Waiting for server (%d/%d)", s->sock, s->fd); |
415 |
45450 |
PTOK(pthread_join(s->tp, &res)); |
416 |
45450 |
if (res != NULL && !vtc_stop) |
417 |
0 |
vtc_fatal(s->vl, "Server returned \"%p\"", |
418 |
0 |
(char *)res); |
419 |
45450 |
s->tp = 0; |
420 |
45450 |
s->run = 0; |
421 |
45450 |
} |
422 |
|
|
423 |
|
/********************************************************************** |
424 |
|
* Generate VCL backend decls for our servers |
425 |
|
*/ |
426 |
|
|
427 |
|
void |
428 |
34400 |
cmd_server_gen_vcl(struct vsb *vsb) |
429 |
|
{ |
430 |
|
struct server *s; |
431 |
|
|
432 |
34400 |
PTOK(pthread_mutex_lock(&server_mtx)); |
433 |
73520 |
VTAILQ_FOREACH(s, &servers, list) { |
434 |
39120 |
if (s->is_dispatch) |
435 |
640 |
continue; |
436 |
|
|
437 |
38480 |
if (VUS_is(s->listen)) |
438 |
1360 |
VSB_printf(vsb, |
439 |
|
"backend %s { .path = \"%s\"; }\n", |
440 |
680 |
s->name, s->listen); |
441 |
|
else |
442 |
75600 |
VSB_printf(vsb, |
443 |
|
"backend %s { .host = \"%s\"; .port = \"%s\"; }\n", |
444 |
37800 |
s->name, s->aaddr, s->aport); |
445 |
38480 |
} |
446 |
34400 |
PTOK(pthread_mutex_unlock(&server_mtx)); |
447 |
34400 |
} |
448 |
|
|
449 |
|
|
450 |
|
/********************************************************************** |
451 |
|
* Generate VCL backend decls for our servers |
452 |
|
*/ |
453 |
|
|
454 |
|
void |
455 |
40 |
cmd_server_gen_haproxy_conf(struct vsb *vsb) |
456 |
|
{ |
457 |
|
struct server *s; |
458 |
|
|
459 |
40 |
PTOK(pthread_mutex_lock(&server_mtx)); |
460 |
80 |
VTAILQ_FOREACH(s, &servers, list) { |
461 |
40 |
if (! VUS_is(s->listen)) |
462 |
80 |
VSB_printf(vsb, |
463 |
|
"\n backend be%s\n" |
464 |
|
"\tserver srv%s %s:%s\n", |
465 |
40 |
s->name + 1, s->name + 1, s->aaddr, s->aport); |
466 |
|
else |
467 |
0 |
INCOMPL(); |
468 |
40 |
} |
469 |
80 |
VTAILQ_FOREACH(s, &servers, list) { |
470 |
40 |
if (! VUS_is(s->listen)) |
471 |
80 |
VSB_printf(vsb, |
472 |
|
"\n frontend http%s\n" |
473 |
|
"\tuse_backend be%s\n" |
474 |
|
"\tbind \"fd@${fe%s}\"\n", |
475 |
40 |
s->name + 1, s->name + 1, s->name + 1); |
476 |
|
else |
477 |
0 |
INCOMPL(); |
478 |
40 |
} |
479 |
40 |
PTOK(pthread_mutex_unlock(&server_mtx)); |
480 |
40 |
} |
481 |
|
|
482 |
|
|
483 |
|
/********************************************************************** |
484 |
|
* Server command dispatch |
485 |
|
*/ |
486 |
|
|
487 |
|
void |
488 |
88600 |
cmd_server(CMD_ARGS) |
489 |
|
{ |
490 |
|
struct server *s; |
491 |
|
|
492 |
88600 |
(void)priv; |
493 |
|
|
494 |
88600 |
if (av == NULL) { |
495 |
|
/* Reset and free */ |
496 |
82090 |
while (1) { |
497 |
82090 |
PTOK(pthread_mutex_lock(&server_mtx)); |
498 |
82090 |
s = VTAILQ_FIRST(&servers); |
499 |
82090 |
CHECK_OBJ_ORNULL(s, SERVER_MAGIC); |
500 |
82090 |
if (s != NULL) |
501 |
41930 |
VTAILQ_REMOVE(&servers, s, list); |
502 |
82090 |
PTOK(pthread_mutex_unlock(&server_mtx)); |
503 |
82090 |
if (s == NULL) |
504 |
40160 |
break; |
505 |
41930 |
if (s->run) { |
506 |
38650 |
(void)pthread_cancel(s->tp); |
507 |
38650 |
server_wait(s); |
508 |
38650 |
} |
509 |
41930 |
if (s->sock >= 0) |
510 |
39320 |
VTCP_close(&s->sock); |
511 |
41930 |
server_delete(s); |
512 |
|
} |
513 |
40160 |
return; |
514 |
|
} |
515 |
|
|
516 |
48440 |
AZ(strcmp(av[0], "server")); |
517 |
48440 |
av++; |
518 |
|
|
519 |
48440 |
PTOK(pthread_mutex_lock(&server_mtx)); |
520 |
60760 |
VTAILQ_FOREACH(s, &servers, list) |
521 |
21440 |
if (!strcmp(s->name, av[0])) |
522 |
9120 |
break; |
523 |
48440 |
PTOK(pthread_mutex_unlock(&server_mtx)); |
524 |
48440 |
if (s == NULL) |
525 |
39320 |
s = server_new(av[0], vl); |
526 |
48440 |
CHECK_OBJ_NOTNULL(s, SERVER_MAGIC); |
527 |
48440 |
av++; |
528 |
|
|
529 |
143400 |
for (; *av != NULL; av++) { |
530 |
94960 |
if (vtc_error) |
531 |
0 |
break; |
532 |
94960 |
if (!strcmp(*av, "-wait")) { |
533 |
4240 |
if (!s->run) |
534 |
0 |
vtc_fatal(s->vl, "Server not -started"); |
535 |
4240 |
server_wait(s); |
536 |
4240 |
continue; |
537 |
|
} |
538 |
|
|
539 |
90720 |
if (!strcmp(*av, "-break")) { |
540 |
120 |
server_break(s); |
541 |
120 |
continue; |
542 |
|
} |
543 |
|
|
544 |
|
/* |
545 |
|
* We do an implicit -wait if people muck about with a |
546 |
|
* running server. |
547 |
|
*/ |
548 |
90600 |
if (s->run) |
549 |
2560 |
server_wait(s); |
550 |
|
|
551 |
90600 |
AZ(s->run); |
552 |
|
|
553 |
90600 |
if (Sess_GetOpt(s->vsp, &av)) |
554 |
3200 |
continue; |
555 |
|
|
556 |
87400 |
if (!strcmp(*av, "-listen")) { |
557 |
2360 |
if (s->sock >= 0) |
558 |
0 |
VTCP_close(&s->sock); |
559 |
2360 |
bprintf(s->listen, "%s", av[1]); |
560 |
2360 |
av++; |
561 |
2360 |
continue; |
562 |
|
} |
563 |
85040 |
if (!strcmp(*av, "-start")) { |
564 |
42440 |
server_start(s); |
565 |
42440 |
continue; |
566 |
|
} |
567 |
42600 |
if (!strcmp(*av, "-dispatch")) { |
568 |
520 |
if (strcmp(s->name, "s0")) |
569 |
0 |
vtc_fatal(s->vl, |
570 |
|
"server -dispatch only works on s0"); |
571 |
520 |
server_dispatch(s); |
572 |
520 |
continue; |
573 |
|
} |
574 |
42080 |
if (**av == '-') |
575 |
0 |
vtc_fatal(s->vl, "Unknown server argument: %s", *av); |
576 |
42080 |
s->spec = *av; |
577 |
42080 |
} |
578 |
88600 |
} |
579 |
|
|
580 |
|
void |
581 |
40160 |
init_server(void) |
582 |
|
{ |
583 |
40160 |
PTOK(pthread_mutex_init(&server_mtx, NULL)); |
584 |
40160 |
} |