1*cf5a6c84SAndroid Build Coastguard Worker /* tcpsvd.c - TCP(UDP)/IP service daemon
2*cf5a6c84SAndroid Build Coastguard Worker *
3*cf5a6c84SAndroid Build Coastguard Worker * Copyright 2013 Ashwini Kumar <[email protected]>
4*cf5a6c84SAndroid Build Coastguard Worker * Copyright 2013 Sandeep Sharma <[email protected]>
5*cf5a6c84SAndroid Build Coastguard Worker * Copyright 2013 Kyungwan Han <[email protected]>
6*cf5a6c84SAndroid Build Coastguard Worker *
7*cf5a6c84SAndroid Build Coastguard Worker * No Standard.
8*cf5a6c84SAndroid Build Coastguard Worker
9*cf5a6c84SAndroid Build Coastguard Worker USE_TCPSVD(NEWTOY(tcpsvd, "^<3c#=30<1b#=20<0C:u:l:hEv", TOYFLAG_USR|TOYFLAG_BIN))
10*cf5a6c84SAndroid Build Coastguard Worker USE_TCPSVD(OLDTOY(udpsvd, tcpsvd, TOYFLAG_USR|TOYFLAG_BIN))
11*cf5a6c84SAndroid Build Coastguard Worker
12*cf5a6c84SAndroid Build Coastguard Worker config TCPSVD
13*cf5a6c84SAndroid Build Coastguard Worker bool "tcpsvd"
14*cf5a6c84SAndroid Build Coastguard Worker default n
15*cf5a6c84SAndroid Build Coastguard Worker depends on TOYBOX_FORK
16*cf5a6c84SAndroid Build Coastguard Worker help
17*cf5a6c84SAndroid Build Coastguard Worker usage: tcpsvd [-hEv] [-c N] [-C N[:MSG]] [-b N] [-u User] [-l Name] IP Port Prog
18*cf5a6c84SAndroid Build Coastguard Worker usage: udpsvd [-hEv] [-c N] [-u User] [-l Name] IP Port Prog
19*cf5a6c84SAndroid Build Coastguard Worker
20*cf5a6c84SAndroid Build Coastguard Worker Create TCP/UDP socket, bind to IP:PORT and listen for incoming connection.
21*cf5a6c84SAndroid Build Coastguard Worker Run PROG for each connection.
22*cf5a6c84SAndroid Build Coastguard Worker
23*cf5a6c84SAndroid Build Coastguard Worker IP IP to listen on, 0 = all
24*cf5a6c84SAndroid Build Coastguard Worker PORT Port to listen on
25*cf5a6c84SAndroid Build Coastguard Worker PROG ARGS Program to run
26*cf5a6c84SAndroid Build Coastguard Worker -l NAME Local hostname (else looks up local hostname in DNS)
27*cf5a6c84SAndroid Build Coastguard Worker -u USER[:GRP] Change to user/group after bind
28*cf5a6c84SAndroid Build Coastguard Worker -c N Handle up to N (> 0) connections simultaneously
29*cf5a6c84SAndroid Build Coastguard Worker -b N (TCP Only) Allow a backlog of approximately N TCP SYNs
30*cf5a6c84SAndroid Build Coastguard Worker -C N[:MSG] (TCP Only) Allow only up to N (> 0) connections from the same IP
31*cf5a6c84SAndroid Build Coastguard Worker New connections from this IP address are closed
32*cf5a6c84SAndroid Build Coastguard Worker immediately. MSG is written to the peer before close
33*cf5a6c84SAndroid Build Coastguard Worker -h Look up peer's hostname
34*cf5a6c84SAndroid Build Coastguard Worker -E Don't set up environment variables
35*cf5a6c84SAndroid Build Coastguard Worker -v Verbose
36*cf5a6c84SAndroid Build Coastguard Worker */
37*cf5a6c84SAndroid Build Coastguard Worker
38*cf5a6c84SAndroid Build Coastguard Worker #define FOR_tcpsvd
39*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
40*cf5a6c84SAndroid Build Coastguard Worker
41*cf5a6c84SAndroid Build Coastguard Worker GLOBALS(
42*cf5a6c84SAndroid Build Coastguard Worker char *l, *u, *C;
43*cf5a6c84SAndroid Build Coastguard Worker long b, c;
44*cf5a6c84SAndroid Build Coastguard Worker
45*cf5a6c84SAndroid Build Coastguard Worker int maxc;
46*cf5a6c84SAndroid Build Coastguard Worker int count_all;
47*cf5a6c84SAndroid Build Coastguard Worker int udp;
48*cf5a6c84SAndroid Build Coastguard Worker )
49*cf5a6c84SAndroid Build Coastguard Worker
50*cf5a6c84SAndroid Build Coastguard Worker struct list_pid {
51*cf5a6c84SAndroid Build Coastguard Worker struct list_pid *next;
52*cf5a6c84SAndroid Build Coastguard Worker char *ip;
53*cf5a6c84SAndroid Build Coastguard Worker int pid;
54*cf5a6c84SAndroid Build Coastguard Worker };
55*cf5a6c84SAndroid Build Coastguard Worker
56*cf5a6c84SAndroid Build Coastguard Worker struct list {
57*cf5a6c84SAndroid Build Coastguard Worker struct list* next;
58*cf5a6c84SAndroid Build Coastguard Worker char *d;
59*cf5a6c84SAndroid Build Coastguard Worker int count;
60*cf5a6c84SAndroid Build Coastguard Worker };
61*cf5a6c84SAndroid Build Coastguard Worker
62*cf5a6c84SAndroid Build Coastguard Worker struct hashed {
63*cf5a6c84SAndroid Build Coastguard Worker struct list *head;
64*cf5a6c84SAndroid Build Coastguard Worker };
65*cf5a6c84SAndroid Build Coastguard Worker
66*cf5a6c84SAndroid Build Coastguard Worker #define HASH_NR 256
67*cf5a6c84SAndroid Build Coastguard Worker struct hashed h[HASH_NR];
68*cf5a6c84SAndroid Build Coastguard Worker struct list_pid *pids = NULL;
69*cf5a6c84SAndroid Build Coastguard Worker
70*cf5a6c84SAndroid Build Coastguard Worker // convert IP address to string.
sock_to_address(struct sockaddr * sock,int flags)71*cf5a6c84SAndroid Build Coastguard Worker static char *sock_to_address(struct sockaddr *sock, int flags)
72*cf5a6c84SAndroid Build Coastguard Worker {
73*cf5a6c84SAndroid Build Coastguard Worker char hbuf[NI_MAXHOST] = {0,};
74*cf5a6c84SAndroid Build Coastguard Worker char sbuf[NI_MAXSERV] = {0,};
75*cf5a6c84SAndroid Build Coastguard Worker int status = 0;
76*cf5a6c84SAndroid Build Coastguard Worker socklen_t len = sizeof(struct sockaddr_in6);
77*cf5a6c84SAndroid Build Coastguard Worker
78*cf5a6c84SAndroid Build Coastguard Worker if (!(status = getnameinfo(sock, len, hbuf, sizeof(hbuf), sbuf,
79*cf5a6c84SAndroid Build Coastguard Worker sizeof(sbuf), flags))) {
80*cf5a6c84SAndroid Build Coastguard Worker if (flags & NI_NUMERICSERV) return xmprintf("%s:%s",hbuf, sbuf);
81*cf5a6c84SAndroid Build Coastguard Worker return xmprintf("%s",hbuf);
82*cf5a6c84SAndroid Build Coastguard Worker }
83*cf5a6c84SAndroid Build Coastguard Worker error_exit("getnameinfo: %s", gai_strerror(status));
84*cf5a6c84SAndroid Build Coastguard Worker }
85*cf5a6c84SAndroid Build Coastguard Worker
86*cf5a6c84SAndroid Build Coastguard Worker // Insert pid, ip and fd in the list.
insert(struct list_pid ** l,int pid,char * addr)87*cf5a6c84SAndroid Build Coastguard Worker static void insert(struct list_pid **l, int pid, char *addr)
88*cf5a6c84SAndroid Build Coastguard Worker {
89*cf5a6c84SAndroid Build Coastguard Worker struct list_pid *newnode = xmalloc(sizeof(struct list_pid));
90*cf5a6c84SAndroid Build Coastguard Worker newnode->pid = pid;
91*cf5a6c84SAndroid Build Coastguard Worker newnode->ip = addr;
92*cf5a6c84SAndroid Build Coastguard Worker newnode->next = NULL;
93*cf5a6c84SAndroid Build Coastguard Worker if (!*l) *l = newnode;
94*cf5a6c84SAndroid Build Coastguard Worker else {
95*cf5a6c84SAndroid Build Coastguard Worker newnode->next = (*l);
96*cf5a6c84SAndroid Build Coastguard Worker *l = newnode;
97*cf5a6c84SAndroid Build Coastguard Worker }
98*cf5a6c84SAndroid Build Coastguard Worker }
99*cf5a6c84SAndroid Build Coastguard Worker
100*cf5a6c84SAndroid Build Coastguard Worker // Hashing of IP address.
haship(char * addr)101*cf5a6c84SAndroid Build Coastguard Worker static int haship(char *addr)
102*cf5a6c84SAndroid Build Coastguard Worker {
103*cf5a6c84SAndroid Build Coastguard Worker uint32_t ip[8] = {0,};
104*cf5a6c84SAndroid Build Coastguard Worker int count = 0, i = 0;
105*cf5a6c84SAndroid Build Coastguard Worker
106*cf5a6c84SAndroid Build Coastguard Worker if (!addr) error_exit("NULL ip");
107*cf5a6c84SAndroid Build Coastguard Worker while (i < strlen(addr)) {
108*cf5a6c84SAndroid Build Coastguard Worker while (addr[i] && (addr[i] != ':') && (addr[i] != '.')) {
109*cf5a6c84SAndroid Build Coastguard Worker ip[count] = ip[count]*10 + (addr[i]-'0');
110*cf5a6c84SAndroid Build Coastguard Worker i++;
111*cf5a6c84SAndroid Build Coastguard Worker }
112*cf5a6c84SAndroid Build Coastguard Worker if (i >= strlen(addr)) break;
113*cf5a6c84SAndroid Build Coastguard Worker count++;
114*cf5a6c84SAndroid Build Coastguard Worker i++;
115*cf5a6c84SAndroid Build Coastguard Worker }
116*cf5a6c84SAndroid Build Coastguard Worker return (ip[0]^ip[1]^ip[2]^ip[3]^ip[4]^ip[5]^ip[6]^ip[7])%HASH_NR;
117*cf5a6c84SAndroid Build Coastguard Worker }
118*cf5a6c84SAndroid Build Coastguard Worker
119*cf5a6c84SAndroid Build Coastguard Worker // Remove a node from the list.
delete(struct list_pid ** pids,int pid)120*cf5a6c84SAndroid Build Coastguard Worker static char *delete(struct list_pid **pids, int pid)
121*cf5a6c84SAndroid Build Coastguard Worker {
122*cf5a6c84SAndroid Build Coastguard Worker struct list_pid *prev, *free_node, *head = *pids;
123*cf5a6c84SAndroid Build Coastguard Worker char *ip = NULL;
124*cf5a6c84SAndroid Build Coastguard Worker
125*cf5a6c84SAndroid Build Coastguard Worker if (!head) return NULL;
126*cf5a6c84SAndroid Build Coastguard Worker prev = free_node = NULL;
127*cf5a6c84SAndroid Build Coastguard Worker while (head) {
128*cf5a6c84SAndroid Build Coastguard Worker if (head->pid == pid) {
129*cf5a6c84SAndroid Build Coastguard Worker ip = head->ip;
130*cf5a6c84SAndroid Build Coastguard Worker free_node = head;
131*cf5a6c84SAndroid Build Coastguard Worker if (!prev) *pids = head->next;
132*cf5a6c84SAndroid Build Coastguard Worker else prev->next = head->next;
133*cf5a6c84SAndroid Build Coastguard Worker free(free_node);
134*cf5a6c84SAndroid Build Coastguard Worker return ip;
135*cf5a6c84SAndroid Build Coastguard Worker }
136*cf5a6c84SAndroid Build Coastguard Worker prev = head;
137*cf5a6c84SAndroid Build Coastguard Worker head = head->next;
138*cf5a6c84SAndroid Build Coastguard Worker }
139*cf5a6c84SAndroid Build Coastguard Worker return NULL;
140*cf5a6c84SAndroid Build Coastguard Worker }
141*cf5a6c84SAndroid Build Coastguard Worker
142*cf5a6c84SAndroid Build Coastguard Worker // decrement the ref count fora connection, if count reches ZERO then remove the node
remove_connection(char * ip)143*cf5a6c84SAndroid Build Coastguard Worker static void remove_connection(char *ip)
144*cf5a6c84SAndroid Build Coastguard Worker {
145*cf5a6c84SAndroid Build Coastguard Worker struct list *head, *prev = NULL, *free_node = NULL;
146*cf5a6c84SAndroid Build Coastguard Worker int hash = haship(ip);
147*cf5a6c84SAndroid Build Coastguard Worker
148*cf5a6c84SAndroid Build Coastguard Worker head = h[hash].head;
149*cf5a6c84SAndroid Build Coastguard Worker while (head) {
150*cf5a6c84SAndroid Build Coastguard Worker if (!strcmp(ip, head->d)) {
151*cf5a6c84SAndroid Build Coastguard Worker head->count--;
152*cf5a6c84SAndroid Build Coastguard Worker free_node = head;
153*cf5a6c84SAndroid Build Coastguard Worker if (!head->count) {
154*cf5a6c84SAndroid Build Coastguard Worker if (!prev) h[hash].head = head->next;
155*cf5a6c84SAndroid Build Coastguard Worker else prev->next = head->next;
156*cf5a6c84SAndroid Build Coastguard Worker free(free_node);
157*cf5a6c84SAndroid Build Coastguard Worker }
158*cf5a6c84SAndroid Build Coastguard Worker break;
159*cf5a6c84SAndroid Build Coastguard Worker }
160*cf5a6c84SAndroid Build Coastguard Worker prev = head;
161*cf5a6c84SAndroid Build Coastguard Worker head = head->next;
162*cf5a6c84SAndroid Build Coastguard Worker }
163*cf5a6c84SAndroid Build Coastguard Worker free(ip);
164*cf5a6c84SAndroid Build Coastguard Worker }
165*cf5a6c84SAndroid Build Coastguard Worker
166*cf5a6c84SAndroid Build Coastguard Worker // Handler function.
handle_exit(int sig)167*cf5a6c84SAndroid Build Coastguard Worker static void handle_exit(int sig)
168*cf5a6c84SAndroid Build Coastguard Worker {
169*cf5a6c84SAndroid Build Coastguard Worker int status;
170*cf5a6c84SAndroid Build Coastguard Worker pid_t pid_n = wait(&status);
171*cf5a6c84SAndroid Build Coastguard Worker char *ip = (pid_n<1) ? 0 : delete(&pids, pid_n);
172*cf5a6c84SAndroid Build Coastguard Worker
173*cf5a6c84SAndroid Build Coastguard Worker if (!ip) return;
174*cf5a6c84SAndroid Build Coastguard Worker remove_connection(ip);
175*cf5a6c84SAndroid Build Coastguard Worker TT.count_all--;
176*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(v)) {
177*cf5a6c84SAndroid Build Coastguard Worker if (WIFEXITED(status))
178*cf5a6c84SAndroid Build Coastguard Worker xprintf("%s: end %d exit %d\n",toys.which->name, pid_n, WEXITSTATUS(status));
179*cf5a6c84SAndroid Build Coastguard Worker else if (WIFSIGNALED(status))
180*cf5a6c84SAndroid Build Coastguard Worker xprintf("%s: end %d signaled %d\n",toys.which->name, pid_n, WTERMSIG(status));
181*cf5a6c84SAndroid Build Coastguard Worker if (TT.c > 1) xprintf("%s: status %d/%ld\n",toys.which->name, TT.count_all, TT.c);
182*cf5a6c84SAndroid Build Coastguard Worker }
183*cf5a6c84SAndroid Build Coastguard Worker }
184*cf5a6c84SAndroid Build Coastguard Worker
185*cf5a6c84SAndroid Build Coastguard Worker // Grab uid and gid
get_uidgid(uid_t * uid,gid_t * gid,char * ug)186*cf5a6c84SAndroid Build Coastguard Worker static void get_uidgid(uid_t *uid, gid_t *gid, char *ug)
187*cf5a6c84SAndroid Build Coastguard Worker {
188*cf5a6c84SAndroid Build Coastguard Worker struct passwd *pass = NULL;
189*cf5a6c84SAndroid Build Coastguard Worker struct group *grp = NULL;
190*cf5a6c84SAndroid Build Coastguard Worker char *user = NULL, *group = NULL;
191*cf5a6c84SAndroid Build Coastguard Worker unsigned int n;
192*cf5a6c84SAndroid Build Coastguard Worker
193*cf5a6c84SAndroid Build Coastguard Worker user = ug;
194*cf5a6c84SAndroid Build Coastguard Worker group = strchr(ug,':');
195*cf5a6c84SAndroid Build Coastguard Worker if (group) {
196*cf5a6c84SAndroid Build Coastguard Worker *group = '\0';
197*cf5a6c84SAndroid Build Coastguard Worker group++;
198*cf5a6c84SAndroid Build Coastguard Worker }
199*cf5a6c84SAndroid Build Coastguard Worker if (!(pass = getpwnam(user))) {
200*cf5a6c84SAndroid Build Coastguard Worker n = atolx_range(user, 0, INT_MAX);
201*cf5a6c84SAndroid Build Coastguard Worker if (!(pass = getpwuid(n))) perror_exit("Invalid user '%s'", user);
202*cf5a6c84SAndroid Build Coastguard Worker }
203*cf5a6c84SAndroid Build Coastguard Worker *uid = pass->pw_uid;
204*cf5a6c84SAndroid Build Coastguard Worker *gid = pass->pw_gid;
205*cf5a6c84SAndroid Build Coastguard Worker
206*cf5a6c84SAndroid Build Coastguard Worker if (group) {
207*cf5a6c84SAndroid Build Coastguard Worker if (!(grp = getgrnam(group))) {
208*cf5a6c84SAndroid Build Coastguard Worker n = atolx_range(group, 0, INT_MAX);
209*cf5a6c84SAndroid Build Coastguard Worker if (!(grp = getgrgid(n))) perror_exit("Invalid group '%s'",group);
210*cf5a6c84SAndroid Build Coastguard Worker }
211*cf5a6c84SAndroid Build Coastguard Worker }
212*cf5a6c84SAndroid Build Coastguard Worker if (grp) *gid = grp->gr_gid;
213*cf5a6c84SAndroid Build Coastguard Worker }
214*cf5a6c84SAndroid Build Coastguard Worker
215*cf5a6c84SAndroid Build Coastguard Worker // Bind socket.
create_bind_sock(char * host,struct sockaddr * haddr)216*cf5a6c84SAndroid Build Coastguard Worker static int create_bind_sock(char *host, struct sockaddr *haddr)
217*cf5a6c84SAndroid Build Coastguard Worker {
218*cf5a6c84SAndroid Build Coastguard Worker struct addrinfo hints, *res = NULL, *rp;
219*cf5a6c84SAndroid Build Coastguard Worker int sockfd, ret, set = 1;
220*cf5a6c84SAndroid Build Coastguard Worker char *ptr;
221*cf5a6c84SAndroid Build Coastguard Worker unsigned long port;
222*cf5a6c84SAndroid Build Coastguard Worker
223*cf5a6c84SAndroid Build Coastguard Worker errno = 0;
224*cf5a6c84SAndroid Build Coastguard Worker port = strtoul(toys.optargs[1], &ptr, 10);
225*cf5a6c84SAndroid Build Coastguard Worker if (errno || port > 65535)
226*cf5a6c84SAndroid Build Coastguard Worker error_exit("Invalid port, Range is [0-65535]");
227*cf5a6c84SAndroid Build Coastguard Worker if (*ptr) ptr = toys.optargs[1];
228*cf5a6c84SAndroid Build Coastguard Worker else {
229*cf5a6c84SAndroid Build Coastguard Worker sprintf(toybuf, "%lu", port);
230*cf5a6c84SAndroid Build Coastguard Worker ptr = toybuf;
231*cf5a6c84SAndroid Build Coastguard Worker }
232*cf5a6c84SAndroid Build Coastguard Worker
233*cf5a6c84SAndroid Build Coastguard Worker memset(&hints, 0, sizeof hints);
234*cf5a6c84SAndroid Build Coastguard Worker hints.ai_family = AF_UNSPEC;
235*cf5a6c84SAndroid Build Coastguard Worker hints.ai_socktype = (TT.udp ? SOCK_DGRAM : SOCK_STREAM);
236*cf5a6c84SAndroid Build Coastguard Worker if ((ret = getaddrinfo(host, ptr, &hints, &res)))
237*cf5a6c84SAndroid Build Coastguard Worker perror_exit("%s", gai_strerror(ret));
238*cf5a6c84SAndroid Build Coastguard Worker
239*cf5a6c84SAndroid Build Coastguard Worker for (rp = res; rp; rp = rp->ai_next)
240*cf5a6c84SAndroid Build Coastguard Worker if ( (rp->ai_family == AF_INET) || (rp->ai_family == AF_INET6)) break;
241*cf5a6c84SAndroid Build Coastguard Worker
242*cf5a6c84SAndroid Build Coastguard Worker if (!rp) error_exit("Invalid IP %s", host);
243*cf5a6c84SAndroid Build Coastguard Worker
244*cf5a6c84SAndroid Build Coastguard Worker sockfd = xsocket(rp->ai_family, TT.udp ? SOCK_DGRAM : SOCK_STREAM, 0);
245*cf5a6c84SAndroid Build Coastguard Worker setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &set, sizeof(set));
246*cf5a6c84SAndroid Build Coastguard Worker if (TT.udp) setsockopt(sockfd, IPPROTO_IP, IP_PKTINFO, &set, sizeof(set));
247*cf5a6c84SAndroid Build Coastguard Worker xbind(sockfd, rp->ai_addr, rp->ai_addrlen);
248*cf5a6c84SAndroid Build Coastguard Worker if(haddr) memcpy(haddr, rp->ai_addr, rp->ai_addrlen);
249*cf5a6c84SAndroid Build Coastguard Worker freeaddrinfo(res);
250*cf5a6c84SAndroid Build Coastguard Worker return sockfd;
251*cf5a6c84SAndroid Build Coastguard Worker }
252*cf5a6c84SAndroid Build Coastguard Worker
handle_signal(int sig)253*cf5a6c84SAndroid Build Coastguard Worker static void handle_signal(int sig)
254*cf5a6c84SAndroid Build Coastguard Worker {
255*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(v)) xprintf("got signal %d, exit\n", sig);
256*cf5a6c84SAndroid Build Coastguard Worker raise(sig);
257*cf5a6c84SAndroid Build Coastguard Worker _exit(sig + 128); //should not reach here
258*cf5a6c84SAndroid Build Coastguard Worker }
259*cf5a6c84SAndroid Build Coastguard Worker
tcpsvd_main(void)260*cf5a6c84SAndroid Build Coastguard Worker void tcpsvd_main(void)
261*cf5a6c84SAndroid Build Coastguard Worker {
262*cf5a6c84SAndroid Build Coastguard Worker uid_t uid = 0;
263*cf5a6c84SAndroid Build Coastguard Worker gid_t gid = 0;
264*cf5a6c84SAndroid Build Coastguard Worker pid_t pid;
265*cf5a6c84SAndroid Build Coastguard Worker char haddr[sizeof(struct sockaddr_in6)];
266*cf5a6c84SAndroid Build Coastguard Worker struct list *head, *newnode;
267*cf5a6c84SAndroid Build Coastguard Worker int hash, fd, newfd, j;
268*cf5a6c84SAndroid Build Coastguard Worker char *ptr = NULL, *addr, *server, buf[sizeof(struct sockaddr_in6)];
269*cf5a6c84SAndroid Build Coastguard Worker socklen_t len = sizeof(buf);
270*cf5a6c84SAndroid Build Coastguard Worker
271*cf5a6c84SAndroid Build Coastguard Worker TT.udp = *toys.which->name == 'u';
272*cf5a6c84SAndroid Build Coastguard Worker if (TT.udp) toys.optflags &= ~FLAG_C;
273*cf5a6c84SAndroid Build Coastguard Worker memset(buf, 0, len);
274*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(C)) {
275*cf5a6c84SAndroid Build Coastguard Worker if ((ptr = strchr(TT.C, ':'))) *ptr++ = 0;
276*cf5a6c84SAndroid Build Coastguard Worker TT.maxc = atolx_range(TT.C, 1, INT_MAX);
277*cf5a6c84SAndroid Build Coastguard Worker }
278*cf5a6c84SAndroid Build Coastguard Worker
279*cf5a6c84SAndroid Build Coastguard Worker fd = create_bind_sock(toys.optargs[0], (struct sockaddr*)&haddr);
280*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(u)) {
281*cf5a6c84SAndroid Build Coastguard Worker get_uidgid(&uid, &gid, TT.u);
282*cf5a6c84SAndroid Build Coastguard Worker setuid(uid);
283*cf5a6c84SAndroid Build Coastguard Worker setgid(gid);
284*cf5a6c84SAndroid Build Coastguard Worker }
285*cf5a6c84SAndroid Build Coastguard Worker
286*cf5a6c84SAndroid Build Coastguard Worker if (!TT.udp && (listen(fd, TT.b) < 0)) perror_exit("Listen failed");
287*cf5a6c84SAndroid Build Coastguard Worker server = sock_to_address((struct sockaddr*)&haddr, NI_NUMERICHOST|NI_NUMERICSERV);
288*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(v)) {
289*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(u))
290*cf5a6c84SAndroid Build Coastguard Worker xprintf("%s: listening on %s, starting, uid %u, gid %u\n",
291*cf5a6c84SAndroid Build Coastguard Worker toys.which->name, server, uid, gid);
292*cf5a6c84SAndroid Build Coastguard Worker else
293*cf5a6c84SAndroid Build Coastguard Worker xprintf("%s: listening on %s, starting\n", toys.which->name, server);
294*cf5a6c84SAndroid Build Coastguard Worker }
295*cf5a6c84SAndroid Build Coastguard Worker for (j = 0; j < HASH_NR; j++) h[j].head = 0;
296*cf5a6c84SAndroid Build Coastguard Worker sigatexit(handle_signal);
297*cf5a6c84SAndroid Build Coastguard Worker signal(SIGCHLD, handle_exit);
298*cf5a6c84SAndroid Build Coastguard Worker
299*cf5a6c84SAndroid Build Coastguard Worker while (1) {
300*cf5a6c84SAndroid Build Coastguard Worker if (TT.count_all < TT.c) {
301*cf5a6c84SAndroid Build Coastguard Worker if (TT.udp) {
302*cf5a6c84SAndroid Build Coastguard Worker if (recvfrom(fd, 0, 0, MSG_PEEK, (void *)buf, &len) < 0)
303*cf5a6c84SAndroid Build Coastguard Worker perror_exit("recvfrom");
304*cf5a6c84SAndroid Build Coastguard Worker newfd = fd;
305*cf5a6c84SAndroid Build Coastguard Worker } else {
306*cf5a6c84SAndroid Build Coastguard Worker newfd = accept(fd, (struct sockaddr *)buf, &len);
307*cf5a6c84SAndroid Build Coastguard Worker if (newfd < 0) perror_exit("Error on accept");
308*cf5a6c84SAndroid Build Coastguard Worker }
309*cf5a6c84SAndroid Build Coastguard Worker } else {
310*cf5a6c84SAndroid Build Coastguard Worker sigset_t ss;
311*cf5a6c84SAndroid Build Coastguard Worker sigemptyset(&ss);
312*cf5a6c84SAndroid Build Coastguard Worker sigsuspend(&ss);
313*cf5a6c84SAndroid Build Coastguard Worker continue;
314*cf5a6c84SAndroid Build Coastguard Worker }
315*cf5a6c84SAndroid Build Coastguard Worker TT.count_all++;
316*cf5a6c84SAndroid Build Coastguard Worker addr = sock_to_address((struct sockaddr*)buf, NI_NUMERICHOST);
317*cf5a6c84SAndroid Build Coastguard Worker
318*cf5a6c84SAndroid Build Coastguard Worker hash = haship(addr);
319*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(C)) {
320*cf5a6c84SAndroid Build Coastguard Worker for (head = h[hash].head; head; head = head->next)
321*cf5a6c84SAndroid Build Coastguard Worker if (!strcmp(head->d, addr)) break;
322*cf5a6c84SAndroid Build Coastguard Worker
323*cf5a6c84SAndroid Build Coastguard Worker if (head && head->count >= TT.maxc) {
324*cf5a6c84SAndroid Build Coastguard Worker if (ptr) write(newfd, ptr, strlen(ptr)); // TODO: this can block
325*cf5a6c84SAndroid Build Coastguard Worker close(newfd);
326*cf5a6c84SAndroid Build Coastguard Worker TT.count_all--;
327*cf5a6c84SAndroid Build Coastguard Worker continue;
328*cf5a6c84SAndroid Build Coastguard Worker }
329*cf5a6c84SAndroid Build Coastguard Worker }
330*cf5a6c84SAndroid Build Coastguard Worker
331*cf5a6c84SAndroid Build Coastguard Worker newnode = (struct list*)xzalloc(sizeof(struct list));
332*cf5a6c84SAndroid Build Coastguard Worker newnode->d = addr;
333*cf5a6c84SAndroid Build Coastguard Worker for (head = h[hash].head; head; head = head->next) {
334*cf5a6c84SAndroid Build Coastguard Worker if (!strcmp(addr, head->d)) {
335*cf5a6c84SAndroid Build Coastguard Worker head->count++;
336*cf5a6c84SAndroid Build Coastguard Worker free(newnode);
337*cf5a6c84SAndroid Build Coastguard Worker break;
338*cf5a6c84SAndroid Build Coastguard Worker }
339*cf5a6c84SAndroid Build Coastguard Worker }
340*cf5a6c84SAndroid Build Coastguard Worker
341*cf5a6c84SAndroid Build Coastguard Worker if (!head) {
342*cf5a6c84SAndroid Build Coastguard Worker newnode->next = h[hash].head;
343*cf5a6c84SAndroid Build Coastguard Worker h[hash].head = newnode;
344*cf5a6c84SAndroid Build Coastguard Worker h[hash].head->count++;
345*cf5a6c84SAndroid Build Coastguard Worker }
346*cf5a6c84SAndroid Build Coastguard Worker
347*cf5a6c84SAndroid Build Coastguard Worker if (!(pid = xfork())) {
348*cf5a6c84SAndroid Build Coastguard Worker char *serv = NULL, *clie = NULL;
349*cf5a6c84SAndroid Build Coastguard Worker char *client = sock_to_address((void *)buf, NI_NUMERICHOST | NI_NUMERICSERV);
350*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(h)) { //lookup name
351*cf5a6c84SAndroid Build Coastguard Worker serv = TT.l ? xstrdup(TT.l) : sock_to_address((void *)&haddr, 0);
352*cf5a6c84SAndroid Build Coastguard Worker clie = sock_to_address((void *)buf, 0);
353*cf5a6c84SAndroid Build Coastguard Worker }
354*cf5a6c84SAndroid Build Coastguard Worker
355*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(E)) {
356*cf5a6c84SAndroid Build Coastguard Worker setenv("PROTO", TT.udp ? "UDP" :"TCP", 1);
357*cf5a6c84SAndroid Build Coastguard Worker setenv("PROTOLOCALADDR", server, 1);
358*cf5a6c84SAndroid Build Coastguard Worker setenv("PROTOREMOTEADDR", client, 1);
359*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(h)) {
360*cf5a6c84SAndroid Build Coastguard Worker setenv("PROTOLOCALHOST", serv, 1);
361*cf5a6c84SAndroid Build Coastguard Worker setenv("PROTOREMOTEHOST", clie, 1);
362*cf5a6c84SAndroid Build Coastguard Worker }
363*cf5a6c84SAndroid Build Coastguard Worker if (!TT.udp) {
364*cf5a6c84SAndroid Build Coastguard Worker char max_c[32];
365*cf5a6c84SAndroid Build Coastguard Worker sprintf(max_c, "%d", TT.maxc);
366*cf5a6c84SAndroid Build Coastguard Worker setenv("TCPCONCURRENCY", max_c, 1); //Not valid for udp
367*cf5a6c84SAndroid Build Coastguard Worker }
368*cf5a6c84SAndroid Build Coastguard Worker }
369*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(v)) {
370*cf5a6c84SAndroid Build Coastguard Worker xprintf("%s: start %d %s-%s",toys.which->name, getpid(), server, client);
371*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(h)) xprintf(" (%s-%s)", serv, clie);
372*cf5a6c84SAndroid Build Coastguard Worker xputc('\n');
373*cf5a6c84SAndroid Build Coastguard Worker if (TT.c > 1)
374*cf5a6c84SAndroid Build Coastguard Worker xprintf("%s: status %d/%ld\n",toys.which->name, TT.count_all, TT.c);
375*cf5a6c84SAndroid Build Coastguard Worker }
376*cf5a6c84SAndroid Build Coastguard Worker free(client);
377*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(h)) {
378*cf5a6c84SAndroid Build Coastguard Worker free(serv);
379*cf5a6c84SAndroid Build Coastguard Worker free(clie);
380*cf5a6c84SAndroid Build Coastguard Worker }
381*cf5a6c84SAndroid Build Coastguard Worker if (TT.udp) xconnect(newfd, (struct sockaddr *)buf, sizeof(buf));
382*cf5a6c84SAndroid Build Coastguard Worker
383*cf5a6c84SAndroid Build Coastguard Worker close(0);
384*cf5a6c84SAndroid Build Coastguard Worker close(1);
385*cf5a6c84SAndroid Build Coastguard Worker dup2(newfd, 0);
386*cf5a6c84SAndroid Build Coastguard Worker dup2(newfd, 1);
387*cf5a6c84SAndroid Build Coastguard Worker xexec(toys.optargs+2); //skip IP PORT
388*cf5a6c84SAndroid Build Coastguard Worker } else {
389*cf5a6c84SAndroid Build Coastguard Worker insert(&pids, pid, addr);
390*cf5a6c84SAndroid Build Coastguard Worker xclose(newfd); //close and reopen for next client.
391*cf5a6c84SAndroid Build Coastguard Worker if (TT.udp) fd = create_bind_sock(toys.optargs[0],
392*cf5a6c84SAndroid Build Coastguard Worker (struct sockaddr*)&haddr);
393*cf5a6c84SAndroid Build Coastguard Worker }
394*cf5a6c84SAndroid Build Coastguard Worker } //while(1)
395*cf5a6c84SAndroid Build Coastguard Worker }
396