/* Un client */ static void* repeater(void* sck) { int sckt = (int) sck; char buf[MAX_BUFFER]; int nbc, i; const char WELCOME[] = "mtcs : bienvenu\n"; pgrs_in(); write(sckt, WELCOME, strlen(WELCOME)); pgrs("enregistrement d'une socket"); add_socket(sckt); while (1) { pgrs("attente read"); nbc = read(sckt, buf, MAX_BUFFER); if (nbc <= 0) { pgrs("fin lecture client"); pgrs("desenregistrement d'une socket"); del_socket(sckt); close(sckt); pgrs_out(); return NULL; } pgrs("boucle ecriture"); for(i=0; i<MAX_CONNECTION; i++) if (sockets[i]) write(sockets[i], buf, nbc); pgrs("fin boucle ecriture"); } return NULL; }
static void serv (void *arg) { int h = *(int *) arg; BINKD_CONFIG *config; #if defined(WITH_PERL) && defined(HAVE_THREADS) void *cperl; #endif #if defined(HAVE_FORK) && !defined(HAVE_THREADS) && !defined(DEBUGCHILD) int curfd; pidcmgr = 0; for (curfd=0; curfd<sockfd_used; curfd++) soclose(sockfd[curfd]); #endif config = lock_current_config(); #if defined(WITH_PERL) && defined(HAVE_THREADS) cperl = perl_init_clone(config); #endif protocol (h, h, NULL, NULL, NULL, NULL, NULL, config); Log (5, "downing server..."); #if defined(WITH_PERL) && defined(HAVE_THREADS) perl_done_clone(cperl); #endif del_socket(h); soclose (h); free (arg); unlock_config_structure(config, 0); rel_grow_handles (-6); #ifdef HAVE_THREADS threadsafe(--n_servers); PostSem(&eothread); ENDTHREAD(); #elif defined(DOS) || defined(DEBUGCHILD) --n_servers; #endif }
int RawSocket::open(uint32_t dip, uint16_t dp, uint16_t sp) { int n = 1; del_socket(); create_socket(); dst_sin_.sin_family = PF_INET; dst_sin_.sin_port = htons(dp); dst_sin_.sin_addr.s_addr = dip; bind_sp(sp); if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &n, sizeof(n)) == -1) { logger->PrintErr("[%s:%d] set IP_HDRINCL failed: %s\n", __FILE__, __LINE__, strerror(errno)); return -1; } if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1) { logger->PrintErr("[%s:%d] set SO_REUSEADDR failed: %s", __FILE__, __LINE__, strerror(errno)); return -1; } return 0; }
/* destructor */ RawSocket::~RawSocket() { del_socket(); }
static int call0 (FTN_NODE *node, BINKD_CONFIG *config) { int sockfd = INVALID_SOCKET; int sock_out; char szDestAddr[FTN_ADDR_SZ + 1]; int i, rc, pid = -1; char host[BINKD_FQDNLEN + 5 + 1]; /* current host/port */ char addrbuf[BINKD_FQDNLEN + 1]; char servbuf[MAXSERVNAME + 1]; char *hosts; char *port; char *dst_host = host; const char *save_err; #ifdef HTTPS int use_proxy; char *proxy, *socks; struct addrinfo *aiProxyHead; #endif struct addrinfo *ai, *aiNodeHead, *aiHead, hints; int aiErr; /* setup hints for getaddrinfo */ memset((void *)&hints, 0, sizeof(hints)); hints.ai_family = node->IP_afamily; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; #ifdef WITH_PERL hosts = xstrdup(node->hosts); #ifdef HTTPS proxy = xstrdup(config->proxy); socks = xstrdup(config->socks); #endif if (!perl_on_call(node, config, &hosts #ifdef HTTPS , &proxy, &socks #endif )) { Log(1, "call aborted by Perl on_call()"); return 0; } #else hosts = node->hosts; #ifdef HTTPS proxy = config->proxy; socks = config->socks; #endif #endif ftnaddress_to_str (szDestAddr, &node->fa); Log (2, "call to %s", szDestAddr); setproctitle ("call to %s", szDestAddr); #ifdef HTTPS use_proxy = (node->NP_flag != NP_ON) && (!node->pipe || !node->pipe[0]) && (proxy[0] || socks[0]); if (use_proxy) { char *sp, *sport; strncpy(host, proxy[0] ? proxy : socks, sizeof(host)); if ((sp=strchr(host, ':')) != NULL) { *sp++ = '\0'; sport = sp; if ((sp=strchr(sp, '/')) != NULL) *sp++ = '\0'; } else { if ((sp=strchr(host, '/')) != NULL) *sp++ = '\0'; sport = proxy[0] ? "squid" : "socks"; /* default port */ } /* resolve proxy host */ if ( (aiErr = srv_getaddrinfo(host, sport, &hints, &aiProxyHead)) != 0) { Log(2, "Port %s not found, try default %d", sp, proxy[0] ? 3128 : 1080); aiErr = getaddrinfo(host, proxy[0] ? "3128" : "1080", &hints, &aiProxyHead); } if (aiErr != 0) { Log(1, "%s host %s not found", proxy[0] ? "Proxy" : "Socks", host); #ifdef WITH_PERL xfree(hosts); #ifdef HTTPS xfree(proxy); xfree(socks); #endif #endif return 0; } } #endif for (i = 1; sockfd == INVALID_SOCKET && (rc = get_host_and_port (i, host, &port, hosts, &node->fa, config)) != -1; ++i) { if (rc == 0) { Log (1, "%s: %i: error parsing host list", hosts, i); continue; } pid = -1; if (node->pipe && node->pipe[0]) { char *cmdline = strdup(node->pipe); cmdline = ed(cmdline, "*H", host, NULL); cmdline = ed(cmdline, "*I", port, NULL); pid = run3(cmdline, &sock_out, &sockfd, NULL); free(cmdline); if (pid != -1) { Log (4, "connected"); add_socket(sock_out); break; } if (!binkd_exit) { Log (1, "connection to %s failed"); /* bad_try (&node->fa, "exec error", BAD_CALL, config); */ } sockfd = INVALID_SOCKET; continue; } #ifdef HTTPS if (use_proxy) aiHead = aiProxyHead; else /* don't resolve if proxy or socks specified */ #endif { aiErr = srv_getaddrinfo(host, port, &hints, &aiNodeHead); if (aiErr != 0) { bad_try(&node->fa, "Cannot getaddrinfo", BAD_CALL, config); continue; } aiHead = aiNodeHead; } /* Trying... */ for (ai = aiHead; ai != NULL && sockfd == INVALID_SOCKET; ai = ai->ai_next) { if ((sockfd = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol)) == INVALID_SOCKET) { Log (1, "socket: %s", TCPERR ()); /* as long as there are more addresses, try those */ if (ai != NULL) continue; else { #ifdef WITH_PERL xfree(hosts); #ifdef HTTPS xfree(proxy); xfree(socks); #endif #endif freeaddrinfo(aiHead); return 0; } } add_socket(sockfd); /* Was the socket created after close_sockets loop in exitfunc()? */ if (binkd_exit) { #ifdef WITH_PERL xfree(hosts); #ifdef HTTPS xfree(proxy); xfree(socks); #endif #endif freeaddrinfo(aiHead); return 0; } rc = getnameinfo(ai->ai_addr, ai->ai_addrlen, addrbuf, sizeof(addrbuf), servbuf, sizeof(servbuf), NI_NUMERICHOST | NI_NUMERICSERV); if (rc != 0) { Log (2, "Error in getnameinfo(): %s (%d)", gai_strerror(rc), rc); snprintf(addrbuf, BINKD_FQDNLEN, "invalid"); *servbuf = '\0'; } #ifdef HTTPS if (use_proxy) { char *sp = strchr(host, ':'); if (sp) *sp = '\0'; if (port == config->oport) Log (4, "trying %s via %s %s:%s...", host, proxy[0] ? "proxy" : "socks", addrbuf, servbuf); else Log (4, "trying %s:%s via %s %s:%s...", host, port, proxy[0] ? "proxy" : "socks", addrbuf, servbuf); sprintf(host+strlen(host), ":%s", port); } else #endif { if (port == config->oport) Log (4, "trying %s [%s]...", host, addrbuf); else Log (4, "trying %s [%s]:%s...", host, addrbuf, servbuf); } /* find bind addr with matching address family */ if (config->bindaddr[0]) { struct addrinfo *src_ai, src_hints; memset((void *)&src_hints, 0, sizeof(src_hints)); src_hints.ai_socktype = SOCK_STREAM; src_hints.ai_family = ai->ai_family; src_hints.ai_protocol = IPPROTO_TCP; if ((aiErr = getaddrinfo(config->bindaddr, NULL, &src_hints, &src_ai)) == 0) { if (bind(sockfd, src_ai->ai_addr, src_ai->ai_addrlen)) Log(4, "bind: %s", TCPERR()); freeaddrinfo(src_ai); } else if (aiErr == EAI_FAMILY) /* address family of target and bind address don't match */ continue; else /* otherwise just warn and don't bind() */ Log(2, "bind -- getaddrinfo: %s (%d)", gai_strerror(aiErr), aiErr); } #ifdef HAVE_FORK if (config->connect_timeout) { signal(SIGALRM, alrm); alarm(config->connect_timeout); } #endif if (connect (sockfd, ai->ai_addr, ai->ai_addrlen) == 0) { #ifdef HAVE_FORK alarm(0); #endif Log (4, "connected"); sock_out = sockfd; dst_host = addrbuf; break; } #ifdef HAVE_FORK if (errno == EINTR && config->connect_timeout) save_err = strerror (ETIMEDOUT); else save_err = TCPERR (); alarm(0); #else save_err = TCPERR (); #endif if (!binkd_exit) { Log (1, "connection to %s failed: %s", szDestAddr, save_err); bad_try (&node->fa, save_err, BAD_CALL, config); } del_socket(sockfd); soclose (sockfd); sockfd = INVALID_SOCKET; } #ifdef HTTPS if (!use_proxy) #endif freeaddrinfo(aiNodeHead); #ifdef HTTPS if (sockfd != INVALID_SOCKET && use_proxy) { if (h_connect(sockfd, host, config, proxy, socks) != 0) { if (!binkd_exit) bad_try (&node->fa, TCPERR (), BAD_CALL, config); del_socket(sockfd); soclose (sockfd); sockfd = INVALID_SOCKET; } else if (port == config->oport) { char *pp; if( (pp = strchr(host, ':')) ){ *pp = '\0'; } } } #endif } #ifdef HTTPS if (use_proxy) freeaddrinfo(aiProxyHead); #endif #ifdef WITH_PERL xfree(hosts); #ifdef HTTPS xfree(proxy); xfree(socks); #endif #endif if (sockfd == INVALID_SOCKET) return 0; protocol (sockfd, sock_out, node, NULL, dst_host, config); if (pid != -1) { del_socket(sock_out); close(sock_out); #ifdef HAVE_WAITPID if (waitpid (pid, &rc, 0) == -1) { Log (1, "waitpid(%u) error: %s", pid, strerror(errno)); } else { if (WIFSIGNALED(rc)) Log (2, "process %u exited by signal %u", pid, WTERMSIG(rc)); else Log (4, "rc(%u)=%u", pid, WEXITSTATUS(rc)); } #endif close(sockfd); } else { del_socket(sockfd); soclose (sockfd); } return 1; }
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 } } } } }