1 /*
2 * LASH
3 *
4 * Copyright (C) 2002 Robert Ham <rah@bash.sh>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #define _GNU_SOURCE /* addrinfo */
22
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <netdb.h>
26 #include <netinet/in.h>
27 #include <string.h>
28 #include <arpa/inet.h>
29 #include <pthread.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <errno.h>
33
34 #include <lash/lash.h>
35 #include <lash/internal_headers.h>
36
37 #include "conn_mgr.h"
38 #include "conn.h"
39 #include "server.h"
40
41 void *conn_mgr_recv_run(void *data);
42 void *conn_mgr_send_run(void *data);
43
44 void
conn_mgr_free(conn_mgr_t * conn_mgr)45 conn_mgr_free(conn_mgr_t * conn_mgr)
46 {
47 conn_t *conn;
48 lash_list_t *list;
49
50 close(conn_mgr->listen_socket);
51
52 for (list = conn_mgr->open_connections; list; list = lash_list_next(list)) {
53 conn = (conn_t *) list->data;
54
55 LASH_DEBUGARGS("closing open connection %ld ('%s')", conn->id,
56 conn_get_str_id(conn));
57 conn_destroy(conn);
58 }
59
60 lash_list_free(conn_mgr->open_connections);
61 conn_mgr->open_connections = NULL;
62 for (list = conn_mgr->connections; list; list = list->next) {
63 conn = (conn_t *) list->data;
64
65 LASH_DEBUGARGS("closing connection %ld ('%s')", conn->id,
66 conn_get_str_id(conn));
67 conn_destroy(conn);
68 }
69 lash_list_free(conn_mgr->connections);
70 conn_mgr->connections = NULL;
71
72 conn_mgr->listen_socket = 0;
73 FD_ZERO(&conn_mgr->sockets);
74 conn_mgr->fd_max = 0;
75 conn_mgr->client_events = NULL;
76
77 pthread_mutex_destroy(&conn_mgr->connections_lock);
78 pthread_mutex_destroy(&conn_mgr->client_event_lock);
79 pthread_cond_destroy(&conn_mgr->client_event_cond);
80 }
81
82 conn_mgr_t *
conn_mgr_new(server_t * server)83 conn_mgr_new(server_t * server)
84 {
85 conn_mgr_t *mgr;
86 int err;
87
88 mgr = lash_malloc0(sizeof(conn_mgr_t));
89 pthread_mutex_init(&mgr->connections_lock, NULL);
90 pthread_mutex_init(&mgr->client_event_lock, NULL);
91 pthread_cond_init(&mgr->client_event_cond, NULL);
92 FD_ZERO(&mgr->sockets);
93
94 mgr->server = server;
95
96 err = conn_mgr_start(mgr);
97 if (err) {
98 if (mgr)
99 conn_mgr_destroy(mgr);
100 return NULL;
101 }
102
103 return mgr;
104 }
105
106 void
conn_mgr_destroy(conn_mgr_t * conn_mgr)107 conn_mgr_destroy(conn_mgr_t * conn_mgr)
108 {
109 LASH_PRINT_DEBUG("stopping");
110 conn_mgr_stop(conn_mgr);
111 LASH_PRINT_DEBUG("stopped");
112
113 conn_mgr_free(conn_mgr);
114 free(conn_mgr);
115 }
116
117 static int
conn_mgr_set_socket_opts(int sock)118 conn_mgr_set_socket_opts(int sock)
119 {
120 int err;
121 int reuse;
122
123 /*
124 * reuse ports. this is so we can bind again quickly after shutting down.
125 */
126 reuse = 1;
127 err = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
128 if (err == -1) {
129 fprintf(stderr, "%s: could not set SO_REUSEADDR on socket: %s\n",
130 __FUNCTION__, strerror(errno));
131 }
132
133 /*
134 * make sure socket is closed on exec()
135 */
136 err = fcntl(sock, F_SETFD, FD_CLOEXEC);
137 if (err == -1) {
138 fprintf(stderr,
139 "%s: could not set close-on-exec on listen socket: %s\n",
140 __FUNCTION__, strerror(errno));
141 return -1;
142 }
143
144 return 0;
145 }
146
147 int
conn_mgr_bind_socket(int * sock,struct addrinfo * addr)148 conn_mgr_bind_socket(int *sock, struct addrinfo *addr)
149 {
150 int err;
151
152 *sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
153 if (*sock == -1) {
154 LASH_DEBUGARGS
155 ("could not create socket with params domain=%d, type=%d, protocol=%d: %s",
156 addr->ai_family, addr->ai_socktype, addr->ai_protocol,
157 strerror(errno));
158 return -1;
159 }
160
161 conn_mgr_set_socket_opts(*sock);
162
163 err = bind(*sock, addr->ai_addr, addr->ai_addrlen);
164 if (err) {
165 LASH_DEBUGARGS("could not bind socket: %s", strerror(errno));
166
167 err = close(*sock);
168 if (err) {
169 fprintf(stderr, "%s: error closing unconnected socket: %s",
170 __FUNCTION__, strerror(errno));
171 }
172
173 return -1;
174 }
175
176 return 0;
177 }
178
179 int
conn_mgr_start(conn_mgr_t * conn_mgr)180 conn_mgr_start(conn_mgr_t * conn_mgr)
181 {
182 struct addrinfo hints;
183 struct addrinfo *addrs;
184 struct addrinfo *addr;
185 int bound = 0;
186 int err;
187
188 memset(&hints, 0, sizeof(hints));
189 hints.ai_socktype = SOCK_STREAM;
190 hints.ai_flags = AI_PASSIVE;
191
192 err = getaddrinfo(NULL, LASH_PORT, &hints, &addrs);
193 if (err) {
194 fprintf(stderr, "%s: could not look up service name: %s\n",
195 __FUNCTION__, gai_strerror(err));
196 return -1;
197 }
198
199 /* try ipv6 first */
200 if (!no_v6)
201 for (addr = addrs; addr; addr = addr->ai_next) {
202 if (addr->ai_family == AF_INET6) {
203 err = conn_mgr_bind_socket(&conn_mgr->listen_socket, addr);
204 if (err)
205 continue;
206 else {
207 bound = 1;
208 break;
209 }
210 }
211 }
212
213 if (!bound)
214 for (addr = addrs; addr; addr = addr->ai_next) {
215 if (no_v6 && addr->ai_family == AF_INET6)
216 continue;
217
218 err = conn_mgr_bind_socket(&conn_mgr->listen_socket, addr);
219 if (err)
220 continue;
221 else {
222 bound = 1;
223 break;
224 }
225 }
226
227 freeaddrinfo(addrs);
228
229 if (!bound) {
230 fprintf(stderr, "%s: could not create listen socket\n", __FUNCTION__);
231 return -1;
232 }
233
234 /* start the listening */
235 err = listen(conn_mgr->listen_socket, 20);
236 if (err == -1) {
237 fprintf(stderr, "%s: error setting socket to listen: %s\n",
238 __FUNCTION__, strerror(errno));
239 return -1;
240 }
241 printf("Listening for connections\n");
242
243 FD_SET(conn_mgr->listen_socket, &conn_mgr->sockets);
244 conn_mgr->fd_max = conn_mgr->listen_socket;
245
246 /* start up the threads */
247 LASH_PRINT_DEBUG("starting recv thread");
248 err =
249 pthread_create(&conn_mgr->recv_thread, NULL, conn_mgr_recv_run,
250 conn_mgr);
251 if (err) {
252 fprintf(stderr, "%s: could not start recv thread\n", __FUNCTION__);
253 abort();
254 }
255 LASH_PRINT_DEBUG("recv thread started; starting send thread");
256 pthread_create(&conn_mgr->send_thread, NULL, conn_mgr_send_run, conn_mgr);
257 LASH_PRINT_DEBUG("send thread started");
258
259 return 0;
260 }
261
262 void
conn_mgr_stop(conn_mgr_t * conn_mgr)263 conn_mgr_stop(conn_mgr_t * conn_mgr)
264 {
265 conn_mgr->quit = 1;
266 pthread_cond_signal(&conn_mgr->client_event_cond);
267 if (conn_mgr->send_thread)
268 pthread_join(conn_mgr->send_thread, NULL);
269 if (conn_mgr->recv_thread)
270 pthread_join(conn_mgr->recv_thread, NULL);
271 }
272
273 void
conn_mgr_send_client_event(conn_mgr_t * conn_mgr,server_event_t * event)274 conn_mgr_send_client_event(conn_mgr_t * conn_mgr, server_event_t * event)
275 {
276 pthread_mutex_lock(&conn_mgr->client_event_lock);
277 conn_mgr->client_events =
278 lash_list_append(conn_mgr->client_events, event);
279 pthread_mutex_unlock(&conn_mgr->client_event_lock);
280 pthread_cond_signal(&conn_mgr->client_event_cond);
281 }
282
283 void
conn_mgr_send_client_lash_event(conn_mgr_t * conn_mgr,unsigned long conn_id,lash_event_t * lash_event)284 conn_mgr_send_client_lash_event(conn_mgr_t * conn_mgr, unsigned long conn_id,
285 lash_event_t * lash_event)
286 {
287 server_event_t *server_event;
288
289 if (!lash_event)
290 return;
291
292 server_event = server_event_new();
293 server_event_set_conn_id(server_event, conn_id);
294 server_event_set_lash_event(server_event, lash_event);
295
296 conn_mgr_send_client_event(conn_mgr, server_event);
297 }
298
299 void
conn_mgr_send_client_lash_config(conn_mgr_t * conn_mgr,unsigned int conn_id,lash_config_t * lash_config)300 conn_mgr_send_client_lash_config(conn_mgr_t * conn_mgr, unsigned int conn_id,
301 lash_config_t * lash_config)
302 {
303 server_event_t *server_event;
304
305 if (!lash_config)
306 return;
307
308 server_event = server_event_new();
309 server_event_set_conn_id(server_event, conn_id);
310 server_event_set_lash_config(server_event, lash_config);
311
312 conn_mgr_send_client_event(conn_mgr, server_event);
313 }
314
315 void
conn_mgr_send_client_lash_comm_event(conn_mgr_t * conn_mgr,unsigned int conn_id,lash_comm_event_t * event)316 conn_mgr_send_client_lash_comm_event(conn_mgr_t * conn_mgr,
317 unsigned int conn_id,
318 lash_comm_event_t * event)
319 {
320 server_event_t *server_event;
321
322 if (!event)
323 return;
324
325 server_event = server_event_new();
326 server_event_set_conn_id(server_event, conn_id);
327 server_event_set_lash_comm_event(server_event, event);
328
329 conn_mgr_send_client_event(conn_mgr, server_event);
330 }
331
332 void
conn_mgr_send_server_lash_event(conn_mgr_t * conn_mgr,unsigned long conn_id,lash_event_t * lash_event)333 conn_mgr_send_server_lash_event(conn_mgr_t * conn_mgr, unsigned long conn_id,
334 lash_event_t * lash_event)
335 {
336 server_event_t *server_event;
337
338 if (!lash_event)
339 return;
340
341 server_event = server_event_new();
342 server_event_set_conn_id(server_event, conn_id);
343 server_event_set_lash_event(server_event, lash_event);
344
345 server_send_event(conn_mgr->server, server_event);
346 }
347
348 void
conn_mgr_send_server_lash_config(conn_mgr_t * conn_mgr,unsigned int conn_id,lash_config_t * lash_config)349 conn_mgr_send_server_lash_config(conn_mgr_t * conn_mgr, unsigned int conn_id,
350 lash_config_t * lash_config)
351 {
352 server_event_t *server_event;
353
354 if (!lash_config)
355 return;
356
357 server_event = server_event_new();
358 server_event_set_conn_id(server_event, conn_id);
359 server_event_set_lash_config(server_event, lash_config);
360
361 server_send_event(conn_mgr->server, server_event);
362 }
363
364 void
conn_mgr_send_server_lash_comm_event(conn_mgr_t * conn_mgr,unsigned int conn_id,lash_comm_event_t * event)365 conn_mgr_send_server_lash_comm_event(conn_mgr_t * conn_mgr,
366 unsigned int conn_id,
367 lash_comm_event_t * event)
368 {
369 server_event_t *server_event;
370
371 if (!event)
372 return;
373
374 server_event = server_event_new();
375 server_event_set_conn_id(server_event, conn_id);
376 server_event_set_lash_comm_event(server_event, event);
377
378 server_send_event(conn_mgr->server, server_event);
379 }
380
381 /***********************************
382 *********** recv thread ***********
383 ***********************************/
384
385 void
conn_mgr_accept_connection(conn_mgr_t * conn_mgr)386 conn_mgr_accept_connection(conn_mgr_t * conn_mgr)
387 {
388 conn_t *conn;
389
390 /*struct sockaddr_storage ss;
391 size_t ss_len;*/
392 int err;
393
394 conn = conn_new();
395
396 /* accept the connection */
397 conn->socket = accept(conn_mgr->listen_socket, NULL, NULL);
398 /*(struct sockaddr *) &ss,
399 * &ss_len); */
400
401 if (conn->socket == -1) {
402 fprintf(stderr,
403 "%s: error accepting socket connection from '%s': %s\n",
404 __FUNCTION__, conn_get_str_id(conn), strerror(errno));
405 conn_destroy(conn);
406 return;
407 }
408 LASH_DEBUGARGS("accepted connection from '%s' with id %ld",
409 conn_get_str_id(conn), conn->id);
410
411 /*
412 * make sure socket is closed on exec()
413 */
414 err = fcntl(conn_mgr->listen_socket, F_SETFD, FD_CLOEXEC);
415 if (err == -1) {
416 fprintf(stderr,
417 "%s: could not set close-on-exec on connection %ld ('%s'): %s\n",
418 __FUNCTION__, conn->id, conn_get_str_id(conn),
419 strerror(errno));
420 exit(1);
421 }
422
423 /* socket stuff */
424 FD_SET(conn->socket, &conn_mgr->sockets);
425 if (conn->socket > conn_mgr->fd_max)
426 conn_mgr->fd_max = conn->socket;
427
428 /* add the connection to the open connection list */
429 conn_mgr->open_connections =
430 lash_list_append(conn_mgr->open_connections, conn);
431 }
432
433 void
conn_mgr_connect_client(conn_mgr_t * conn_mgr,conn_t * conn)434 conn_mgr_connect_client(conn_mgr_t * conn_mgr, conn_t * conn)
435 {
436 lash_comm_event_t *event;
437 server_event_t *server_event;
438 int err;
439 lash_connect_params_t *params;
440 char id[37];
441
442 /* read the Connect event */
443 event = lash_comm_event_new();
444
445 LASH_PRINT_DEBUG("recieving Connect");
446 err = lash_comm_recv_event(conn->socket, event);
447 if (err == -1 ||
448 err == -2 ||
449 err == -3 ||
450 lash_comm_event_get_type(event) != LASH_Comm_Event_Connect ||
451 !LASH_PROTOCOL_IS_VALID(event->event_data.connect->protocol_version))
452 {
453 /* there was an error */
454
455 if (err == -1)
456 fprintf(stderr,
457 "%s: there was a recieve error from connection '%s': disconnecting client\n",
458 __FUNCTION__, conn_get_str_id(conn));
459
460 else if (err == -2)
461 fprintf(stderr,
462 "%s: connection '%s' closed before sending Connect event\n",
463 __FUNCTION__, conn_get_str_id(conn));
464
465 else if (err == -3)
466 fprintf(stderr,
467 "%s: connection '%s' is using the wrong low-level protocol version\n",
468 __FUNCTION__, conn_get_str_id(conn));
469
470 else if (lash_comm_event_get_type(event) != LASH_Comm_Event_Connect)
471 fprintf(stderr,
472 "%s: connection '%s' sent an event (of type %d) that wasn't Connect before it was connected; removing\n",
473 __FUNCTION__, conn_get_str_id(conn),
474 lash_comm_event_get_type(event));
475
476 else if (!LASH_PROTOCOL_IS_VALID
477 (event->event_data.connect->protocol_version)) {
478 lash_comm_event_t mismatch_event;
479
480 fprintf(stderr,
481 "%s: connection '%s' is using protocol %s; disconnecting\n",
482 __FUNCTION__, conn_get_str_id(conn),
483 lash_protocol_string(event->event_data.connect->
484 protocol_version));
485
486 lash_comm_event_set_protocol_mismatch(&mismatch_event,
487 LASH_PROTOCOL_VERSION);
488 lash_comm_send_event(conn->socket, &mismatch_event);
489 }
490
491 lash_comm_event_destroy(event);
492 FD_CLR(conn->socket, &conn_mgr->sockets);
493 conn_mgr->open_connections =
494 lash_list_remove(conn_mgr->open_connections, conn);
495 conn_destroy(conn);
496 return;
497 }
498
499 params = event->event_data.connect;
500 uuid_unparse(params->id, id);
501
502 LASH_PRINT_DEBUG("connecting new client with:");
503 LASH_DEBUGARGS(" connection id: %ld", conn->id);
504 LASH_DEBUGARGS(" source address: %s", conn_get_str_id(conn));
505 LASH_DEBUGARGS(" protocol: %s",
506 lash_protocol_string(event->event_data.connect->
507 protocol_version));
508 LASH_DEBUGARGS(" class: '%s'", params->class);
509 LASH_DEBUGARGS(" id: '%s'", id);
510 LASH_DEBUGARGS(" working dir: '%s'", params->working_dir);
511 LASH_DEBUGARGS(" requested proj: '%s'", params->project);
512 LASH_DEBUGARGS(" flags: %d", params->flags);
513 LASH_DEBUGARGS(" %d args:", params->argc);
514 for (err = 0; err < params->argc; err++) {
515 LASH_DEBUGARGS(" arg %d: '%s'", err, params->argv[err]);
516 }
517
518 /* tell the server there's a new client connection */
519 server_event = server_event_new();
520 server_event_set_conn_id(server_event, conn->id);
521 server_event_set_lash_connect_params(server_event,
522 event->event_data.connect);
523
524 server_send_event(conn_mgr->server, server_event);
525
526 event->event_data.connect = NULL;
527 lash_comm_event_destroy(event);
528
529 /* remove the connection from the open list */
530 conn_mgr->open_connections =
531 lash_list_remove(conn_mgr->open_connections, conn);
532
533 /* add the connection to the connection list */
534 pthread_mutex_lock(&conn_mgr->connections_lock);
535 conn_mgr->connections = lash_list_append(conn_mgr->connections, conn);
536 pthread_mutex_unlock(&conn_mgr->connections_lock);
537
538 conn_set_recv_stamp(conn);
539 }
540
541 void
conn_mgr_disconnect_client(conn_mgr_t * conn_mgr,conn_t * conn,int notify_server)542 conn_mgr_disconnect_client(conn_mgr_t * conn_mgr, conn_t * conn,
543 int notify_server)
544 {
545 unsigned long conn_id;
546
547 /* clear up what we know of the connection */
548 conn_mgr->connections = lash_list_remove(conn_mgr->connections, conn);
549
550 conn_id = conn->id;
551 FD_CLR(conn->socket, &conn_mgr->sockets);
552
553 conn_unlock(conn);
554 conn_destroy(conn);
555
556 if (notify_server) {
557 server_event_t *server_event;
558
559 server_event = server_event_new();
560 server_event_set_type(server_event, Client_Disconnect);
561 server_event_set_conn_id(server_event, conn_id);
562
563 server_send_event(conn_mgr->server, server_event);
564 }
565
566 LASH_DEBUGARGS("disconnected client on connection %ld", conn_id);
567 }
568
569 void
conn_mgr_deal_with_event(conn_mgr_t * conn_mgr,conn_t * conn,lash_comm_event_t * event)570 conn_mgr_deal_with_event(conn_mgr_t * conn_mgr, conn_t * conn,
571 lash_comm_event_t * event)
572 {
573 switch (lash_comm_event_get_type(event)) {
574 case LASH_Comm_Event_Event:
575 conn_mgr_send_server_lash_event(conn_mgr, conn->id,
576 lash_comm_event_take_event(event));
577 lash_comm_event_destroy(event);
578 break;
579 case LASH_Comm_Event_Config:
580 conn_mgr_send_server_lash_config(conn_mgr, conn->id,
581 lash_comm_event_take_config(event));
582 lash_comm_event_destroy(event);
583 break;
584 case LASH_Comm_Event_Ping:
585 lash_comm_event_set_type(event, LASH_Comm_Event_Pong);
586 conn_mgr_send_client_lash_comm_event(conn_mgr, conn->id, event);
587 break;
588 case LASH_Comm_Event_Pong:
589 lash_comm_event_destroy(event);
590 break;
591 default:
592 break;
593 }
594 }
595
596 void
conn_mgr_recv_event(conn_mgr_t * conn_mgr,conn_t * conn)597 conn_mgr_recv_event(conn_mgr_t * conn_mgr, conn_t * conn)
598 {
599 int err;
600 lash_comm_event_t *event;
601
602 /* recieve the event */
603 event = lash_comm_event_new();
604 err = lash_comm_recv_event(conn->socket, event);
605
606 if (err == -1) {
607 fprintf(stderr, "%s: error recieving event from connection '%s'\n",
608 __FUNCTION__, conn_get_str_id(conn));
609 return;
610 }
611
612 /* connection disconnect */
613 if (err == -2 || lash_comm_event_get_type(event) == LASH_Comm_Event_Close) {
614 LASH_DEBUGARGS("%s: connection '%s' disconnected",
615 conn_get_str_id(conn));
616
617 if (lash_comm_event_get_type(event) == LASH_Comm_Event_Close)
618 lash_comm_event_destroy(event);
619
620 conn_mgr_disconnect_client(conn_mgr, conn, 1);
621
622 /* done what we might have done */
623 pthread_mutex_unlock(&conn_mgr->connections_lock);
624 return;
625 }
626
627 /* give up the lock here, as we're definately not messing with it now */
628 pthread_mutex_unlock(&conn_mgr->connections_lock);
629
630 /* this function will destroy the event */
631 conn_mgr_deal_with_event(conn_mgr, conn, event);
632
633 /* reset ping */
634 conn_set_recv_stamp(conn);
635
636 /* unlock the connection */
637 conn_unlock(conn);
638 }
639
640 void
conn_mgr_read_socket(conn_mgr_t * conn_mgr,int socket)641 conn_mgr_read_socket(conn_mgr_t * conn_mgr, int socket)
642 {
643 lash_list_t *list;
644 conn_t *conn;
645
646 /* check if it's a new connection */
647 if (socket == conn_mgr->listen_socket) {
648 conn_mgr_accept_connection(conn_mgr);
649 return;
650 }
651
652 /* see if it's an open connection */
653 list = conn_mgr->open_connections;
654 while (list) {
655 conn = (conn_t *) list->data;
656 if (conn->socket == socket) {
657 conn_mgr_connect_client(conn_mgr, conn);
658 return;
659 }
660
661 list = list->next;
662 }
663
664 /* else find it in the existing connections */
665 pthread_mutex_lock(&conn_mgr->connections_lock);
666 list = conn_mgr->connections;
667 while (list) {
668 conn = (conn_t *) list->data;
669 if (conn->socket == socket) {
670 conn_lock(conn);
671
672 /* must unlock connection! */
673 conn_mgr_recv_event(conn_mgr, conn);
674 return;
675 }
676
677 list = list->next;
678 }
679
680 fprintf(stderr,
681 "%s: could not find a connection with socket %d! this should, like, never happen. you shouldn't be reading this. if you are, bad things have happened. your computer will likely melt after about 20 minutes.",
682 __FUNCTION__, socket);
683 abort();
684 }
685
686 void
conn_mgr_check_timeouts(conn_mgr_t * conn_mgr)687 conn_mgr_check_timeouts(conn_mgr_t * conn_mgr)
688 {
689 lash_list_t *list, *next;
690 conn_t *conn;
691 time_t now;
692
693 now = time(NULL);
694 if (now == (time_t) - 1) {
695 fprintf(stderr, "%s: could not get time, aborting!: %s\n",
696 __FUNCTION__, strerror(errno));
697 abort();
698 }
699
700 pthread_mutex_lock(&conn_mgr->connections_lock);
701 list = conn_mgr->connections;
702 while (list) {
703 conn = (conn_t *) list->data;
704 next = list->next;
705
706 conn_lock(conn);
707
708 if (conn_get_pinged(conn)) {
709 if (conn_ping_timed_out(conn, now)) {
710 fprintf(stderr,
711 "%s: connection '%ld' has not responded to ping for %ld seconds, disconnecting it\n",
712 __FUNCTION__, conn->id, CONN_TIMEOUT);
713 conn_mgr_disconnect_client(conn_mgr, conn, 1);
714 } else
715 conn_unlock(conn);
716 } else {
717 if (conn_recv_timed_out(conn, now)) {
718 /* send a ping */
719 lash_comm_event_t *event;
720
721 /* LASH_DEBUGARGS ("pinging connection '%ld'", conn_get_id (conn)); */
722
723 event = lash_comm_event_new();
724 lash_comm_event_set_type(event, LASH_Comm_Event_Ping);
725 conn_mgr_send_client_lash_comm_event(conn_mgr, conn->id,
726 event);
727 conn_set_ping_stamp(conn);
728 }
729
730 conn_unlock(conn);
731 }
732
733 list = next;
734 }
735 pthread_mutex_unlock(&conn_mgr->connections_lock);
736 }
737
738 void *
conn_mgr_recv_run(void * data)739 conn_mgr_recv_run(void *data)
740 {
741 conn_mgr_t *conn_mgr;
742 fd_set sockets;
743 int err, i;
744 struct timeval select_timeout;
745
746 conn_mgr = (conn_mgr_t *) data;
747
748 while (!conn_mgr->quit) {
749 sockets = conn_mgr->sockets;
750 select_timeout.tv_sec = 1;
751 select_timeout.tv_usec = 0;
752
753 err =
754 select(conn_mgr->fd_max + 1, &sockets, NULL, NULL,
755 &select_timeout);
756 if (err == -1) {
757 if (errno == EINTR)
758 continue;
759
760 fprintf(stderr, "%s: error calling select(): %s\n", __FUNCTION__,
761 strerror(errno));
762
763 if (errno == EBADF)
764 continue;
765 else
766 return NULL;
767 }
768
769 if (conn_mgr->quit)
770 break;
771
772 for (i = 0; i <= conn_mgr->fd_max; i++) {
773 if (FD_ISSET(i, &sockets)) {
774 conn_mgr_read_socket(conn_mgr, i);
775 }
776 }
777
778 conn_mgr_check_timeouts(conn_mgr);
779 }
780
781 LASH_PRINT_DEBUG("finished");
782 return NULL;
783 }
784
785 /****************************************
786 ************ send thread ***************
787 ****************************************/
788
789 void
conn_mgr_send_lash_comm_event_to_client(conn_t * conn,lash_comm_event_t * lash_comm_event)790 conn_mgr_send_lash_comm_event_to_client(conn_t * conn,
791 lash_comm_event_t * lash_comm_event)
792 {
793 int err;
794
795 err = lash_comm_send_event(conn->socket, lash_comm_event);
796
797 if (err == -1) {
798 fprintf(stderr, "%s: could not send event to client\n", __FUNCTION__);
799 }
800
801 lash_comm_event_destroy(lash_comm_event);
802 }
803
804 void
conn_mgr_send_disconnect_client(conn_mgr_t * conn_mgr,unsigned long conn_id)805 conn_mgr_send_disconnect_client(conn_mgr_t * conn_mgr, unsigned long conn_id)
806 {
807 lash_list_t *list;
808 conn_t *conn;
809
810 pthread_mutex_lock(&conn_mgr->connections_lock);
811 for (list = conn_mgr->connections; list; list = list->next) {
812 conn = (conn_t *) list->data;
813
814 if (conn->id == conn_id) {
815 /* remove it */
816 conn_lock(conn);
817 conn_mgr_disconnect_client(conn_mgr, conn, 0);
818 pthread_mutex_unlock(&conn_mgr->connections_lock);
819 return;
820 }
821 }
822
823 pthread_mutex_unlock(&conn_mgr->connections_lock);
824 fprintf(stderr,
825 "%s: request from server to remove unknown connection %ld\n",
826 __FUNCTION__, conn_id);
827 }
828
829 void
conn_mgr_send_server_event_to_client(conn_mgr_t * conn_mgr,server_event_t * server_event)830 conn_mgr_send_server_event_to_client(conn_mgr_t * conn_mgr,
831 server_event_t * server_event)
832 {
833 lash_comm_event_t *lash_comm_event = NULL;
834 unsigned long conn_id;
835 lash_list_t *list;
836 conn_t *conn;
837
838 conn_id = server_event->conn_id;
839
840 /* extract the comm event */
841 switch (server_event->type) {
842 case Client_Event:
843 lash_comm_event = lash_comm_event_new();
844 lash_comm_event_set_event(lash_comm_event,
845 server_event_take_lash_event(server_event));
846 break;
847
848 case Client_Config:
849 lash_comm_event = lash_comm_event_new();
850 lash_comm_event_set_config(lash_comm_event,
851 server_event_take_lash_config
852 (server_event));
853 break;
854
855 case Client_Comm_Event:
856 lash_comm_event = server_event_take_lash_comm_event(server_event);
857 break;
858
859 case Client_Disconnect:
860 conn_mgr_send_disconnect_client(conn_mgr, server_event->conn_id);
861 server_event_destroy(server_event);
862 return;
863
864 case Client_Connect:
865 default:
866 fprintf(stderr,
867 "%s: recieved unknown send request of type %d from server\n",
868 __FUNCTION__, server_event->type);
869 server_event_destroy(server_event);
870 return;
871 }
872 server_event_destroy(server_event);
873
874 /* attempt to find the connection */
875 pthread_mutex_lock(&conn_mgr->connections_lock);
876 list = conn_mgr->connections;
877 while (list) {
878 conn = (conn_t *) list->data;
879
880 if (conn->id == conn_id) {
881 /* send it */
882 conn_lock(conn);
883 pthread_mutex_unlock(&conn_mgr->connections_lock);
884 conn_mgr_send_lash_comm_event_to_client(conn, lash_comm_event);
885 conn_unlock(conn);
886 return;
887 }
888
889 list = list->next;
890 }
891
892 pthread_mutex_unlock(&conn_mgr->connections_lock);
893
894 fprintf(stderr, "%s: could not send event to unknown connection id %ld\n",
895 __FUNCTION__, conn_id);
896 }
897
898 void *
conn_mgr_send_run(void * data)899 conn_mgr_send_run(void *data)
900 {
901 conn_mgr_t *conn_mgr;
902 lash_list_t *list;
903 server_event_t *server_event;
904
905 LASH_PRINT_DEBUG("send thread starting");
906
907 conn_mgr = (conn_mgr_t *) data;
908
909 while (!conn_mgr->quit) {
910 pthread_mutex_lock(&conn_mgr->client_event_lock);
911 list = conn_mgr->client_events;
912 if (list)
913 conn_mgr->client_events = NULL;
914 else {
915 pthread_cond_wait(&conn_mgr->client_event_cond,
916 &conn_mgr->client_event_lock);
917 list = conn_mgr->client_events;
918 conn_mgr->client_events = NULL;
919 }
920
921 pthread_mutex_unlock(&conn_mgr->client_event_lock);
922
923 if (conn_mgr->quit) {
924 break;
925 }
926
927 while (list) {
928 server_event = (server_event_t *) list->data;
929
930 conn_mgr_send_server_event_to_client(conn_mgr, server_event);
931
932 list = list->next;
933 }
934 }
935
936 LASH_PRINT_DEBUG("finished");
937 return NULL;
938 }
939
940 /* EOF */
941