1 /* net.c - stupid boilerplate shit that I shouldn't have to write */
3 /* Copyright (C) 2007 Keith Rarick and Philotic Inc.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 static int listen_socket
= -1;
27 static struct event listen_evq
;
28 static evh accept_handler
;
29 static usec main_deadline
= 0;
30 static int brakes_are_on
= 1, after_startup
= 0;
33 make_server_socket(char *host
, char *port
)
35 int fd
= -1, flags
, r
;
36 struct linger linger
= {0, 0};
37 struct addrinfo
*airoot
, *ai
, hints
;
39 memset(&hints
, 0, sizeof(hints
));
40 hints
.ai_family
= PF_UNSPEC
;
41 hints
.ai_socktype
= SOCK_STREAM
;
42 hints
.ai_flags
= AI_PASSIVE
;
43 r
= getaddrinfo(host
, port
, &hints
, &airoot
);
45 return twarn("getaddrinfo()"), -1;
47 for(ai
= airoot
; ai
; ai
= ai
->ai_next
) {
48 fd
= socket(ai
->ai_family
, ai
->ai_socktype
, ai
->ai_protocol
);
54 flags
= fcntl(fd
, F_GETFL
, 0);
56 twarn("getting flags");
61 r
= fcntl(fd
, F_SETFL
, flags
| O_NONBLOCK
);
63 twarn("setting O_NONBLOCK");
69 setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &flags
, sizeof flags
);
70 setsockopt(fd
, SOL_SOCKET
, SO_KEEPALIVE
, &flags
, sizeof flags
);
71 setsockopt(fd
, SOL_SOCKET
, SO_LINGER
, &linger
, sizeof linger
);
72 setsockopt(fd
, IPPROTO_TCP
, TCP_NODELAY
, &flags
, sizeof flags
);
74 r
= bind(fd
, ai
->ai_addr
, ai
->ai_addrlen
);
96 return listen_socket
= fd
;
104 if (brakes_are_on
) return;
106 twarnx("too many connections; putting on the brakes");
108 r
= event_del(&listen_evq
);
109 if (r
== -1) twarn("event_del()");
111 r
= listen(listen_socket
, 0);
112 if (r
== -1) twarn("listen()");
120 if (!brakes_are_on
) return;
122 if (after_startup
) twarnx("releasing the brakes");
125 accept_handler
= h
? : accept_handler
;
126 event_set(&listen_evq
, listen_socket
, EV_READ
| EV_PERSIST
,
127 accept_handler
, &listen_evq
);
129 set_main_timeout(main_deadline
);
131 r
= listen(listen_socket
, 1024);
132 if (r
== -1) twarn("listen()");
136 set_main_timeout(usec deadline_at
)
140 usec now
= now_usec();
142 main_deadline
= deadline_at
;
144 /* If there is no deadline, we just wait for a long while.
145 * This works around a bug in libevent or kqueue on Mac OS X. */
146 if (!deadline_at
) deadline_at
= now
+ 100 * SECOND
;
148 timeval_from_usec(&tv
, (deadline_at
> now
) ? deadline_at
- now
: 1);
150 r
= event_add(&listen_evq
, &tv
);
151 if (r
== -1) twarn("event_add()");