14 #include <minix/config.h>
15 #include <sys/ioctl.h>
18 #include <net/netlib.h>
19 #include <net/gen/in.h>
20 #include <net/gen/inet.h>
21 #include <net/gen/netdb.h>
22 #include <net/gen/tcp.h>
23 #include <net/gen/tcp_io.h>
25 /* This program can be compiled to be paranoid, i.e. check incoming connection
26 * according to an access file, or to trust anyone. The much smaller "trust
27 * 'em" binary will call the paranoid version if the access file exists.
30 static char *arg0
, *service
;
31 static unsigned nchildren
;
33 static void report(const char *label
)
37 fprintf(stderr
, "%s %s: %s: %s\n", arg0
, service
, label
, strerror(err
));
41 static void sigchld(int sig
)
43 while (waitpid(0, NULL
, WNOHANG
) > 0) {
44 if (nchildren
> 0) nchildren
--;
48 static void release(int *fd
)
56 static void usage(void)
59 "Usage: %s [-d] [-m maxclients] service program [arg ...]\n",
64 int main(int argc
, char **argv
)
68 struct nwio_tcpcl tcplistenopt
;
69 struct nwio_tcpconf tcpconf
;
70 struct nwio_tcpopt tcpopt
;
72 struct servent
*servent
;
73 int tcp_fd
, client_fd
, r
;
77 sigset_t chldmask
, chldunmask
, oldmask
;
82 # define max_children ((unsigned) -1)
85 /* Switch to the paranoid version of me if there are flags, or if
86 * there is an access file.
88 if (argv
[1][0] == '-' || access(_PATH_SERVACCES
, F_OK
) == 0) {
89 execv("/usr/bin/tcpdp", argv
);
93 if (argc
< 3) usage();
99 unsigned max_children
;
105 while (i
< argc
&& argv
[i
][0] == '-') {
106 char *opt
= argv
[i
++] + 1;
110 if (*opt
== '-' && opt
[1] == 0) break; /* -- */
112 while (*opt
!= 0) switch (*opt
++) {
118 if (i
== argc
) usage();
121 m
= strtoul(opt
, &end
, 10);
122 if (m
<= 0 || m
> UINT_MAX
|| *end
!= 0) usage();
132 if (i
>= argc
) usage();
135 /* The interface to start the service on. */
136 if ((tcp_device
= getenv("TCP_DEVICE")) == NULL
) tcp_device
= TCP_DEVICE
;
138 /* Let SIGCHLD interrupt whatever I'm doing. */
139 sigemptyset(&chldmask
);
140 sigaddset(&chldmask
, SIGCHLD
);
141 sigprocmask(SIG_BLOCK
, &chldmask
, &oldmask
);
143 sigdelset(&chldunmask
, SIGCHLD
);
144 sigemptyset(&sa
.sa_mask
);
146 sa
.sa_handler
= sigchld
;
147 sigaction(SIGCHLD
, &sa
, NULL
);
149 /* Open a socket to the service I'm to serve. */
150 if ((servent
= getservbyname(service
, "tcp")) == NULL
) {
154 p
= strtoul(service
, &end
, 0);
155 if (p
<= 0 || p
> 0xFFFF || *end
!= 0) {
156 fprintf(stderr
, "%s: %s: Unknown service\n",
160 port
= htons((tcpport_t
) p
);
162 port
= servent
->s_port
;
166 fprintf(stderr
, "%s %s: listening to port %u\n",
167 arg0
, service
, ntohs(port
));
175 if ((tcp_fd
= open(tcp_device
, O_RDWR
)) < 0) {
178 if (errno
== ENOENT
|| errno
== ENODEV
187 fprintf(stderr
, "%s %s: %s: Ok\n",
188 arg0
, service
, tcp_device
);
191 tcpconf
.nwtc_flags
= NWTC_LP_SET
| NWTC_UNSET_RA
| NWTC_UNSET_RP
;
192 tcpconf
.nwtc_locport
= port
;
194 if (ioctl(tcp_fd
, NWIOSTCPCONF
, &tcpconf
) < 0) {
195 report("Can't configure TCP channel");
199 tcpopt
.nwto_flags
= NWTO_DEL_RST
;
201 if (ioctl(tcp_fd
, NWIOSTCPOPT
, &tcpopt
) < 0) {
202 report("Can't set TCP options");
206 if (client_fd
!= -1) {
207 /* We have a client, so start a server for it. */
209 tcpopt
.nwto_flags
= 0;
210 (void) ioctl(client_fd
, NWIOSTCPOPT
, &tcpopt
);
214 /* Create a pipe to serve as an error indicator. */
219 (void) fcntl(pfd
[1], F_SETFD
,
220 fcntl(pfd
[1], F_GETFD
) | FD_CLOEXEC
);
233 /* Check if access to this service allowed. */
234 if (ioctl(client_fd
, NWIOGTCPCONF
, &tcpconf
) == 0
235 && tcpconf
.nwtc_remaddr
!= tcpconf
.nwtc_locaddr
236 && !servxcheck(tcpconf
.nwtc_remaddr
, service
, NULL
)
241 sigprocmask(SIG_SETMASK
, &oldmask
, NULL
);
245 execvp(progv
[0], progv
);
247 write(pfd
[1], &errno
, sizeof(errno
));
253 r
= read(pfd
[0], &errno
, sizeof(errno
));
255 if (r
!= 0) goto bad
;
260 while (nchildren
>= max_children
) {
261 /* Too many clients, wait for one to die off. */
262 sigsuspend(&chldunmask
);
265 /* Wait for a new connection. */
266 sigprocmask(SIG_UNBLOCK
, &chldmask
, NULL
);
268 tcplistenopt
.nwtcl_flags
= 0;
269 while (ioctl(tcp_fd
, NWIOTCPLISTEN
, &tcplistenopt
) < 0) {
270 if (errno
!= EINTR
) {
271 if (errno
!= EAGAIN
|| debug
) {
272 report("Unable to listen");
277 sigprocmask(SIG_BLOCK
, &chldmask
, NULL
);
279 /* We got a connection. */
283 if (debug
&& ioctl(client_fd
, NWIOGTCPCONF
, &tcpconf
) == 0) {
284 fprintf(stderr
, "%s %s: Connection from %s:%u\n",
286 inet_ntoa(tcpconf
.nwtc_remaddr
),
287 ntohs(tcpconf
.nwtc_remport
));
289 /* All is well, no need to stall. */
294 /* All is not well, release resources. */
298 /* Wait a bit if this happens more than once. */
301 fprintf(stderr
, "%s %s: stalling %u second%s\n",
303 stall
, stall
== 1 ? "" : "s");