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