14 #include <minix/config.h>
15 #include <minix/paths.h>
16 #include <sys/ioctl.h>
19 #include <net/netlib.h>
20 #include <net/gen/in.h>
21 #include <net/gen/inet.h>
23 #include <net/gen/tcp.h>
24 #include <net/gen/tcp_io.h>
26 /* This program can be compiled to be paranoid, i.e. check incoming connection
27 * according to an access file, or to trust anyone. The much smaller "trust
28 * 'em" binary will call the paranoid version if the access file exists.
31 static char *arg0
, *service
;
32 static unsigned nchildren
;
34 static void report(const char *label
)
38 fprintf(stderr
, "%s %s: %s: %s\n", arg0
, service
, label
, strerror(err
));
42 static void sigchld(int sig
)
44 while (waitpid(0, NULL
, WNOHANG
) > 0) {
45 if (nchildren
> 0) nchildren
--;
49 static void release(int *fd
)
57 static void usage(void)
60 "Usage: %s [-d] [-m maxclients] service program [arg ...]\n",
65 int main(int argc
, char **argv
)
69 struct nwio_tcpcl tcplistenopt
;
70 struct nwio_tcpconf tcpconf
;
71 struct nwio_tcpopt tcpopt
;
73 struct servent
*servent
;
74 int tcp_fd
, client_fd
, r
;
78 sigset_t chldmask
, chldunmask
, oldmask
;
83 # define max_children ((unsigned) -1)
86 /* Switch to the paranoid version of me if there are flags, or if
87 * there is an access file.
89 if (argv
[1][0] == '-' || access(_PATH_SERVACCES
, F_OK
) == 0) {
90 execv("/usr/bin/tcpdp", argv
);
94 if (argc
< 3) usage();
100 unsigned max_children
;
106 while (i
< argc
&& argv
[i
][0] == '-') {
107 char *opt
= argv
[i
++] + 1;
111 if (*opt
== '-' && opt
[1] == 0) break; /* -- */
113 while (*opt
!= 0) switch (*opt
++) {
119 if (i
== argc
) usage();
122 m
= strtoul(opt
, &end
, 10);
123 if (m
<= 0 || m
> UINT_MAX
|| *end
!= 0) usage();
133 if (i
>= argc
) usage();
136 /* The interface to start the service on. */
137 if ((tcp_device
= getenv("TCP_DEVICE")) == NULL
) tcp_device
= TCP_DEVICE
;
139 /* Let SIGCHLD interrupt whatever I'm doing. */
140 sigemptyset(&chldmask
);
141 sigaddset(&chldmask
, SIGCHLD
);
142 sigprocmask(SIG_BLOCK
, &chldmask
, &oldmask
);
144 sigdelset(&chldunmask
, SIGCHLD
);
145 sigemptyset(&sa
.sa_mask
);
147 sa
.sa_handler
= sigchld
;
148 sigaction(SIGCHLD
, &sa
, NULL
);
150 /* Open a socket to the service I'm to serve. */
151 if ((servent
= getservbyname(service
, "tcp")) == NULL
) {
155 p
= strtoul(service
, &end
, 0);
156 if (p
<= 0 || p
> 0xFFFF || *end
!= 0) {
157 fprintf(stderr
, "%s: %s: Unknown service\n",
161 port
= htons((tcpport_t
) p
);
163 port
= servent
->s_port
;
167 fprintf(stderr
, "%s %s: listening to port %u\n",
168 arg0
, service
, ntohs(port
));
176 if ((tcp_fd
= open(tcp_device
, O_RDWR
)) < 0) {
179 if (errno
== ENOENT
|| errno
== ENODEV
188 fprintf(stderr
, "%s %s: %s: Ok\n",
189 arg0
, service
, tcp_device
);
192 tcpconf
.nwtc_flags
= NWTC_LP_SET
| NWTC_UNSET_RA
| NWTC_UNSET_RP
;
193 tcpconf
.nwtc_locport
= port
;
195 if (ioctl(tcp_fd
, NWIOSTCPCONF
, &tcpconf
) < 0) {
196 report("Can't configure TCP channel");
200 tcpopt
.nwto_flags
= NWTO_DEL_RST
;
202 if (ioctl(tcp_fd
, NWIOSTCPOPT
, &tcpopt
) < 0) {
203 report("Can't set TCP options");
207 if (client_fd
!= -1) {
208 /* We have a client, so start a server for it. */
210 tcpopt
.nwto_flags
= 0;
211 (void) ioctl(client_fd
, NWIOSTCPOPT
, &tcpopt
);
215 /* Create a pipe to serve as an error indicator. */
220 (void) fcntl(pfd
[1], F_SETFD
,
221 fcntl(pfd
[1], F_GETFD
) | FD_CLOEXEC
);
234 /* Check if access to this service allowed. */
235 if (ioctl(client_fd
, NWIOGTCPCONF
, &tcpconf
) == 0
236 && tcpconf
.nwtc_remaddr
!= tcpconf
.nwtc_locaddr
237 && !servxcheck(tcpconf
.nwtc_remaddr
, service
, NULL
)
242 sigprocmask(SIG_SETMASK
, &oldmask
, NULL
);
246 execvp(progv
[0], progv
);
248 write(pfd
[1], &errno
, sizeof(errno
));
254 r
= read(pfd
[0], &errno
, sizeof(errno
));
256 if (r
!= 0) goto bad
;
261 while (nchildren
>= max_children
) {
262 /* Too many clients, wait for one to die off. */
263 sigsuspend(&chldunmask
);
266 /* Wait for a new connection. */
267 sigprocmask(SIG_UNBLOCK
, &chldmask
, NULL
);
269 tcplistenopt
.nwtcl_flags
= 0;
270 while (ioctl(tcp_fd
, NWIOTCPLISTEN
, &tcplistenopt
) < 0) {
271 if (errno
!= EINTR
) {
272 if (errno
!= EAGAIN
|| debug
) {
273 report("Unable to listen");
278 sigprocmask(SIG_BLOCK
, &chldmask
, NULL
);
280 /* We got a connection. */
284 if (debug
&& ioctl(client_fd
, NWIOGTCPCONF
, &tcpconf
) == 0) {
285 fprintf(stderr
, "%s %s: Connection from %s:%u\n",
287 inet_ntoa(tcpconf
.nwtc_remaddr
),
288 ntohs(tcpconf
.nwtc_remport
));
290 /* All is well, no need to stall. */
295 /* All is not well, release resources. */
299 /* Wait a bit if this happens more than once. */
302 fprintf(stderr
, "%s %s: stalling %u second%s\n",
304 stall
, stall
== 1 ? "" : "s");