Browse code

reconnect if connection is broken use recv/send instead of fdopen on socket

git-svn: trunk@4345

Török Edvin authored on 2008/11/06 23:27:35
Showing 2 changed files
... ...
@@ -1,3 +1,8 @@
1
+Thu Nov  6 12:29:26 EET 2008 (edwin)
2
+------------------------------------
3
+ * contrib/clamdtop/clamdtop.c: reconnect if connection is broken use
4
+ recv/send instead of fdopen on socket
5
+
1 6
 Thu Nov  6 11:37:08 EET 2008 (edwin)
2 7
 ------------------------------------
3 8
  * clamd/server-th.c, clamd/session.c, clamd/thrmgr.c,
... ...
@@ -36,7 +36,9 @@
36 36
 #include <sys/un.h>
37 37
 #include <sys/time.h>
38 38
 #include <assert.h>
39
+#include <errno.h>
39 40
 
41
+/* ---------------------- NCurses routines -----------------*/
40 42
 enum colors {
41 43
 	header_color=1,
42 44
 	version_color,
... ...
@@ -184,7 +186,6 @@ static void win_start(WINDOW *win, enum colors col)
184 184
 	werase(win);
185 185
 }
186 186
 
187
-static char *clamd_version = NULL;
188 187
 
189 188
 static void  print_colored(WINDOW *win, const char *p)
190 189
 {
... ...
@@ -200,6 +201,8 @@ static void  print_colored(WINDOW *win, const char *p)
200 200
 	}
201 201
 }
202 202
 
203
+static char *clamd_version = NULL;
204
+
203 205
 static void header(void)
204 206
 {
205 207
 	size_t i, x=0;
... ...
@@ -274,8 +277,140 @@ static int tasks_compare(const void *a, const void *b)
274 274
 	return 0;
275 275
 }
276 276
 
277
+/* ----------- Socket routines ----------------------- */
278
+typedef struct connection {
279
+	int sd;
280
+	const char *remote;
281
+} conn_t;
282
+
283
+static void print_con_error(const char *fmt, ...)
284
+{
285
+	va_list ap;
286
+	va_start(ap, fmt);
287
+	if (version_window) {
288
+		werase(version_window);
289
+		wmove(version_window, 0, 0);
290
+		vwprintw(version_window, fmt, ap);
291
+		wrefresh(version_window);
292
+	} else
293
+		vfprintf(stderr, fmt, ap);
294
+	va_end(ap);
295
+}
296
+
277 297
 
