Make sure fd is always initialized.
[beanstalkd.git] / net.c
blobd2d814c1f4ff78d3ef71a22d38352f9da425a77a
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/>.
19 #include <stdio.h>
20 #include <string.h>
21 #include <errno.h>
23 #include "net.h"
24 #include "util.h"
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;
32 int
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);
44 if (r == -1)
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);
49 if (fd == -1) {
50 twarn("socket()");
51 continue;
54 flags = fcntl(fd, F_GETFL, 0);
55 if (flags < 0) {
56 twarn("getting flags");
57 close(fd);
58 continue;
61 r = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
62 if (r == -1) {
63 twarn("setting O_NONBLOCK");
64 close(fd);
65 continue;
68 flags = 1;
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);
75 if (r == -1) {
76 twarn("bind()");
77 close(fd);
78 continue;
81 r = listen(fd, 1024);
82 if (r == -1) {
83 twarn("listen()");
84 close(fd);
85 continue;
88 break;
91 freeaddrinfo(airoot);
93 if(ai == NULL)
94 fd = -1;
96 return listen_socket = fd;
99 void
100 brake()
102 int r;
104 if (brakes_are_on) return;
105 brakes_are_on = 1;
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()");
115 void
116 unbrake(evh h)
118 int r;
120 if (!brakes_are_on) return;
121 brakes_are_on = 0;
122 if (after_startup) twarnx("releasing the brakes");
123 after_startup = 1;
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()");
135 void
136 set_main_timeout(usec deadline_at)
138 int r;
139 struct timeval tv;
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()");