git-svn: trunk@4345
Török Edvin authored on 2008/11/06 23:27:35... | ... |
@@ -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; |