int b_connect_ (int s, struct sockaddr *name, int namelen, int timeout) { struct itimerval old_itimer; unsigned int oldTimer; sigset_t newMask, oldMask; struct sigaction action, old_action; if (getitimer (ITIMER_REAL, &old_itimer) < 0) return -1; action.sa_flags = 0; action.sa_handler = (SIGFUNCTYPE) alarmer_; sigfillset (&action.sa_mask); sigaction (SIGALRM, &action, &old_action); unblocksig (SIGALRM); blockSigs_ (SIGALRM, &newMask, &oldMask); oldTimer = alarm (timeout); if (connect (s, name, namelen) < 0) { if (errno == EINTR) errno = ETIMEDOUT; alarm (oldTimer); setitimer (ITIMER_REAL, &old_itimer, NULL); sigaction (SIGALRM, &old_action, NULL); sigprocmask (SIG_SETMASK, &oldMask, NULL); return -1; } alarm (oldTimer); setitimer (ITIMER_REAL, &old_itimer, NULL); sigaction (SIGALRM, &old_action, NULL); sigprocmask (SIG_SETMASK, &oldMask, NULL); return 0; }
void clientmgr (void *arg) { int status; BINKD_CONFIG *config = NULL; #if defined(WITH_PERL) && defined(HAVE_THREADS) void *cperl = NULL; #endif UNUSED_ARG(arg); #ifdef HAVE_FORK pidcmgr = 0; pidCmgr = (int) getpid(); blocksig(); signal (SIGCHLD, sighandler); #elif HAVE_THREADS pidcmgr = PID(); #endif config = lock_current_config(); #if defined(WITH_PERL) && defined(HAVE_THREADS) if (server_flag) cperl = perl_init_clone(config); #endif setproctitle ("client manager"); Log (4, "clientmgr started"); for (;;) { if (config != current_config) { #if defined(WITH_PERL) && defined(HAVE_THREADS) if (server_flag && cperl) perl_done_clone(cperl); #endif if (config) unlock_config_structure(config, 0); config = lock_current_config(); #if defined(WITH_PERL) && defined(HAVE_THREADS) if (server_flag) cperl = perl_init_clone(config); #endif } status = do_client(config); if (status != 0 || binkd_exit) break; if ( #ifdef HAVE_THREADS !server_flag && #endif !poll_flag) checkcfg(); } Log (5, "downing clientmgr..."); #if defined(WITH_PERL) && defined(HAVE_THREADS) if (server_flag && cperl) perl_done_clone(cperl); #endif unlock_config_structure(config, 0); unblocksig(); #ifdef HAVE_THREADS pidcmgr = 0; PostSem(&eothread); if (binkd_exit) _endthread(); #endif exit (0); }
/* * Run one client loop. Return -1 to exit */ static int do_client(BINKD_CONFIG *config) { FTN_NODE *r; int pid; if (!config->q_present) { q_free (SCAN_LISTED, config); if (config->printq) Log (-1, "scan\r"); q_scan (SCAN_LISTED, config); config->q_present = 1; if (config->printq) { LockSem (&lsem); q_list (stderr, SCAN_LISTED, config); ReleaseSem (&lsem); Log (-1, "idle\r"); } } if (n_clients < config->max_clients) { if ((r = q_next_node (config)) != 0) { struct call_args args; if (!bsy_test (&r->fa, F_BSY, config) || !bsy_test (&r->fa, F_CSY, config)) { char szDestAddr[FTN_ADDR_SZ + 1]; ftnaddress_to_str (szDestAddr, &r->fa); Log (4, "%s busy, skipping", szDestAddr); return 0; /* go to the next node */ } rel_grow_handles (6); threadsafe(++n_clients); lock_config_structure(config); args.node = r; args.config = config; if ((pid = branch (call, &args, sizeof (args))) < 0) { unlock_config_structure(config, 0); rel_grow_handles (-6); threadsafe(--n_clients); PostSem(&eothread); Log (1, "cannot branch out"); unblocksig(); SLEEP(1); blocksig(); check_child(&n_clients); } #if !defined(DEBUGCHILD) else { Log (5, "started client #%i, id=%i", n_clients, pid); #if defined(HAVE_FORK) && !defined(AMIGA) unlock_config_structure(config, 0); /* Forked child has own copy */ #endif } #endif } else { if (poll_flag) { if (n_clients <= 0 && q_not_empty (config) == 0) { Log (4, "the queue is empty, quitting..."); return -1; } } else config->q_present = 0; unblocksig(); SLEEP (config->rescan_delay); blocksig(); check_child(&n_clients); } } else { unblocksig(); SLEEP (config->call_delay); blocksig(); check_child(&n_clients); } return 0; }
static int do_server(BINKD_CONFIG *config) { struct addrinfo *ai, *aiHead, hints; int aiErr; SOCKET new_sockfd; int pid; socklen_t client_addr_len; struct sockaddr_storage client_addr; int opt = 1; int save_errno; struct listenchain *listen_list; /* setup hints for getaddrinfo */ memset((void *)&hints, 0, sizeof(hints)); hints.ai_flags = AI_PASSIVE; hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; for (listen_list = config->listen.first; listen_list; listen_list = listen_list->next) { if ((aiErr = getaddrinfo(listen_list->addr[0] ? listen_list->addr : NULL, listen_list->port, &hints, &aiHead)) != 0) { Log(0, "servmgr getaddrinfo: %s (%d)", gai_strerror(aiErr), aiErr); return -1; } for (ai = aiHead; ai != NULL && sockfd_used < MAX_LISTENSOCK; ai = ai->ai_next) { sockfd[sockfd_used] = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (sockfd[sockfd_used] < 0) { Log (0, "servmgr socket(): %s", TCPERR ()); continue; } #ifdef UNIX /* Not sure how to set NOINHERIT flag for socket on Windows and OS/2 */ if (fcntl(sockfd[sockfd_used], F_SETFD, FD_CLOEXEC) != 0) Log(1, "servmgr fcntl set FD_CLOEXEC error: %s", strerror(errno)); #endif #ifdef IPV6_V6ONLY if (ai->ai_family == PF_INET6) { int v6only = 1; if (setsockopt(sockfd[sockfd_used], IPPROTO_IPV6, IPV6_V6ONLY, (char *) &v6only, sizeof(v6only)) == SOCKET_ERROR) Log(1, "servmgr setsockopt (IPV6_V6ONLY): %s", TCPERR()); } #endif if (setsockopt (sockfd[sockfd_used], SOL_SOCKET, SO_REUSEADDR, (char *) &opt, sizeof opt) == SOCKET_ERROR) Log (1, "servmgr setsockopt (SO_REUSEADDR): %s", TCPERR ()); if (bind (sockfd[sockfd_used], ai->ai_addr, ai->ai_addrlen) != 0) { Log (0, "servmgr bind(): %s", TCPERR ()); soclose(sockfd[sockfd_used]); continue; } if (listen (sockfd[sockfd_used], 5) != 0) { Log(0, "servmgr listen(): %s", TCPERR ()); soclose(sockfd[sockfd_used]); continue; } sockfd_used++; } Log (3, "servmgr listen on %s:%s", listen_list->addr[0] ? listen_list->addr : "*", listen_list->port); freeaddrinfo(aiHead); } if (sockfd_used == 0) { Log(0, "servmgr: No listen socket open"); return -1; } setproctitle ("server manager (listen %s)", config->listen.first->port); for (;;) { struct timeval tv; int n; int curfd, maxfd = 0; fd_set r; FD_ZERO (&r); for (curfd=0; curfd<sockfd_used; curfd++) { FD_SET (sockfd[curfd], &r); if (sockfd[curfd] > maxfd) maxfd = sockfd[curfd]; } tv.tv_usec = 0; tv.tv_sec = CHECKCFG_INTERVAL; unblocksig(); check_child(&n_servers); n = select(maxfd+1, &r, NULL, NULL, &tv); blocksig(); switch (n) { case 0: /* timeout */ if (checkcfg()) { for (curfd=0; curfd<sockfd_used; curfd++) soclose(sockfd[curfd]); sockfd_used = 0; return 0; } unblocksig(); check_child(&n_servers); blocksig(); continue; case -1: save_errno = TCPERRNO; if (binkd_exit) goto accepterr; if (TCPERRNO == EINTR) { unblocksig(); check_child(&n_servers); blocksig(); if (checkcfg()) { for (curfd=0; curfd<sockfd_used; curfd++) soclose(sockfd[curfd]); sockfd_used = 0; return 0; } continue; } Log (1, "servmgr select(): %s", TCPERR ()); goto accepterr; } for (curfd=0; curfd<sockfd_used; curfd++) { if (!FD_ISSET(sockfd[curfd], &r)) continue; client_addr_len = sizeof (client_addr); if ((new_sockfd = accept (sockfd[curfd], (struct sockaddr *)&client_addr, &client_addr_len)) == INVALID_SOCKET) { save_errno = TCPERRNO; if (save_errno != EINVAL && save_errno != EINTR) { if (!binkd_exit) Log (1, "servmgr accept(): %s", TCPERR ()); #ifdef UNIX if (save_errno == ECONNRESET || save_errno == ETIMEDOUT || save_errno == ECONNABORTED || save_errno == EHOSTUNREACH) continue; #endif accepterr: #ifdef OS2 /* Buggy external process closed our socket? Or OS/2 bug? */ if (save_errno == ENOTSOCK) return 0; /* will force socket re-creation */ #endif return -1; } } else { char host[BINKD_FQDNLEN + 1]; char service[MAXSERVNAME + 1]; int aiErr; add_socket(new_sockfd); /* Was the socket created after close_sockets loop in exitfunc()? */ if (binkd_exit) { del_socket(new_sockfd); soclose(new_sockfd); continue; } rel_grow_handles (6); ext_rand=rand(); /* never resolve name in here, will be done during session */ aiErr = getnameinfo((struct sockaddr *)&client_addr, client_addr_len, host, sizeof(host), service, sizeof(service), NI_NUMERICHOST | NI_NUMERICSERV); if (aiErr == 0) Log (3, "incoming from %s (%s)", host, service); else { Log(2, "Error in getnameinfo(): %s (%d)", gai_strerror(aiErr), aiErr); Log(3, "incoming from unknown"); } /* Creating a new process for the incoming connection */ threadsafe(++n_servers); if ((pid = branch (serv, (void *) &new_sockfd, sizeof (new_sockfd))) < 0) { del_socket(new_sockfd); soclose(new_sockfd); rel_grow_handles (-6); threadsafe(--n_servers); PostSem(&eothread); Log (1, "servmgr branch(): cannot branch out"); sleep(1); } else { Log (5, "started server #%i, id=%i", n_servers, pid); #if defined(HAVE_FORK) && !defined(HAVE_THREADS) soclose (new_sockfd); #endif } } } } }