net.c revision 1.4
1/* $OpenBSD: net.c,v 1.4 2005/05/23 19:53:27 ho Exp $ */ 2 3/* 4 * Copyright (c) 2005 H�kan Olsson. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28/* 29 * This code was written under funding by Multicom Security AB. 30 */ 31 32 33#include <sys/types.h> 34#include <sys/socket.h> 35#include <sys/time.h> 36#include <netinet/in.h> 37#include <arpa/inet.h> 38#include <ifaddrs.h> 39#include <netdb.h> 40 41#include <openssl/aes.h> 42#include <openssl/sha.h> 43 44#include <errno.h> 45#include <stdio.h> 46#include <stdlib.h> 47#include <string.h> 48#include <unistd.h> 49 50#include "sasyncd.h" 51#include "net.h" 52 53struct msg { 54 u_int8_t *buf; 55 u_int32_t len; 56 int refcnt; 57}; 58 59struct qmsg { 60 SIMPLEQ_ENTRY(qmsg) next; 61 struct msg *msg; 62}; 63 64int listen_socket; 65AES_KEY aes_key[2]; 66#define AES_IV_LEN AES_BLOCK_SIZE 67 68/* We never send (or expect to receive) messages smaller/larger than this. */ 69#define MSG_MINLEN 12 70#define MSG_MAXLEN 4096 71 72/* Local prototypes. */ 73static u_int8_t *net_read(struct syncpeer *, u_int32_t *, u_int32_t *); 74static int net_set_sa(struct sockaddr *, char *, in_port_t); 75static void net_check_peers(void *); 76 77/* Pretty-print a buffer. */ 78static void 79dump_buf(int lvl, u_int8_t *b, u_int32_t len, char *title) 80{ 81 u_int32_t i, off, blen; 82 u_int8_t *buf; 83 const char def[] = "Buffer:"; 84 85 if (cfgstate.verboselevel < lvl) 86 return; 87 88 blen = 2 * (len + len / 36) + 3 + (title ? strlen(title) : sizeof def); 89 if (!(buf = (u_int8_t *)calloc(1, blen))) 90 return; 91 92 snprintf(buf, blen, "%s\n ", title ? title : def); 93 off = strlen(buf); 94 for (i = 0; i < len; i++, off+=2) { 95 snprintf(buf + off, blen - off, "%02x", b[i]); 96 if ((i+1) % 36 == 0) { 97 off += 2; 98 snprintf(buf + off, blen - off, "\n "); 99 } 100 } 101 log_msg(lvl, "%s", buf); 102 free(buf); 103} 104 105int 106net_init(void) 107{ 108 struct sockaddr_storage sa_storage; 109 struct sockaddr *sa = (struct sockaddr *)&sa_storage; 110 struct syncpeer *p; 111 char host[NI_MAXHOST], port[NI_MAXSERV]; 112 int r; 113 114 /* The shared key needs to be 128, 192 or 256 bits */ 115 r = strlen(cfgstate.sharedkey) << 3; 116 if (r != 128 && r != 192 && r != 256) { 117 fprintf(stderr, "Bad shared key length (%d bits), " 118 "should be 128, 192 or 256\n", r); 119 return -1; 120 } 121 122 if (AES_set_encrypt_key(cfgstate.sharedkey, r, &aes_key[0]) || 123 AES_set_decrypt_key(cfgstate.sharedkey, r, &aes_key[1])) { 124 fprintf(stderr, "Bad AES shared key\n"); 125 return -1; 126 } 127 128 /* Setup listening socket. */ 129 memset(&sa_storage, 0, sizeof sa_storage); 130 if (net_set_sa(sa, cfgstate.listen_on, cfgstate.listen_port)) { 131 log_msg(0, "net_init: could not find listen address (%s)", 132 cfgstate.listen_on); 133 return -1; 134 } 135 136 listen_socket = socket(sa->sa_family, SOCK_STREAM, 0); 137 if (listen_socket < 0) { 138 perror("socket()"); 139 close(listen_socket); 140 return -1; 141 } 142 r = 1; 143 if (setsockopt(listen_socket, SOL_SOCKET, 144 cfgstate.listen_on ? SO_REUSEADDR : SO_REUSEPORT, (void *)&r, 145 sizeof r)) { 146 perror("setsockopt()"); 147 close(listen_socket); 148 return -1; 149 } 150 if (bind(listen_socket, sa, sizeof(struct sockaddr_in))) { 151 perror("bind()"); 152 close(listen_socket); 153 return -1; 154 } 155 if (listen(listen_socket, 10)) { 156 perror("listen()"); 157 close(listen_socket); 158 return -1; 159 } 160 161 if (getnameinfo(sa, sa->sa_len, host, sizeof host, port, sizeof port, 162 NI_NUMERICHOST | NI_NUMERICSERV)) 163 log_msg(2, "listening on port %u fd %d", cfgstate.listen_port, 164 listen_socket); 165 else 166 log_msg(2, "listening on %s port %s fd %d", host, port, 167 listen_socket); 168 169 for (p = LIST_FIRST(&cfgstate.peerlist); p; p = LIST_NEXT(p, link)) { 170 p->socket = -1; 171 SIMPLEQ_INIT(&p->msgs); 172 } 173 174 net_check_peers(0); 175 return 0; 176} 177 178static void 179net_enqueue(struct syncpeer *p, struct msg *m) 180{ 181 struct qmsg *qm; 182 183 if (p->socket < 0) 184 return; 185 186 qm = (struct qmsg *)malloc(sizeof *qm); 187 if (!qm) { 188 log_err("malloc()"); 189 return; 190 } 191 192 memset(qm, 0, sizeof *qm); 193 qm->msg = m; 194 m->refcnt++; 195 196 SIMPLEQ_INSERT_TAIL(&p->msgs, qm, next); 197 return; 198} 199 200/* 201 * Queue a message for transmission to a particular peer, 202 * or to all peers if no peer is specified. 203 */ 204int 205net_queue(struct syncpeer *p0, u_int32_t msgtype, u_int8_t *buf, u_int32_t len) 206{ 207 struct syncpeer *p = p0; 208 struct msg *m; 209 SHA_CTX ctx; 210 u_int8_t hash[SHA_DIGEST_LENGTH]; 211 u_int8_t iv[AES_IV_LEN], tmp_iv[AES_IV_LEN]; 212 u_int32_t v, padlen = 0; 213 int i, offset; 214 215 m = (struct msg *)calloc(1, sizeof *m); 216 if (!m) { 217 log_err("calloc()"); 218 free(buf); 219 return -1; 220 } 221 222 /* Generate hash */ 223 SHA1_Init(&ctx); 224 SHA1_Update(&ctx, buf, len); 225 SHA1_Final(hash, &ctx); 226 dump_buf(5, hash, sizeof hash, "net_queue: computed hash"); 227 228 /* Padding required? */ 229 i = len % AES_IV_LEN; 230 if (i) { 231 u_int8_t *pbuf; 232 i = AES_IV_LEN - i; 233 pbuf = realloc(buf, len + i); 234 if (!pbuf) { 235 log_err("net_queue: realloc()"); 236 free(buf); 237 free(m); 238 return -1; 239 } 240 padlen = i; 241 while (i > 0) 242 pbuf[len++] = (u_int8_t)i--; 243 buf = pbuf; 244 } 245 246 /* Get random IV */ 247 for (i = 0; i <= sizeof iv - sizeof v; i += sizeof v) { 248 v = arc4random(); 249 memcpy(&iv[i], &v, sizeof v); 250 } 251 dump_buf(5, iv, sizeof iv, "net_queue: IV"); 252 memcpy(tmp_iv, iv, sizeof tmp_iv); 253 254 /* Encrypt */ 255 dump_buf(5, buf, len, "net_queue: pre encrypt"); 256 AES_cbc_encrypt(buf, buf, len, &aes_key[0], tmp_iv, AES_ENCRYPT); 257 dump_buf(5, buf, len, "net_queue: post encrypt"); 258 259 /* Allocate send buffer */ 260 m->len = len + sizeof iv + sizeof hash + 3 * sizeof(u_int32_t); 261 m->buf = (u_int8_t *)malloc(m->len); 262 if (!m->buf) { 263 free(m); 264 free(buf); 265 log_err("net_queue: calloc()"); 266 return -1; 267 } 268 offset = 0; 269 270 /* Fill it (order must match parsing code in net_read()) */ 271 v = htonl(m->len - sizeof(u_int32_t)); 272 memcpy(m->buf + offset, &v, sizeof v); 273 offset += sizeof v; 274 v = htonl(msgtype); 275 memcpy(m->buf + offset, &v, sizeof v); 276 offset += sizeof v; 277 v = htonl(padlen); 278 memcpy(m->buf + offset, &v, sizeof v); 279 offset += sizeof v; 280 memcpy(m->buf + offset, hash, sizeof hash); 281 offset += sizeof hash; 282 memcpy(m->buf + offset, iv, sizeof iv); 283 offset += sizeof iv; 284 memcpy(m->buf + offset, buf, len); 285 free(buf); 286 287 if (p) 288 net_enqueue(p, m); 289 else 290 for (p = LIST_FIRST(&cfgstate.peerlist); p; 291 p = LIST_NEXT(p, link)) 292 net_enqueue(p, m); 293 294 if (!m->refcnt) { 295 free(m->buf); 296 free(m); 297 } 298 299 return 0; 300} 301 302/* Set all write pending filedescriptors. */ 303int 304net_set_pending_wfds(fd_set *fds) 305{ 306 struct syncpeer *p; 307 int max_fd = -1; 308 309 for (p = LIST_FIRST(&cfgstate.peerlist); p; p = LIST_NEXT(p, link)) 310 if (p->socket > -1 && SIMPLEQ_FIRST(&p->msgs)) { 311 FD_SET(p->socket, fds); 312 if (p->socket > max_fd) 313 max_fd = p->socket; 314 } 315 return max_fd + 1; 316} 317 318/* 319 * Set readable filedescriptors. They are basically the same as for write, 320 * plus the listening socket. 321 */ 322int 323net_set_rfds(fd_set *fds) 324{ 325 struct syncpeer *p; 326 int max_fd = -1; 327 328 for (p = LIST_FIRST(&cfgstate.peerlist); p; p = LIST_NEXT(p, link)) { 329 if (p->socket > -1) 330 FD_SET(p->socket, fds); 331 if (p->socket > max_fd) 332 max_fd = p->socket; 333 } 334 FD_SET(listen_socket, fds); 335 if (listen_socket > max_fd) 336 max_fd = listen_socket; 337 return max_fd + 1; 338} 339 340void 341net_handle_messages(fd_set *fds) 342{ 343 struct sockaddr_storage sa_storage, sa_storage2; 344 struct sockaddr *sa = (struct sockaddr *)&sa_storage; 345 struct sockaddr *sa2 = (struct sockaddr *)&sa_storage2; 346 socklen_t socklen; 347 struct syncpeer *p; 348 u_int8_t *msg; 349 u_int32_t msgtype, msglen; 350 int newsock, found; 351 352 if (FD_ISSET(listen_socket, fds)) { 353 /* Accept a new incoming connection */ 354 socklen = sizeof sa_storage; 355 newsock = accept(listen_socket, sa, &socklen); 356 if (newsock > -1) { 357 /* Setup the syncpeer structure */ 358 found = 0; 359 for (p = LIST_FIRST(&cfgstate.peerlist); p && !found; 360 p = LIST_NEXT(p, link)) { 361 struct sockaddr_in *sin, *sin2; 362 struct sockaddr_in6 *sin6, *sin62; 363 364 /* Match? */ 365 if (net_set_sa(sa2, p->name, 0)) 366 continue; 367 if (sa->sa_family != sa2->sa_family) 368 continue; 369 if (sa->sa_family == AF_INET) { 370 sin = (struct sockaddr_in *)sa; 371 sin2 = (struct sockaddr_in *)sa2; 372 if (memcmp(&sin->sin_addr, 373 &sin2->sin_addr, 374 sizeof(struct in_addr))) 375 continue; 376 } else { 377 sin6 = (struct sockaddr_in6 *)sa; 378 sin62 = (struct sockaddr_in6 *)sa2; 379 if (memcmp(&sin6->sin6_addr, 380 &sin62->sin6_addr, 381 sizeof(struct in6_addr))) 382 continue; 383 } 384 /* Match! */ 385 found++; 386 p->socket = newsock; 387 log_msg(1, "net: peer \"%s\" connected", 388 p->name); 389 } 390 if (!found) { 391 log_msg(1, "net: found no matching peer for " 392 "accepted socket, closing."); 393 close(newsock); 394 } 395 } else 396 log_err("accept()"); 397 } 398 399 for (p = LIST_FIRST(&cfgstate.peerlist); p; p = LIST_NEXT(p, link)) { 400 if (p->socket < 0 || !FD_ISSET(p->socket, fds)) 401 continue; 402 msg = net_read(p, &msgtype, &msglen); 403 if (!msg) 404 continue; 405 406 log_msg(4, "net_handle_messages: got msg type %u len %u from " 407 "peer %s", msgtype, msglen, p->name); 408 409 switch (msgtype) { 410 case MSG_SYNCCTL: 411 net_ctl_handle_msg(p, msg, msglen); 412 free(msg); 413 break; 414 415 case MSG_PFKEYDATA: 416 if (p->runstate != MASTER || 417 cfgstate.runstate == MASTER) { 418 log_msg(1, "net: got PFKEY message from " 419 "non-MASTER peer"); 420 free(msg); 421 if (cfgstate.runstate == MASTER) 422 net_ctl_send_state(p); 423 else 424 net_ctl_send_error(p, 0); 425 } else if (pfkey_queue_message(msg, msglen)) 426 free(msg); 427 break; 428 429 default: 430 log_msg(0, "net: got unknown message type %u len %u " 431 "from peer %s", msgtype, msglen, p->name); 432 free(msg); 433 net_ctl_send_error(p, 0); 434 } 435 } 436} 437 438void 439net_send_messages(fd_set *fds) 440{ 441 struct syncpeer *p; 442 struct qmsg *qm; 443 struct msg *m; 444 ssize_t r; 445 446 for (p = LIST_FIRST(&cfgstate.peerlist); p; p = LIST_NEXT(p, link)) { 447 if (p->socket < 0 || !FD_ISSET(p->socket, fds)) 448 continue; 449 qm = SIMPLEQ_FIRST(&p->msgs); 450 if (!qm) { 451 /* XXX Log */ 452 continue; 453 } 454 m = qm->msg; 455 456 log_msg(4, "net_send_messages: msg %p len %d ref %d " 457 "to peer %s", m, m->len, m->refcnt, p->name); 458 459 /* write message */ 460 r = write(p->socket, m->buf, m->len); 461 if (r == -1) { 462 net_disconnect_peer(p); 463 log_msg(0, "net_send_messages: write() failed, " 464 "peer disconnected"); 465 } else if (r < (ssize_t)m->len) { 466 /* retransmit later */ 467 continue; 468 } 469 470 /* cleanup */ 471 SIMPLEQ_REMOVE_HEAD(&p->msgs, next); 472 free(qm); 473 474 if (--m->refcnt < 1) { 475 log_msg(4, "net_send_messages: freeing msg %p", m); 476 free(m->buf); 477 free(m); 478 } 479 } 480 return; 481} 482 483void 484net_disconnect_peer(struct syncpeer *p) 485{ 486 if (p->socket > -1) { 487 log_msg(1, "net_disconnect_peer: peer \"%s\" removed", 488 p->name); 489 close(p->socket); 490 } 491 p->socket = -1; 492} 493 494void 495net_shutdown(void) 496{ 497 struct syncpeer *p; 498 struct qmsg *qm; 499 struct msg *m; 500 501 while ((p = LIST_FIRST(&cfgstate.peerlist))) { 502 while ((qm = SIMPLEQ_FIRST(&p->msgs))) { 503 SIMPLEQ_REMOVE_HEAD(&p->msgs, next); 504 m = qm->msg; 505 if (--m->refcnt < 1) { 506 free(m->buf); 507 free(m); 508 } 509 free(qm); 510 } 511 net_disconnect_peer(p); 512 if (p->name) 513 free(p->name); 514 LIST_REMOVE(p, link); 515 free(p); 516 } 517 518 if (listen_socket > -1) 519 close(listen_socket); 520} 521 522/* 523 * Helper functions (local) below here. 524 */ 525 526static u_int8_t * 527net_read(struct syncpeer *p, u_int32_t *msgtype, u_int32_t *msglen) 528{ 529 u_int8_t *msg, *blob, *rhash, *iv, hash[SHA_DIGEST_LENGTH]; 530 u_int32_t v, blob_len; 531 int padlen = 0, offset = 0, r; 532 SHA_CTX ctx; 533 534 /* Read blob length */ 535 r = read(p->socket, &v, sizeof v); 536 if (r != (ssize_t)sizeof v) { 537 if (r < 1) 538 net_disconnect_peer(p); 539 return NULL; 540 } 541 542 blob_len = ntohl(v); 543 if (blob_len < sizeof hash + AES_IV_LEN + 2 * sizeof(u_int32_t)) 544 return NULL; 545 *msglen = blob_len - sizeof hash - AES_IV_LEN - 2 * sizeof(u_int32_t); 546 if (*msglen < MSG_MINLEN || *msglen > MSG_MAXLEN) 547 return NULL; 548 549 /* Read message blob */ 550 blob = (u_int8_t *)malloc(blob_len); 551 if (!blob) { 552 log_err("net_read: malloc()"); 553 return NULL; 554 } 555 r = read(p->socket, blob, blob_len); 556 if (r < 1) { 557 net_disconnect_peer(p); 558 free(blob); 559 return NULL; 560 } else if (r < (ssize_t)blob_len) { 561 /* XXX wait and read more? */ 562 fprintf(stderr, "net_read: wanted %d, got %d\n", blob_len, r); 563 free(blob); 564 return NULL; 565 } 566 567 offset = 0; 568 memcpy(&v, blob + offset, sizeof v); 569 *msgtype = ntohl(v); 570 offset += sizeof v; 571 572 if (*msgtype > MSG_MAXTYPE) { 573 free(blob); 574 return NULL; 575 } 576 577 memcpy(&v, blob + offset, sizeof v); 578 padlen = ntohl(v); 579 offset += sizeof v; 580 581 rhash = blob + offset; 582 iv = rhash + sizeof hash; 583 msg = (u_int8_t *)malloc(*msglen); 584 if (!msg) { 585 free(blob); 586 return NULL; 587 } 588 memcpy(msg, iv + AES_IV_LEN, *msglen); 589 590 dump_buf(5, rhash, sizeof hash, "net_read: got hash"); 591 dump_buf(5, iv, AES_IV_LEN, "net_read: got IV"); 592 dump_buf(5, msg, *msglen, "net_read: pre decrypt"); 593 AES_cbc_encrypt(msg, msg, *msglen, &aes_key[1], iv, AES_DECRYPT); 594 dump_buf(5, msg, *msglen, "net_read: post decrypt"); 595 *msglen -= padlen; 596 597 SHA1_Init(&ctx); 598 SHA1_Update(&ctx, msg, *msglen); 599 SHA1_Final(hash, &ctx); 600 dump_buf(5, hash, sizeof hash, "net_read: computed hash"); 601 602 if (memcmp(hash, rhash, sizeof hash) != 0) { 603 free(blob); 604 log_msg(0, "net_read: got bad message (typo in shared key?)"); 605 return NULL; 606 } 607 free(blob); 608 return msg; 609} 610 611static int 612net_set_sa(struct sockaddr *sa, char *name, in_port_t port) 613{ 614 struct sockaddr_in *sin = (struct sockaddr_in *)sa; 615 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; 616 struct ifaddrs *ifap, *ifa; 617 618 if (!name) { 619 /* XXX Assume IPv4 */ 620 sa->sa_family = AF_INET; 621 sin->sin_port = htons(port); 622 sin->sin_len = sizeof *sin; 623 return 0; 624 } 625 626 if (inet_pton(AF_INET, name, &sin->sin_addr) == 1) { 627 sa->sa_family = AF_INET; 628 sin->sin_port = htons(port); 629 sin->sin_len = sizeof *sin; 630 return 0; 631 } 632 633 if (inet_pton(AF_INET6, name, &sin6->sin6_addr) == 1) { 634 sa->sa_family = AF_INET6; 635 sin6->sin6_port = htons(port); 636 sin6->sin6_len = sizeof *sin6; 637 return 0; 638 } 639 640 /* inet_pton failed. fail here if name is not cfgstate.listen_on */ 641 if (strcmp(cfgstate.listen_on, name) != 0) 642 return -1; 643 644 /* Is cfgstate.listen_on the name of one our interfaces? */ 645 if (getifaddrs(&ifap) != 0) { 646 perror("getifaddrs()"); 647 return -1; 648 } 649 sa->sa_family = AF_UNSPEC; 650 for (ifa = ifap; ifa && sa->sa_family == AF_UNSPEC; 651 ifa = ifa->ifa_next) { 652 if (!ifa->ifa_name || !ifa->ifa_addr) 653 continue; 654 if (strcmp(ifa->ifa_name, name) != 0) 655 continue; 656 657 switch (ifa->ifa_addr->sa_family) { 658 case AF_INET: 659 sa->sa_family = AF_INET; 660 sin->sin_port = htons(port); 661 sin->sin_len = sizeof *sin; 662 memcpy(&sin->sin_addr, 663 &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr, 664 sizeof sin->sin_addr); 665 break; 666 667 case AF_INET6: 668 sa->sa_family = AF_INET6; 669 sin6->sin6_port = htons(port); 670 sin6->sin6_len = sizeof *sin6; 671 memcpy(&sin6->sin6_addr, 672 &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr, 673 sizeof sin6->sin6_addr); 674 break; 675 } 676 } 677 freeifaddrs(ifap); 678 return sa->sa_family == AF_UNSPEC ? -1 : 0; 679} 680 681 682static void 683got_sigalrm(int s) 684{ 685 return; 686} 687 688void 689net_connect(void) 690{ 691 struct sockaddr_storage sa_storage; 692 struct itimerval iv; 693 struct sockaddr *sa = (struct sockaddr *)&sa_storage; 694 struct syncpeer *p; 695 696 signal(SIGALRM, got_sigalrm); 697 memset(&iv, 0, sizeof iv); 698 iv.it_value.tv_sec = 5; 699 iv.it_interval.tv_sec = 5; 700 setitimer(ITIMER_REAL, &iv, NULL); 701 702 for (p = LIST_FIRST(&cfgstate.peerlist); p; p = LIST_NEXT(p, link)) { 703 if (p->socket > -1) 704 continue; 705 706 memset(sa, 0, sizeof sa_storage); 707 if (net_set_sa(sa, p->name, cfgstate.listen_port)) 708 continue; 709 p->socket = socket(sa->sa_family, SOCK_STREAM, 0); 710 if (p->socket < 0) { 711 log_err("peer \"%s\": socket()", p->name); 712 continue; 713 } 714 if (connect(p->socket, sa, sa->sa_len)) { 715 log_msg(1, "net_connect: peer \"%s\" not ready yet", 716 p->name); 717 net_disconnect_peer(p); 718 continue; 719 } 720 if (net_ctl_send_state(p)) { 721 log_msg(0, "net_connect: peer \"%s\" failed", p->name); 722 net_disconnect_peer(p); 723 continue; 724 } 725 log_msg(1, "net_connect: peer \"%s\" connected, fd %d", 726 p->name, p->socket); 727 } 728 729 timerclear(&iv.it_value); 730 timerclear(&iv.it_interval); 731 setitimer(ITIMER_REAL, &iv, NULL); 732 signal(SIGALRM, SIG_IGN); 733 734 return; 735} 736 737static void 738net_check_peers(void *arg) 739{ 740 net_connect(); 741 742 (void)timer_add("peer recheck", 600, net_check_peers, 0); 743} 744 745