10f66f451Sopenharmony_ci/* tcpsvd.c - TCP(UDP)/IP service daemon 20f66f451Sopenharmony_ci * 30f66f451Sopenharmony_ci * Copyright 2013 Ashwini Kumar <ak.ashwini@gmail.com> 40f66f451Sopenharmony_ci * Copyright 2013 Sandeep Sharma <sandeep.jack2756@gmail.com> 50f66f451Sopenharmony_ci * Copyright 2013 Kyungwan Han <asura321@gmail.com> 60f66f451Sopenharmony_ci * 70f66f451Sopenharmony_ci * No Standard. 80f66f451Sopenharmony_ci 90f66f451Sopenharmony_ciUSE_TCPSVD(NEWTOY(tcpsvd, "^<3c#=30<1C:b#=20<0u:l:hEv", TOYFLAG_USR|TOYFLAG_BIN)) 100f66f451Sopenharmony_ciUSE_TCPSVD(OLDTOY(udpsvd, tcpsvd, TOYFLAG_USR|TOYFLAG_BIN)) 110f66f451Sopenharmony_ci 120f66f451Sopenharmony_ciconfig TCPSVD 130f66f451Sopenharmony_ci bool "tcpsvd" 140f66f451Sopenharmony_ci default n 150f66f451Sopenharmony_ci depends on TOYBOX_FORK 160f66f451Sopenharmony_ci help 170f66f451Sopenharmony_ci usage: tcpsvd [-hEv] [-c N] [-C N[:MSG]] [-b N] [-u User] [-l Name] IP Port Prog 180f66f451Sopenharmony_ci usage: udpsvd [-hEv] [-c N] [-u User] [-l Name] IP Port Prog 190f66f451Sopenharmony_ci 200f66f451Sopenharmony_ci Create TCP/UDP socket, bind to IP:PORT and listen for incoming connection. 210f66f451Sopenharmony_ci Run PROG for each connection. 220f66f451Sopenharmony_ci 230f66f451Sopenharmony_ci IP IP to listen on, 0 = all 240f66f451Sopenharmony_ci PORT Port to listen on 250f66f451Sopenharmony_ci PROG ARGS Program to run 260f66f451Sopenharmony_ci -l NAME Local hostname (else looks up local hostname in DNS) 270f66f451Sopenharmony_ci -u USER[:GRP] Change to user/group after bind 280f66f451Sopenharmony_ci -c N Handle up to N (> 0) connections simultaneously 290f66f451Sopenharmony_ci -b N (TCP Only) Allow a backlog of approximately N TCP SYNs 300f66f451Sopenharmony_ci -C N[:MSG] (TCP Only) Allow only up to N (> 0) connections from the same IP 310f66f451Sopenharmony_ci New connections from this IP address are closed 320f66f451Sopenharmony_ci immediately. MSG is written to the peer before close 330f66f451Sopenharmony_ci -h Look up peer's hostname 340f66f451Sopenharmony_ci -E Don't set up environment variables 350f66f451Sopenharmony_ci -v Verbose 360f66f451Sopenharmony_ci*/ 370f66f451Sopenharmony_ci 380f66f451Sopenharmony_ci#define FOR_tcpsvd 390f66f451Sopenharmony_ci#include "toys.h" 400f66f451Sopenharmony_ci 410f66f451Sopenharmony_ciGLOBALS( 420f66f451Sopenharmony_ci char *name; 430f66f451Sopenharmony_ci char *user; 440f66f451Sopenharmony_ci long bn; 450f66f451Sopenharmony_ci char *nmsg; 460f66f451Sopenharmony_ci long cn; 470f66f451Sopenharmony_ci 480f66f451Sopenharmony_ci int maxc; 490f66f451Sopenharmony_ci int count_all; 500f66f451Sopenharmony_ci int udp; 510f66f451Sopenharmony_ci) 520f66f451Sopenharmony_ci 530f66f451Sopenharmony_cistruct list_pid { 540f66f451Sopenharmony_ci struct list_pid *next; 550f66f451Sopenharmony_ci char *ip; 560f66f451Sopenharmony_ci int pid; 570f66f451Sopenharmony_ci}; 580f66f451Sopenharmony_ci 590f66f451Sopenharmony_cistruct list { 600f66f451Sopenharmony_ci struct list* next; 610f66f451Sopenharmony_ci char *d; 620f66f451Sopenharmony_ci int count; 630f66f451Sopenharmony_ci}; 640f66f451Sopenharmony_ci 650f66f451Sopenharmony_cistruct hashed { 660f66f451Sopenharmony_ci struct list *head; 670f66f451Sopenharmony_ci}; 680f66f451Sopenharmony_ci 690f66f451Sopenharmony_ci#define HASH_NR 256 700f66f451Sopenharmony_cistruct hashed h[HASH_NR]; 710f66f451Sopenharmony_cistruct list_pid *pids = NULL; 720f66f451Sopenharmony_ci 730f66f451Sopenharmony_ci// convert IP address to string. 740f66f451Sopenharmony_cistatic char *sock_to_address(struct sockaddr *sock, int flags) 750f66f451Sopenharmony_ci{ 760f66f451Sopenharmony_ci char hbuf[NI_MAXHOST] = {0,}; 770f66f451Sopenharmony_ci char sbuf[NI_MAXSERV] = {0,}; 780f66f451Sopenharmony_ci int status = 0; 790f66f451Sopenharmony_ci socklen_t len = sizeof(struct sockaddr_in6); 800f66f451Sopenharmony_ci 810f66f451Sopenharmony_ci if (!(status = getnameinfo(sock, len, hbuf, sizeof(hbuf), sbuf, 820f66f451Sopenharmony_ci sizeof(sbuf), flags))) { 830f66f451Sopenharmony_ci if (flags & NI_NUMERICSERV) return xmprintf("%s:%s",hbuf, sbuf); 840f66f451Sopenharmony_ci return xmprintf("%s",hbuf); 850f66f451Sopenharmony_ci } 860f66f451Sopenharmony_ci error_exit("getnameinfo: %s", gai_strerror(status)); 870f66f451Sopenharmony_ci} 880f66f451Sopenharmony_ci 890f66f451Sopenharmony_ci// Insert pid, ip and fd in the list. 900f66f451Sopenharmony_cistatic void insert(struct list_pid **l, int pid, char *addr) 910f66f451Sopenharmony_ci{ 920f66f451Sopenharmony_ci struct list_pid *newnode = xmalloc(sizeof(struct list_pid)); 930f66f451Sopenharmony_ci newnode->pid = pid; 940f66f451Sopenharmony_ci newnode->ip = addr; 950f66f451Sopenharmony_ci newnode->next = NULL; 960f66f451Sopenharmony_ci if (!*l) *l = newnode; 970f66f451Sopenharmony_ci else { 980f66f451Sopenharmony_ci newnode->next = (*l); 990f66f451Sopenharmony_ci *l = newnode; 1000f66f451Sopenharmony_ci } 1010f66f451Sopenharmony_ci} 1020f66f451Sopenharmony_ci 1030f66f451Sopenharmony_ci// Hashing of IP address. 1040f66f451Sopenharmony_cistatic int haship( char *addr) 1050f66f451Sopenharmony_ci{ 1060f66f451Sopenharmony_ci uint32_t ip[8] = {0,}; 1070f66f451Sopenharmony_ci int count = 0, i = 0; 1080f66f451Sopenharmony_ci 1090f66f451Sopenharmony_ci if (!addr) error_exit("NULL ip"); 1100f66f451Sopenharmony_ci while (i < strlen(addr)) { 1110f66f451Sopenharmony_ci while (addr[i] && (addr[i] != ':') && (addr[i] != '.')) { 1120f66f451Sopenharmony_ci ip[count] = ip[count]*10 + (addr[i]-'0'); 1130f66f451Sopenharmony_ci i++; 1140f66f451Sopenharmony_ci } 1150f66f451Sopenharmony_ci if (i >= strlen(addr)) break; 1160f66f451Sopenharmony_ci count++; 1170f66f451Sopenharmony_ci i++; 1180f66f451Sopenharmony_ci } 1190f66f451Sopenharmony_ci return (ip[0]^ip[1]^ip[2]^ip[3]^ip[4]^ip[5]^ip[6]^ip[7])%HASH_NR; 1200f66f451Sopenharmony_ci} 1210f66f451Sopenharmony_ci 1220f66f451Sopenharmony_ci// Remove a node from the list. 1230f66f451Sopenharmony_cistatic char *delete(struct list_pid **pids, int pid) 1240f66f451Sopenharmony_ci{ 1250f66f451Sopenharmony_ci struct list_pid *prev, *free_node, *head = *pids; 1260f66f451Sopenharmony_ci char *ip = NULL; 1270f66f451Sopenharmony_ci 1280f66f451Sopenharmony_ci if (!head) return NULL; 1290f66f451Sopenharmony_ci prev = free_node = NULL; 1300f66f451Sopenharmony_ci while (head) { 1310f66f451Sopenharmony_ci if (head->pid == pid) { 1320f66f451Sopenharmony_ci ip = head->ip; 1330f66f451Sopenharmony_ci free_node = head; 1340f66f451Sopenharmony_ci if (!prev) *pids = head->next; 1350f66f451Sopenharmony_ci else prev->next = head->next; 1360f66f451Sopenharmony_ci free(free_node); 1370f66f451Sopenharmony_ci return ip; 1380f66f451Sopenharmony_ci } 1390f66f451Sopenharmony_ci prev = head; 1400f66f451Sopenharmony_ci head = head->next; 1410f66f451Sopenharmony_ci } 1420f66f451Sopenharmony_ci return NULL; 1430f66f451Sopenharmony_ci} 1440f66f451Sopenharmony_ci 1450f66f451Sopenharmony_ci// decrement the ref count fora connection, if count reches ZERO then remove the node 1460f66f451Sopenharmony_cistatic void remove_connection(char *ip) 1470f66f451Sopenharmony_ci{ 1480f66f451Sopenharmony_ci struct list *head, *prev = NULL, *free_node = NULL; 1490f66f451Sopenharmony_ci int hash = haship(ip); 1500f66f451Sopenharmony_ci 1510f66f451Sopenharmony_ci head = h[hash].head; 1520f66f451Sopenharmony_ci while (head) { 1530f66f451Sopenharmony_ci if (!strcmp(ip, head->d)) { 1540f66f451Sopenharmony_ci head->count--; 1550f66f451Sopenharmony_ci free_node = head; 1560f66f451Sopenharmony_ci if (!head->count) { 1570f66f451Sopenharmony_ci if (!prev) h[hash].head = head->next; 1580f66f451Sopenharmony_ci else prev->next = head->next; 1590f66f451Sopenharmony_ci free(free_node); 1600f66f451Sopenharmony_ci } 1610f66f451Sopenharmony_ci break; 1620f66f451Sopenharmony_ci } 1630f66f451Sopenharmony_ci prev = head; 1640f66f451Sopenharmony_ci head = head->next; 1650f66f451Sopenharmony_ci } 1660f66f451Sopenharmony_ci free(ip); 1670f66f451Sopenharmony_ci} 1680f66f451Sopenharmony_ci 1690f66f451Sopenharmony_ci// Handler function. 1700f66f451Sopenharmony_cistatic void handle_exit(int sig) 1710f66f451Sopenharmony_ci{ 1720f66f451Sopenharmony_ci int status; 1730f66f451Sopenharmony_ci pid_t pid_n = wait(&status); 1740f66f451Sopenharmony_ci 1750f66f451Sopenharmony_ci if (pid_n <= 0) return; 1760f66f451Sopenharmony_ci char *ip = delete(&pids, pid_n); 1770f66f451Sopenharmony_ci if (!ip) return; 1780f66f451Sopenharmony_ci remove_connection(ip); 1790f66f451Sopenharmony_ci TT.count_all--; 1800f66f451Sopenharmony_ci if (toys.optflags & FLAG_v) { 1810f66f451Sopenharmony_ci if (WIFEXITED(status)) 1820f66f451Sopenharmony_ci xprintf("%s: end %d exit %d\n",toys.which->name, pid_n, WEXITSTATUS(status)); 1830f66f451Sopenharmony_ci else if (WIFSIGNALED(status)) 1840f66f451Sopenharmony_ci xprintf("%s: end %d signaled %d\n",toys.which->name, pid_n, WTERMSIG(status)); 1850f66f451Sopenharmony_ci if (TT.cn > 1) xprintf("%s: status %d/%d\n",toys.which->name, TT.count_all, TT.cn); 1860f66f451Sopenharmony_ci } 1870f66f451Sopenharmony_ci} 1880f66f451Sopenharmony_ci 1890f66f451Sopenharmony_ci// Grab uid and gid 1900f66f451Sopenharmony_cistatic void get_uidgid(uid_t *uid, gid_t *gid, char *ug) 1910f66f451Sopenharmony_ci{ 1920f66f451Sopenharmony_ci struct passwd *pass = NULL; 1930f66f451Sopenharmony_ci struct group *grp = NULL; 1940f66f451Sopenharmony_ci char *user = NULL, *group = NULL; 1950f66f451Sopenharmony_ci unsigned int n; 1960f66f451Sopenharmony_ci 1970f66f451Sopenharmony_ci user = ug; 1980f66f451Sopenharmony_ci group = strchr(ug,':'); 1990f66f451Sopenharmony_ci if (group) { 2000f66f451Sopenharmony_ci *group = '\0'; 2010f66f451Sopenharmony_ci group++; 2020f66f451Sopenharmony_ci } 2030f66f451Sopenharmony_ci if (!(pass = getpwnam(user))) { 2040f66f451Sopenharmony_ci n = atolx_range(user, 0, INT_MAX); 2050f66f451Sopenharmony_ci if (!(pass = getpwuid(n))) perror_exit("Invalid user '%s'", user); 2060f66f451Sopenharmony_ci } 2070f66f451Sopenharmony_ci *uid = pass->pw_uid; 2080f66f451Sopenharmony_ci *gid = pass->pw_gid; 2090f66f451Sopenharmony_ci 2100f66f451Sopenharmony_ci if (group) { 2110f66f451Sopenharmony_ci if (!(grp = getgrnam(group))) { 2120f66f451Sopenharmony_ci n = atolx_range(group, 0, INT_MAX); 2130f66f451Sopenharmony_ci if (!(grp = getgrgid(n))) perror_exit("Invalid group '%s'",group); 2140f66f451Sopenharmony_ci } 2150f66f451Sopenharmony_ci } 2160f66f451Sopenharmony_ci if (grp) *gid = grp->gr_gid; 2170f66f451Sopenharmony_ci} 2180f66f451Sopenharmony_ci 2190f66f451Sopenharmony_ci// Bind socket. 2200f66f451Sopenharmony_cistatic int create_bind_sock(char *host, struct sockaddr *haddr) 2210f66f451Sopenharmony_ci{ 2220f66f451Sopenharmony_ci struct addrinfo hints, *res = NULL, *rp; 2230f66f451Sopenharmony_ci int sockfd, ret, set = 1; 2240f66f451Sopenharmony_ci char *ptr; 2250f66f451Sopenharmony_ci unsigned long port; 2260f66f451Sopenharmony_ci 2270f66f451Sopenharmony_ci errno = 0; 2280f66f451Sopenharmony_ci port = strtoul(toys.optargs[1], &ptr, 10); 2290f66f451Sopenharmony_ci if (errno || port > 65535) 2300f66f451Sopenharmony_ci error_exit("Invalid port, Range is [0-65535]"); 2310f66f451Sopenharmony_ci if (*ptr) ptr = toys.optargs[1]; 2320f66f451Sopenharmony_ci else { 2330f66f451Sopenharmony_ci sprintf(toybuf, "%lu", port); 2340f66f451Sopenharmony_ci ptr = toybuf; 2350f66f451Sopenharmony_ci } 2360f66f451Sopenharmony_ci 2370f66f451Sopenharmony_ci memset(&hints, 0, sizeof hints); 2380f66f451Sopenharmony_ci hints.ai_family = AF_UNSPEC; 2390f66f451Sopenharmony_ci hints.ai_socktype = ((TT.udp) ?SOCK_DGRAM : SOCK_STREAM); 2400f66f451Sopenharmony_ci if ((ret = getaddrinfo(host, ptr, &hints, &res))) 2410f66f451Sopenharmony_ci perror_exit("%s", gai_strerror(ret)); 2420f66f451Sopenharmony_ci 2430f66f451Sopenharmony_ci for (rp = res; rp; rp = rp->ai_next) 2440f66f451Sopenharmony_ci if ( (rp->ai_family == AF_INET) || (rp->ai_family == AF_INET6)) break; 2450f66f451Sopenharmony_ci 2460f66f451Sopenharmony_ci if (!rp) error_exit("Invalid IP %s", host); 2470f66f451Sopenharmony_ci 2480f66f451Sopenharmony_ci sockfd = xsocket(rp->ai_family, TT.udp ?SOCK_DGRAM :SOCK_STREAM, 0); 2490f66f451Sopenharmony_ci setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &set, sizeof(set)); 2500f66f451Sopenharmony_ci if (TT.udp) setsockopt(sockfd, IPPROTO_IP, IP_PKTINFO, &set, sizeof(set)); 2510f66f451Sopenharmony_ci xbind(sockfd, rp->ai_addr, rp->ai_addrlen); 2520f66f451Sopenharmony_ci if(haddr) memcpy(haddr, rp->ai_addr, rp->ai_addrlen); 2530f66f451Sopenharmony_ci freeaddrinfo(res); 2540f66f451Sopenharmony_ci return sockfd; 2550f66f451Sopenharmony_ci} 2560f66f451Sopenharmony_ci 2570f66f451Sopenharmony_cistatic void handle_signal(int sig) 2580f66f451Sopenharmony_ci{ 2590f66f451Sopenharmony_ci if (toys.optflags & FLAG_v) xprintf("got signal %d, exit\n", sig); 2600f66f451Sopenharmony_ci raise(sig); 2610f66f451Sopenharmony_ci _exit(sig + 128); //should not reach here 2620f66f451Sopenharmony_ci} 2630f66f451Sopenharmony_ci 2640f66f451Sopenharmony_civoid tcpsvd_main(void) 2650f66f451Sopenharmony_ci{ 2660f66f451Sopenharmony_ci uid_t uid = 0; 2670f66f451Sopenharmony_ci gid_t gid = 0; 2680f66f451Sopenharmony_ci pid_t pid; 2690f66f451Sopenharmony_ci char haddr[sizeof(struct sockaddr_in6)]; 2700f66f451Sopenharmony_ci struct list *head, *newnode; 2710f66f451Sopenharmony_ci int hash, fd, newfd, j; 2720f66f451Sopenharmony_ci char *ptr = NULL, *addr, *server, buf[sizeof(struct sockaddr_in6)]; 2730f66f451Sopenharmony_ci socklen_t len = sizeof(buf); 2740f66f451Sopenharmony_ci 2750f66f451Sopenharmony_ci TT.udp = (*toys.which->name == 'u'); 2760f66f451Sopenharmony_ci if (TT.udp) toys.optflags &= ~FLAG_C; 2770f66f451Sopenharmony_ci memset(buf, 0, len); 2780f66f451Sopenharmony_ci if (toys.optflags & FLAG_C) { 2790f66f451Sopenharmony_ci if ((ptr = strchr(TT.nmsg, ':'))) { 2800f66f451Sopenharmony_ci *ptr = '\0'; 2810f66f451Sopenharmony_ci ptr++; 2820f66f451Sopenharmony_ci } 2830f66f451Sopenharmony_ci TT.maxc = atolx_range(TT.nmsg, 1, INT_MAX); 2840f66f451Sopenharmony_ci } 2850f66f451Sopenharmony_ci 2860f66f451Sopenharmony_ci fd = create_bind_sock(toys.optargs[0], (struct sockaddr*)&haddr); 2870f66f451Sopenharmony_ci if(toys.optflags & FLAG_u) { 2880f66f451Sopenharmony_ci get_uidgid(&uid, &gid, TT.user); 2890f66f451Sopenharmony_ci setuid(uid); 2900f66f451Sopenharmony_ci setgid(gid); 2910f66f451Sopenharmony_ci } 2920f66f451Sopenharmony_ci 2930f66f451Sopenharmony_ci if (!TT.udp && (listen(fd, TT.bn) < 0)) perror_exit("Listen failed"); 2940f66f451Sopenharmony_ci server = sock_to_address((struct sockaddr*)&haddr, NI_NUMERICHOST|NI_NUMERICSERV); 2950f66f451Sopenharmony_ci if (toys.optflags & FLAG_v) { 2960f66f451Sopenharmony_ci if (toys.optflags & FLAG_u) 2970f66f451Sopenharmony_ci xprintf("%s: listening on %s, starting, uid %u, gid %u\n" 2980f66f451Sopenharmony_ci ,toys.which->name, server, uid, gid); 2990f66f451Sopenharmony_ci else 3000f66f451Sopenharmony_ci xprintf("%s: listening on %s, starting\n", toys.which->name, server); 3010f66f451Sopenharmony_ci } 3020f66f451Sopenharmony_ci for (j = 0; j < HASH_NR; j++) h[j].head = NULL; 3030f66f451Sopenharmony_ci sigatexit(handle_signal); 3040f66f451Sopenharmony_ci signal(SIGCHLD, handle_exit); 3050f66f451Sopenharmony_ci 3060f66f451Sopenharmony_ci while (1) { 3070f66f451Sopenharmony_ci if (TT.count_all < TT.cn) { 3080f66f451Sopenharmony_ci if (TT.udp) { 3090f66f451Sopenharmony_ci if(recvfrom(fd, NULL, 0, MSG_PEEK, (struct sockaddr *)buf, &len) < 0) 3100f66f451Sopenharmony_ci perror_exit("recvfrom"); 3110f66f451Sopenharmony_ci newfd = fd; 3120f66f451Sopenharmony_ci } else { 3130f66f451Sopenharmony_ci newfd = accept(fd, (struct sockaddr *)buf, &len); 3140f66f451Sopenharmony_ci if (newfd < 0) perror_exit("Error on accept"); 3150f66f451Sopenharmony_ci } 3160f66f451Sopenharmony_ci } else { 3170f66f451Sopenharmony_ci sigset_t ss; 3180f66f451Sopenharmony_ci sigemptyset(&ss); 3190f66f451Sopenharmony_ci sigsuspend(&ss); 3200f66f451Sopenharmony_ci continue; 3210f66f451Sopenharmony_ci } 3220f66f451Sopenharmony_ci TT.count_all++; 3230f66f451Sopenharmony_ci addr = sock_to_address((struct sockaddr*)buf, NI_NUMERICHOST); 3240f66f451Sopenharmony_ci 3250f66f451Sopenharmony_ci hash = haship(addr); 3260f66f451Sopenharmony_ci if (toys.optflags & FLAG_C) { 3270f66f451Sopenharmony_ci for (head = h[hash].head; head; head = head->next) 3280f66f451Sopenharmony_ci if (!strcmp(head->d, addr)) break; 3290f66f451Sopenharmony_ci 3300f66f451Sopenharmony_ci if (head && head->count >= TT.maxc) { 3310f66f451Sopenharmony_ci if (ptr) write(newfd, ptr, strlen(ptr)+1); 3320f66f451Sopenharmony_ci close(newfd); 3330f66f451Sopenharmony_ci TT.count_all--; 3340f66f451Sopenharmony_ci continue; 3350f66f451Sopenharmony_ci } 3360f66f451Sopenharmony_ci } 3370f66f451Sopenharmony_ci 3380f66f451Sopenharmony_ci newnode = (struct list*)xzalloc(sizeof(struct list)); 3390f66f451Sopenharmony_ci newnode->d = addr; 3400f66f451Sopenharmony_ci for (head = h[hash].head; head; head = head->next) { 3410f66f451Sopenharmony_ci if (!strcmp(addr, head->d)) { 3420f66f451Sopenharmony_ci head->count++; 3430f66f451Sopenharmony_ci free(newnode); 3440f66f451Sopenharmony_ci break; 3450f66f451Sopenharmony_ci } 3460f66f451Sopenharmony_ci } 3470f66f451Sopenharmony_ci 3480f66f451Sopenharmony_ci if (!head) { 3490f66f451Sopenharmony_ci newnode->next = h[hash].head; 3500f66f451Sopenharmony_ci h[hash].head = newnode; 3510f66f451Sopenharmony_ci h[hash].head->count++; 3520f66f451Sopenharmony_ci } 3530f66f451Sopenharmony_ci 3540f66f451Sopenharmony_ci if (!(pid = xfork())) { 3550f66f451Sopenharmony_ci char *serv = NULL, *clie = NULL; 3560f66f451Sopenharmony_ci char *client = sock_to_address((struct sockaddr*)buf, NI_NUMERICHOST | NI_NUMERICSERV); 3570f66f451Sopenharmony_ci if (toys.optflags & FLAG_h) { //lookup name 3580f66f451Sopenharmony_ci if (toys.optflags & FLAG_l) serv = xstrdup(TT.name); 3590f66f451Sopenharmony_ci else serv = sock_to_address((struct sockaddr*)&haddr, 0); 3600f66f451Sopenharmony_ci clie = sock_to_address((struct sockaddr*)buf, 0); 3610f66f451Sopenharmony_ci } 3620f66f451Sopenharmony_ci 3630f66f451Sopenharmony_ci if (!(toys.optflags & FLAG_E)) { 3640f66f451Sopenharmony_ci setenv("PROTO", TT.udp ?"UDP" :"TCP", 1); 3650f66f451Sopenharmony_ci setenv("PROTOLOCALADDR", server, 1); 3660f66f451Sopenharmony_ci setenv("PROTOREMOTEADDR", client, 1); 3670f66f451Sopenharmony_ci if (toys.optflags & FLAG_h) { 3680f66f451Sopenharmony_ci setenv("PROTOLOCALHOST", serv, 1); 3690f66f451Sopenharmony_ci setenv("PROTOREMOTEHOST", clie, 1); 3700f66f451Sopenharmony_ci } 3710f66f451Sopenharmony_ci if (!TT.udp) { 3720f66f451Sopenharmony_ci char max_c[32]; 3730f66f451Sopenharmony_ci sprintf(max_c, "%d", TT.maxc); 3740f66f451Sopenharmony_ci setenv("TCPCONCURRENCY", max_c, 1); //Not valid for udp 3750f66f451Sopenharmony_ci } 3760f66f451Sopenharmony_ci } 3770f66f451Sopenharmony_ci if (toys.optflags & FLAG_v) { 3780f66f451Sopenharmony_ci xprintf("%s: start %d %s-%s",toys.which->name, getpid(), server, client); 3790f66f451Sopenharmony_ci if (toys.optflags & FLAG_h) xprintf(" (%s-%s)", serv, clie); 3800f66f451Sopenharmony_ci xputc('\n'); 3810f66f451Sopenharmony_ci if (TT.cn > 1) 3820f66f451Sopenharmony_ci xprintf("%s: status %d/%d\n",toys.which->name, TT.count_all, TT.cn); 3830f66f451Sopenharmony_ci } 3840f66f451Sopenharmony_ci free(client); 3850f66f451Sopenharmony_ci if (toys.optflags & FLAG_h) { 3860f66f451Sopenharmony_ci free(serv); 3870f66f451Sopenharmony_ci free(clie); 3880f66f451Sopenharmony_ci } 3890f66f451Sopenharmony_ci if (TT.udp) xconnect(newfd, (struct sockaddr *)buf, sizeof(buf)); 3900f66f451Sopenharmony_ci 3910f66f451Sopenharmony_ci close(0); 3920f66f451Sopenharmony_ci close(1); 3930f66f451Sopenharmony_ci dup2(newfd, 0); 3940f66f451Sopenharmony_ci dup2(newfd, 1); 3950f66f451Sopenharmony_ci xexec(toys.optargs+2); //skip IP PORT 3960f66f451Sopenharmony_ci } else { 3970f66f451Sopenharmony_ci insert(&pids, pid, addr); 3980f66f451Sopenharmony_ci xclose(newfd); //close and reopen for next client. 3990f66f451Sopenharmony_ci if (TT.udp) fd = create_bind_sock(toys.optargs[0], 4000f66f451Sopenharmony_ci (struct sockaddr*)&haddr); 4010f66f451Sopenharmony_ci } 4020f66f451Sopenharmony_ci } //while(1) 4030f66f451Sopenharmony_ci} 404