1 /* -*- c-basic-offset: 8; -*-
3 * Copyright (c) 1993 W. Richard Stevens. All rights reserved.
4 * Permission to use or modify this software and its documentation only for
5 * educational purposes and without fee is hereby granted, provided that
6 * the above copyright notice appear in all copies. The author makes no
7 * representations about the suitability of this software for any purpose.
8 * It is provided "as is" without express or implied warranty.
14 #include <sys/types.h>
15 #include <netinet/in.h>
16 #include <arpa/inet.h>
20 servopen(char *host
, char *port
)
22 int fd
, newfd
, i
, on
, pid
;
24 struct in_addr inaddr
;
27 protocol
= udp
? "udp" : "tcp";
29 /* Initialize the socket address structure */
30 bzero(&servaddr
, sizeof(servaddr
));
31 servaddr
.sin_family
= AF_INET
;
33 /* Caller normally wildcards the local Internet address, meaning
34 a connection will be accepted on any connected interface.
35 We only allow an IP address for the "host", not a name. */
37 servaddr
.sin_addr
.s_addr
= htonl(INADDR_ANY
); /* wildcard */
39 if (inet_aton(host
, &inaddr
) == 0)
40 err_quit("invalid host name for server: %s", host
);
41 servaddr
.sin_addr
= inaddr
;
44 /* See if "port" is a service name or number */
45 if ( (i
= atoi(port
)) == 0) {
46 if ( (sp
= getservbyname(port
, protocol
)) == NULL
)
47 err_ret("getservbyname() error for: %s/%s", port
, protocol
);
49 servaddr
.sin_port
= sp
->s_port
;
51 servaddr
.sin_port
= htons(i
);
53 if ( (fd
= socket(AF_INET
, udp
? SOCK_DGRAM
: SOCK_STREAM
, 0)) < 0)
54 err_sys("socket() error");
58 if (setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &on
, sizeof(on
)) < 0)
59 err_sys("setsockopt of SO_REUSEADDR error");
65 if (setsockopt(fd
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
)) < 0)
66 err_sys("setsockopt of SO_REUSEPORT error");
70 /* Bind our well-known port so the client can connect to us. */
71 if (bind(fd
, (struct sockaddr
*) &servaddr
, sizeof(servaddr
)) < 0)
72 err_sys("can't bind local address");
74 join_mcast(fd
, &servaddr
);
79 if (foreignip
[0] != 0) { /* connect to foreignip/port# */
80 bzero(&cliaddr
, sizeof(cliaddr
));
81 if (inet_aton(foreignip
, &cliaddr
.sin_addr
) == 0)
82 err_quit("invalid IP address: %s", foreignip
);
83 cliaddr
.sin_family
= AF_INET
;
84 cliaddr
.sin_port
= htons(foreignport
);
85 /* connect() for datagram socket doesn't appear to allow
86 wildcarding of either IP address or port number */
88 if (connect(fd
, (struct sockaddr
*) &cliaddr
, sizeof(cliaddr
))
90 err_sys("connect() error");
96 return(fd
); /* nothing else to do */
99 buffers(fd
); /* may set receive buffer size; must do here to get
100 correct window advertised on SYN */
101 sockopts(fd
, 0); /* only set some socket options for fd */
106 sleep_us(pauselisten
*1000); /* lets connection queue build up */
109 TELL_WAIT(); /* initialize synchronization primitives */
113 if ( (newfd
= accept(fd
, (struct sockaddr
*) &cliaddr
, &i
)) < 0)
114 err_sys("accept() error");
117 if ( (pid
= fork()) < 0)
118 err_sys("fork error");
121 close(newfd
); /* parent closes connected socket */
122 WAIT_CHILD(); /* wait for child to output to terminal */
123 continue; /* and back to for(;;) for another accept() */
125 close(fd
); /* child closes listening socket */
129 /* child (or iterative server) continues here */
131 /* Call getsockname() to find local address bound to socket:
132 local internet address is now determined (if multihomed). */
133 i
= sizeof(servaddr
);
134 if (getsockname(newfd
, (struct sockaddr
*) &servaddr
, &i
) < 0)
135 err_sys("getsockname() error");
137 /* Can't do one fprintf() since inet_ntoa() stores
138 the result in a static location. */
139 fprintf(stderr
, "connection on %s.%d ",
140 INET_NTOA(servaddr
.sin_addr
), ntohs(servaddr
.sin_port
));
141 fprintf(stderr
, "from %s.%d\n",
142 INET_NTOA(cliaddr
.sin_addr
), ntohs(cliaddr
.sin_port
));
145 buffers(newfd
); /* setsockopt() again, in case it didn't propagate
146 from listening socket to connected socket */
147 sockopts(newfd
, 1); /* can set all socket options for this socket */
150 TELL_PARENT(getppid()); /* tell parent we're done with terminal */