3 // Copyright (c) 1987-2024 by the citadel.org team
5 // This program is open source software. Use, duplication, or disclosure is subject to the GNU General Public License v3.
9 // lingering_close() a`la Apache. see
10 // http://httpd.apache.org/docs/2.0/misc/fin_wait_2.html for rationale
11 int lingering_close(int fd) {
15 struct timeval tv, start;
17 gettimeofday(&start, NULL);
23 gettimeofday(&tv, NULL);
24 tv.tv_sec = SLEEPING - (tv.tv_sec - start.tv_sec);
25 tv.tv_usec = start.tv_usec - tv.tv_usec;
28 tv.tv_usec += 1000000;
32 i = select(fd + 1, &set, NULL, NULL, &tv);
33 } while (i == -1 && errno == EINTR);
38 i = read(fd, buf, sizeof buf);
39 } while (i != 0 && (i != -1 || errno == EINTR));
45 // This is a generic function to set up a master socket for listening on
46 // a TCP port. The server shuts down if the bind fails. (IPv4/IPv6 version)
48 // ip_addr IP address to bind
49 // port_number port number to bind
50 // queue_len number of incoming connections to allow in the queue
51 int webcit_tcp_server(const char *ip_addr, int port_number, int queue_len) {
52 const char *ipv4broadcast = "0.0.0.0";
55 struct sockaddr_in6 sin6;
56 struct sockaddr_in sin4;
61 memset(&sin6, 0, sizeof(sin6));
62 memset(&sin4, 0, sizeof(sin4));
63 sin6.sin6_family = AF_INET6;
64 sin4.sin_family = AF_INET;
66 if ( (ip_addr == NULL) // any IPv6
67 || (IsEmptyStr(ip_addr))
68 || (!strcmp(ip_addr, "*"))
72 sin6.sin6_addr = in6addr_any;
74 else if (!strcmp(ip_addr, "0.0.0.0")) { // any IPv4
76 sin4.sin_addr.s_addr = INADDR_ANY;
78 else if ((strchr(ip_addr, '.')) && (!strchr(ip_addr, ':'))) { // specific IPv4
80 if (inet_pton(AF_INET, ip_addr, &sin4.sin_addr) <= 0) {
81 syslog(LOG_WARNING, "tcp_sockets: error binding to [%s] : %m", ip_addr);
85 else { // specific IPv6
88 if (inet_pton(AF_INET6, ip_addr, &sin6.sin6_addr) <= 0) {
89 syslog(LOG_WARNING, "tcp_sockets: error binding to [%s] : %m", ip_addr);
94 if (port_number == 0) {
95 syslog(LOG_WARNING, "tcp_sockets: cannot start: no port number specified");
98 sin6.sin6_port = htons((u_short) port_number);
99 sin4.sin_port = htons((u_short) port_number);
101 p = getprotobyname("tcp");
103 s = socket(((ip_version == 6) ? PF_INET6 : PF_INET), SOCK_STREAM, (p->p_proto));
105 if (IsDefault && (errno == EAFNOSUPPORT)) {
107 ip_addr = ipv4broadcast;
110 syslog(LOG_WARNING, "tcp_sockets: can't create a listening socket: %m");
114 // Set some socket options that make sense.
116 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
118 if (ip_version == 6) {
119 b = bind(s, (struct sockaddr *) &sin6, sizeof(sin6));
122 b = bind(s, (struct sockaddr *) &sin4, sizeof(sin4));
126 syslog(LOG_ERR, "tcp_sockets: can't bind: %m");
131 if (listen(s, queue_len) < 0) {
132 syslog(LOG_ERR, "tcp_sockets: can't listen: %m");
140 // Create a Unix domain socket and listen on it
141 // sockpath - file name of the unix domain socket
142 // queue_len - Number of incoming connections to allow in the queue
143 int webcit_uds_server(char *sockpath, int queue_len) {
144 struct sockaddr_un addr;
147 int actual_queue_len;
149 actual_queue_len = queue_len;
150 if (actual_queue_len < 5)
151 actual_queue_len = 5;
153 i = unlink(sockpath);
154 if ((i != 0) && (errno != ENOENT)) {
155 syslog(LOG_WARNING, "tcp_sockets: can't unlink %s: %m", sockpath);
159 memset(&addr, 0, sizeof(addr));
160 addr.sun_family = AF_UNIX;
161 safestrncpy(addr.sun_path, sockpath, sizeof addr.sun_path);
163 s = socket(AF_UNIX, SOCK_STREAM, 0);
165 syslog(LOG_WARNING, "tcp_sockets: can't create a unix domain socket: %m");
169 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
170 syslog(LOG_WARNING, "tcp_sockets: Can't bind: %m");
175 if (listen(s, actual_queue_len) < 0) {
176 syslog(LOG_WARNING, "tcp_sockets: Can't listen: %m");
181 chmod(sockpath, 0777);