278
-static size_t parse_queue(FILE *f, size_t line, char* buf, size_t len)
298
+static int make_connection(const char *soname, conn_t *conn)
299
+{
300
+	int s;
301
+	if(access(soname, F_OK) == 0) {
302
+		struct sockaddr_un addr;
303
+		s = socket(AF_UNIX, SOCK_STREAM, 0);
304
+		if(s < 0) {
305
+			perror("socket");
306
+			return -1;
307
+		}
308
+		memset(&addr, 0, sizeof(addr));
309
+		addr.sun_family = AF_UNIX;
310
+		strncpy(addr.sun_path, soname, sizeof(addr.sun_path));
311
+		printf("Connecting to: %s\n", soname);
312
+		if (connect(s, (struct sockaddr *)&addr, sizeof(addr))) {
313
+			perror("connect");
314
+			return -1;
315
+		}
316
+	} else {
317
+		struct sockaddr_in server;
318
+		struct hostent *hp;
319
+		unsigned port = 0;
320
+		char *name = strdup(soname);
321
+		const char *host = name;
322
+		name = strchr(name, ':');
323
+		if(name) {
324
+			*name++ = '\0';
325
+			port = atoi(name);
326
+		}
327
+		if(!port)
328
+			port = 3310;
329
+		printf("Looking up: %s\n", host);
330
+		if((hp = gethostbyname(host)) == NULL) {
331
+			herror("Cannot find host");
332
+			return -1;
333
+		}
334
+		free(name);
335
+		s = socket(AF_INET, SOCK_STREAM, 0);
336
+		if(s < 0) {
337
+			perror("socket");
338
+			return -1;
339
+		}
340
+		server.sin_family = AF_INET;
341
+		server.sin_port = htons(port);
342
+		server.sin_addr.s_addr = ((struct in_addr*)(hp->h_addr))->s_addr;
343
+		printf("Connecting to: %s:%u\n", inet_ntoa(server.sin_addr), port);
344
+		if (connect(s, (struct sockaddr *)&server, sizeof(server))) {
345
+			perror("connect");
346
+			return -1;
347
+		}
348
+	}
349
+	conn->remote = soname;
350
+	conn->sd = s;
351
+	return 0;
352
+}
353
+
354
+static void reconnect(conn_t *conn)
355
+{
356
+	print_con_error("%s: %s", conn->remote, strerror(errno));
357
+	if (make_connection(conn->remote, conn) < 0) {
358
+		print_con_error("Unable to reconnect to %s: %s", conn->remote, strerror(errno));
359
+		exit(3);
360
+	}
361
+}
362
+
363
+static void send_string(conn_t *conn, const char *cmd)
364
+{
365
+	assert(cmd);
366
+	assert(conn && conn->sd > 0);
367
+
368
+	while(send(conn->sd, cmd, strlen(cmd), 0) == -1) {
369
+		reconnect(conn);
370
+	}
371
+}
372
+
373
+static int recv_line(conn_t *conn, char *buf, size_t len)
374
+{
375
+	assert(len > 0);
376
+	assert(conn && conn->sd > 0);
377
+	assert(buf);
378
+
379
+	len--;
380
+	if (!len)
381
+		return 0;
382
+	while (len > 0) {
383
+		ssize_t nread = recv(conn->sd, buf, len, MSG_PEEK);
384
+		if (nread == -1)
385
+			reconnect(conn);
386
+		else {
387
+			char *p = memchr(buf, '\n', nread);
388
+			if (p) {
389
+				len = p - buf + 1;
390
+			} else
391
+				len = nread;
392
+			assert(len > 0);
393
+			assert(len <= (size_t)nread);
394
+			nread = recv(conn->sd, buf, len, 0);
395
+			if (nread == -1)
396
+				reconnect(conn);
397
+			else {
398
+				assert(nread >0 && (size_t)nread == len);
399
+				buf += nread;
400
+			}
401
+			if (p)
402
+				break;
403
+		}
404
+	}
405
+	*buf = '\0';
406
+	return 1;
407
+}
408
+
409
+/* ---------------------- stats parsing routines ------------------- */
410
+static size_t parse_queue(conn_t *conn, size_t line, char* buf, size_t len)
279 411
 {
280 412
 	struct task *tasks = NULL;
281 413
 	size_t n = 0, i;
... ...
@@ -296,7 +431,7 @@ static size_t parse_queue(FILE *f, size_t line, char* buf, size_t len)
296 296
 		if(!tasks[n-1].line)
297 297
 			exit(1);
298 298
 		tasks[n-1].tim  = tim;
299
-	} while (fgets(buf, len, f) && buf[0] == '\t' && strcmp("END\n", buf) != 0);
299
+	} while (recv_line(conn, buf, len) && buf[0] == '\t' && strcmp("END\n", buf) != 0);
300 300
 	qsort(tasks, n, sizeof(*tasks), tasks_compare);
301 301
 	wattron(stats_window, COLOR_PAIR(queue_header_color));
302 302
 	mvwprintw(stats_window, line++, 0, queue_header);
... ...
@@ -369,7 +504,7 @@ static void output_memstats(const char* line)
369 369
 
370 370
 static struct timeval tv_conn;
371 371
 
