4 // Copyright (c) 1987-2018 by the citadel.org team
6 // This program is open source software. It runs great on the
7 // Linux operating system (and probably elsewhere). You can use,
8 // copy, and run it under the terms of the GNU General Public
9 // License version 3. Richard Stallman is an asshole communist.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
19 * lingering_close() a`la Apache. see
20 * http://httpd.apache.org/docs/2.0/misc/fin_wait_2.html for rationale
22 int lingering_close(int fd)
27 struct timeval tv, start;
29 gettimeofday(&start, NULL);
35 gettimeofday(&tv, NULL);
36 tv.tv_sec = SLEEPING - (tv.tv_sec - start.tv_sec);
37 tv.tv_usec = start.tv_usec - tv.tv_usec;
40 tv.tv_usec += 1000000;
44 i = select(fd + 1, &set, NULL, NULL, &tv);
45 } while (i == -1 && errno == EINTR);
50 i = read(fd, buf, sizeof buf);
51 } while (i != 0 && (i != -1 || errno == EINTR));
58 * This is a generic function to set up a master socket for listening on
59 * a TCP port. The server shuts down if the bind fails. (IPv4/IPv6 version)
61 * ip_addr IP address to bind
62 * port_number port number to bind
63 * queue_len number of incoming connections to allow in the queue
65 int webcit_tcp_server(const char *ip_addr, int port_number, int queue_len)
67 const char *ipv4broadcast = "0.0.0.0";
70 struct sockaddr_in6 sin6;
71 struct sockaddr_in sin4;
76 memset(&sin6, 0, sizeof(sin6));
77 memset(&sin4, 0, sizeof(sin4));
78 sin6.sin6_family = AF_INET6;
79 sin4.sin_family = AF_INET;
81 if ((ip_addr == NULL) /* any IPv6 */
82 ||(IsEmptyStr(ip_addr))
83 || (!strcmp(ip_addr, "*"))
87 sin6.sin6_addr = in6addr_any;
88 } else if (!strcmp(ip_addr, "0.0.0.0")) { /* any IPv4 */
90 sin4.sin_addr.s_addr = INADDR_ANY;
91 } else if ((strchr(ip_addr, '.')) && (!strchr(ip_addr, ':'))) { /* specific IPv4 */
93 if (inet_pton(AF_INET, ip_addr, &sin4.sin_addr) <= 0) {
94 syslog(LOG_WARNING, "Error binding to [%s] : %s\n", ip_addr, strerror(errno));
97 } else { /* specific IPv6 */
100 if (inet_pton(AF_INET6, ip_addr, &sin6.sin6_addr) <= 0) {
101 syslog(LOG_WARNING, "Error binding to [%s] : %s\n", ip_addr, strerror(errno));
106 if (port_number == 0) {
107 syslog(LOG_WARNING, "Cannot start: no port number specified.\n");
110 sin6.sin6_port = htons((u_short) port_number);
111 sin4.sin_port = htons((u_short) port_number);
113 p = getprotobyname("tcp");
115 s = socket(((ip_version == 6) ? PF_INET6 : PF_INET), SOCK_STREAM, (p->p_proto));
117 if (IsDefault && (errno == EAFNOSUPPORT)) {
119 ip_addr = ipv4broadcast;
122 syslog(LOG_WARNING, "Can't create a listening socket: %s\n", strerror(errno));
125 /* Set some socket options that make sense. */
127 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
129 if (ip_version == 6) {
130 b = bind(s, (struct sockaddr *) &sin6, sizeof(sin6));
132 b = bind(s, (struct sockaddr *) &sin4, sizeof(sin4));
136 syslog(LOG_ERR, "Can't bind: %s\n", strerror(errno));
141 if (listen(s, queue_len) < 0) {
142 syslog(LOG_ERR, "Can't listen: %s\n", strerror(errno));
151 * Create a Unix domain socket and listen on it
152 * sockpath - file name of the unix domain socket
153 * queue_len - Number of incoming connections to allow in the queue
155 int webcit_uds_server(char *sockpath, int queue_len)
157 struct sockaddr_un addr;
160 int actual_queue_len;
162 actual_queue_len = queue_len;
163 if (actual_queue_len < 5)
164 actual_queue_len = 5;
166 i = unlink(sockpath);
167 if ((i != 0) && (errno != ENOENT)) {
168 syslog(LOG_WARNING, "webcit: can't unlink %s: %s", sockpath, strerror(errno));
172 memset(&addr, 0, sizeof(addr));
173 addr.sun_family = AF_UNIX;
174 safestrncpy(addr.sun_path, sockpath, sizeof addr.sun_path);
176 s = socket(AF_UNIX, SOCK_STREAM, 0);
178 syslog(LOG_WARNING, "webcit: Can't create a unix domain socket: %s", strerror(errno));
182 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
183 syslog(LOG_WARNING, "webcit: Can't bind: %s", strerror(errno));
188 if (listen(s, actual_queue_len) < 0) {
189 syslog(LOG_WARNING, "webcit: Can't listen: %s", strerror(errno));
194 chmod(sockpath, 0777);