372
-static void parse_stats(FILE *f)
372
+static void parse_stats(conn_t *conn)
373 373
 {
374 374
 	WINDOW *win = stats_head_window;
375 375
 	char buf[1024];
... ...
@@ -386,7 +521,7 @@ static void parse_stats(FILE *f)
386 386
 	conn_dt = tv.tv_sec + tv.tv_usec/1e6;
387 387
 	mvwprintw(stats_head_window, i++, 0, "Connected since: %02u:%02u:%02u",
388 388
 			conn_dt/3600, (conn_dt/60)%60, conn_dt%60);
389
-	while(fgets(buf, sizeof(buf), f) && strcmp("END\n",buf) != 0) {
389
+	while(recv_line(conn, buf, sizeof(buf)) && strcmp("END\n",buf) != 0) {
390 390
 		char *val = strchr(buf, ':');
391 391
 		if(i >= 4 && win == stats_head_window) {
392 392
 			win = stats_window;
... ...
@@ -394,7 +529,7 @@ static void parse_stats(FILE *f)
394 394
 		}
395 395
 
396 396
 		if(buf[0] == '\t') {
397
-			i = parse_queue(f, i, buf, sizeof(buf));
397
+			i = parse_queue(conn, i, buf, sizeof(buf));
398 398
 			continue;
399 399
 		} else if(val)
400 400
 			*val++ = '\0';
... ...
@@ -433,94 +568,31 @@ static void parse_stats(FILE *f)
433 433
 	wrefresh(stats_window);
434 434
 }
435 435
 
436
-static int make_connection(char *soname)
437
-{
438
-	int s;
439
-	if(access(soname, F_OK) == 0) {
440
-		struct sockaddr_un addr;
441
-		s = socket(AF_UNIX, SOCK_STREAM, 0);
442
-		if(s < 0) {
443
-			perror("socket");
444
-			return -1;
445
-		}
446
-		memset(&addr, 0, sizeof(addr));
447
-		addr.sun_family = AF_UNIX;
448
-		strncpy(addr.sun_path, soname, sizeof(addr.sun_path));
449
-		printf("Connecting to: %s\n", soname);
450
-		if (connect(s, (struct sockaddr *)&addr, sizeof(addr))) {
451
-			perror("connect");
452
-			return -1;
453
-		}
454
-	} else {
455
-		struct sockaddr_in server;
456
-		struct hostent *hp;
457
-		unsigned port = 0;
458
-		char *host = soname;
459
-		soname = strchr(soname, ':');
460
-		if(soname) {
461
-			*soname++ = '\0';
462
-			port = atoi(soname);
463
-		}
464
-		if(!port)
465
-			port = 3310;
466
-		printf("Looking up: %s\n", host);
467
-		if((hp = gethostbyname(host)) == NULL) {
468
-			herror("Cannot find host");
469
-			return -1;
470
-		}
471
-		s = socket(AF_INET, SOCK_STREAM, 0);
472
-		if(s < 0) {
473
-			perror("socket");
474
-			return -1;
475
-		}
476
-		server.sin_family = AF_INET;
477
-		server.sin_port = htons(port);
478
-		server.sin_addr.s_addr = ((struct in_addr*)(hp->h_addr))->s_addr;
479
-		printf("Connecting to: %s:%u\n", inet_ntoa(server.sin_addr), port);
480
-		if (connect(s, (struct sockaddr *)&server, sizeof(server))) {
481
-			perror("connect");
482
-			return -1;
483
-		}
484
-	}
485
-	return s;
486
-}
487
-
488
-static void read_version(FILE *f)
436
+static void read_version(conn_t *conn)
489 437
 {
490 438
 	char buf[1024];
491
-	if(fgets(buf, sizeof(buf), f)) {
439
+	if(recv_line(conn, buf, sizeof(buf))) {
492 440
 		clamd_version = strdup(buf);
493 441
 	}
494 442
 }
495 443
 
496
-static void sighandler(int arg)
497
-{
498
-	exit_reason = "Broken pipe";
499
-	exit(3);
500
-}
444
+static conn_t conn;
501 445
 
502 446
 int main(int argc, char *argv[])
503 447
 {
504 448
 	int ch = 0, need_initwin=0;
505
-	FILE *f;
506 449
 	fd_set rfds;
507 450
 	struct timeval tv_last, tv;
508 451
 
509
-	int sd = make_connection(argc > 1 ? argv[1] : "/tmp/clamd.socket");
510
-	if(sd < 0)
452
+	/* TODO: parse clamd.conf */
453
+	if (make_connection(argc > 1 ? argv[1] : "/tmp/clamd.socket", &conn) < 0)
511 454
 		exit(2);
512 455
 
513
-	signal(SIGPIPE, sighandler);
456
+	signal(SIGPIPE, SIG_IGN);
514 457
 
515
-	f = fdopen(sd,"r+");
516
-	if(!f) {
517
-		perror("fdopen");
518
-		exit(2);
519
-	}
520 458
 	gettimeofday(&tv_conn, NULL);
521
-	fputs("SESSION\nVERSION\n",f);
522
-	fflush(f);
523
-	read_version(f);
459
+	send_string(&conn, "SESSION\nVERSION\n");
460
+	read_version(&conn);
524 461
 	init_ncurses();
525 462
 
526 463
 	FD_ZERO(&rfds);
... ...
@@ -543,14 +615,14 @@ int main(int argc, char *argv[])
543 543
 				init_windows();
544 544
 				need_initwin = 0;
545 545
 			}
546
-			fputs("STATS\n",f);
546
+			send_string(&conn, "STATS\n");
547 547
 			header();
548
-			parse_stats(f);
548
+			parse_stats(&conn);
549 549
 			tv_last = tv;
550 550
 		}
551 551
 	} while(toupper(ch = getch()) != 'Q');
552
-	fputs("END\n",f);
553
-	fclose(f);
552
+	send_string(&conn, "END\n");
553
+	close(conn.sd);
554 554
 	free(clamd_version);
555 555
 	normal_exit = 1;
556 556
 	return 0;