Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 246 lines (197 sloc) 5.099 kb
282d900 @nicolasff Removed global variables.
authored
1 #include "server.h"
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
2 #include "worker.h"
7cfb80d @nicolasff Add client.{c,h}. Needs a lot more refactoring.
authored
3 #include "client.h"
282d900 @nicolasff Removed global variables.
authored
4 #include "conf.h"
a9cfcb1 @nicolasff Add version.h and log webdis version on startup (issue #81)
authored
5 #include "version.h"
282d900 @nicolasff Removed global variables.
authored
6
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
7 #include <stdlib.h>
8 #include <stdio.h>
03af442 @nicolasff Drop privileges.
authored
9 #include <unistd.h>
a8bccb4 @nicolasff Refactoring
authored
10 #include <signal.h>
11 #include <string.h>
5385f9c @nicolasff Fixed warnings seen on FreeBSD.
authored
12 #include <netinet/in.h>
0dde1f5 @nicolasff Start changing HTTP parser.
authored
13 #include <arpa/inet.h>
2a84258 @nicolasff Add daemonize support.
authored
14 #include <fcntl.h>
df73255 @nicolasff More logs in server.c (socket creation)
authored
15 #include <errno.h>
0dde1f5 @nicolasff Start changing HTTP parser.
authored
16 #include <sys/types.h>
17 #include <sys/socket.h>
81d18dd @nicolasff Fix issue #24 with slow-reading clients.
authored
18 #include <sys/ioctl.h>
a8bccb4 @nicolasff Refactoring
authored
19
0dde1f5 @nicolasff Start changing HTTP parser.
authored
20 /**
21 * Sets up a non-blocking socket
22 */
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
23 static int
df73255 @nicolasff More logs in server.c (socket creation)
authored
24 socket_setup(struct server *s, const char *ip, short port) {
a8bccb4 @nicolasff Refactoring
authored
25
0dde1f5 @nicolasff Start changing HTTP parser.
authored
26 int reuse = 1;
27 struct sockaddr_in addr;
28 int fd, ret;
a8bccb4 @nicolasff Refactoring
authored
29
6051d8b @nicolasff Fix server.c for OSX
authored
30 memset(&addr, 0, sizeof(addr));
bd8a060 @andrebraga Fix server.c for BSDs, actually.
andrebraga authored
31 #if defined __BSD__
6051d8b @nicolasff Fix server.c for OSX
authored
32 addr.sin_len = sizeof(struct sockaddr_in);
33 #endif
0dde1f5 @nicolasff Start changing HTTP parser.
authored
34 addr.sin_family = AF_INET;
35 addr.sin_port = htons(port);
282d900 @nicolasff Removed global variables.
authored
36
0dde1f5 @nicolasff Start changing HTTP parser.
authored
37 addr.sin_addr.s_addr = inet_addr(ip);
282d900 @nicolasff Removed global variables.
authored
38
0dde1f5 @nicolasff Start changing HTTP parser.
authored
39 /* this sad list of tests could use a Maybe monad... */
282d900 @nicolasff Removed global variables.
authored
40
0dde1f5 @nicolasff Start changing HTTP parser.
authored
41 /* create socket */
42 fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
43 if (-1 == fd) {
df73255 @nicolasff More logs in server.c (socket creation)
authored
44 slog(s, WEBDIS_ERROR, strerror(errno), 0);
0dde1f5 @nicolasff Start changing HTTP parser.
authored
45 return -1;
282d900 @nicolasff Removed global variables.
authored
46 }
47
0dde1f5 @nicolasff Start changing HTTP parser.
authored
48 /* reuse address if we've bound to it before. */
49 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse,
50 sizeof(reuse)) < 0) {
df73255 @nicolasff More logs in server.c (socket creation)
authored
51 slog(s, WEBDIS_ERROR, strerror(errno), 0);
0dde1f5 @nicolasff Start changing HTTP parser.
authored
52 return -1;
282d900 @nicolasff Removed global variables.
authored
53 }
54
0dde1f5 @nicolasff Start changing HTTP parser.
authored
55 /* set socket as non-blocking. */
56 ret = fcntl(fd, F_SETFD, O_NONBLOCK);
57 if (0 != ret) {
df73255 @nicolasff More logs in server.c (socket creation)
authored
58 slog(s, WEBDIS_ERROR, strerror(errno), 0);
0dde1f5 @nicolasff Start changing HTTP parser.
authored
59 return -1;
282d900 @nicolasff Removed global variables.
authored
60 }
61
0dde1f5 @nicolasff Start changing HTTP parser.
authored
62 /* bind */
63 ret = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
64 if (0 != ret) {
df73255 @nicolasff More logs in server.c (socket creation)
authored
65 slog(s, WEBDIS_ERROR, strerror(errno), 0);
0dde1f5 @nicolasff Start changing HTTP parser.
authored
66 return -1;
f4e2893 @nicolasff Added support for Redis AUTH command.
authored
67 }
0dde1f5 @nicolasff Start changing HTTP parser.
authored
68
69 /* listen */
70 ret = listen(fd, SOMAXCONN);
71 if (0 != ret) {
df73255 @nicolasff More logs in server.c (socket creation)
authored
72 slog(s, WEBDIS_ERROR, strerror(errno), 0);
0dde1f5 @nicolasff Start changing HTTP parser.
authored
73 return -1;
0bb096a @nicolasff Add database switch in config file.
authored
74 }
282d900 @nicolasff Removed global variables.
authored
75
0dde1f5 @nicolasff Start changing HTTP parser.
authored
76 /* there you go, ready to accept! */
77 return fd;
282d900 @nicolasff Removed global variables.
authored
78 }
79
2c980a2 @nicolasff First try.
authored
80 struct server *
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
81 server_new(const char *cfg_file) {
82
83 int i;
a8bccb4 @nicolasff Refactoring
authored
84 struct server *s = calloc(1, sizeof(struct server));
b042c70 @nicolasff Added CORS
authored
85
9a2be34 @nicolasff Reopen logs on SIGHUP (GitHub issue #10)
authored
86 s->log.fd = -1;
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
87 s->cfg = conf_read(cfg_file);
b042c70 @nicolasff Added CORS
authored
88
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
89 /* workers */
90 s->w = calloc(s->cfg->http_threads, sizeof(struct worker*));
91 for(i = 0; i < s->cfg->http_threads; ++i) {
92 s->w[i] = worker_new(s);
0bb096a @nicolasff Add database switch in config file.
authored
93 }
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
94 return s;
b042c70 @nicolasff Added CORS
authored
95 }
a8bccb4 @nicolasff Refactoring
authored
96
0dde1f5 @nicolasff Start changing HTTP parser.
authored
97 static void
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
98 server_can_accept(int fd, short event, void *ptr) {
0dde1f5 @nicolasff Start changing HTTP parser.
authored
99
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
100 struct server *s = ptr;
101 struct worker *w;
102 struct http_client *c;
0dde1f5 @nicolasff Start changing HTTP parser.
authored
103 int client_fd;
104 struct sockaddr_in addr;
105 socklen_t addr_sz = sizeof(addr);
81d18dd @nicolasff Fix issue #24 with slow-reading clients.
authored
106 char on = 1;
0dde1f5 @nicolasff Start changing HTTP parser.
authored
107 (void)event;
a8bccb4 @nicolasff Refactoring
authored
108
cd9fd9a @nicolasff Refactoring, commenting.
authored
109 /* select worker to send the client to */
110 w = s->w[s->next_worker];
bec19d0 @nicolasff Merge branch 'slog' of https://github.com/mrb/webdis into slog
authored
111
cd9fd9a @nicolasff Refactoring, commenting.
authored
112 /* accept client */
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
113 client_fd = accept(fd, (struct sockaddr*)&addr, &addr_sz);
a8bccb4 @nicolasff Refactoring
authored
114
81d18dd @nicolasff Fix issue #24 with slow-reading clients.
authored
115 /* make non-blocking */
116 ioctl(client_fd, (int)FIONBIO, (char *)&on);
117
cd9fd9a @nicolasff Refactoring, commenting.
authored
118 /* create client and send to worker. */
704a288 @nicolasff Bugfix.
authored
119 if(client_fd > 0) {
120 c = http_client_new(w, client_fd, addr.sin_addr.s_addr);
121 worker_add_client(w, c);
b042c70 @nicolasff Added CORS
authored
122
704a288 @nicolasff Bugfix.
authored
123 /* loop over ring of workers */
124 s->next_worker = (s->next_worker + 1) % s->cfg->http_threads;
6d7cd41 @nicolasff Log notice for large number of connections.
authored
125 } else { /* too many connections */
126 slog(s, WEBDIS_NOTICE, "Too many connections", 0);
a8bccb4 @nicolasff Refactoring
authored
127 }
128 }
129
0b5f2c9 @nicolasff Restored daemonize.
authored
130 /**
131 * Daemonize server.
132 * (taken from Redis)
133 */
134 static void
b56218c @nicolasff Write pidfile when daemonized (GitHub issue #10)
authored
135 server_daemonize(const char *pidfile) {
2eba190 @nicolasff Fixed daemonize issue
authored
136 int fd;
137
138 if (fork() != 0) exit(0); /* parent exits */
139 setsid(); /* create a new session */
140
141 /* Every output goes to /dev/null. */
142 if ((fd = open("/dev/null", O_RDWR, 0)) != -1) {
143 dup2(fd, STDIN_FILENO);
144 dup2(fd, STDOUT_FILENO);
145 dup2(fd, STDERR_FILENO);
146 if (fd > STDERR_FILENO) close(fd);
147 }
2a84258 @nicolasff Add daemonize support.
authored
148
b56218c @nicolasff Write pidfile when daemonized (GitHub issue #10)
authored
149 /* write pidfile */
150 if (pidfile) {
151 FILE *f = fopen(pidfile, "w");
152 if (f) {
153 fprintf(f, "%d\n", (int)getpid());
154 fclose(f);
155 }
156 }
157 }
a8bccb4 @nicolasff Refactoring
authored
158
e978ff2 @nicolasff Handle SIGTERM & SIGINT (issue #10)
authored
159 /* global pointer to the server object, used in signal handlers */
160 static struct server *__server;
161
162 static void
163 server_handle_signal(int id) {
164
165 switch(id) {
166 case SIGHUP:
167 slog_init(__server);
168 break;
169 case SIGTERM:
170 case SIGINT:
171 slog(__server, WEBDIS_INFO, "Webdis terminating", 0);
172 exit(0);
173 break;
174 default:
175 break;
176 }
177 }
178
179 static void
180 server_install_signal_handlers(struct server *s) {
181 __server = s;
182
183 signal(SIGHUP, server_handle_signal);
184 signal(SIGTERM, server_handle_signal);
185 signal(SIGINT, server_handle_signal);
186 }
187
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
188 int
a8bccb4 @nicolasff Refactoring
authored
189 server_start(struct server *s) {
2a84258 @nicolasff Add daemonize support.
authored
190
8916feb @nicolasff Add error message for failing event_add.
authored
191 int i, ret;
2eba190 @nicolasff Fixed daemonize issue
authored
192
193 /* initialize libevent */
194 s->base = event_base_new();
195
2a84258 @nicolasff Add daemonize support.
authored
196 if(s->cfg->daemonize) {
b56218c @nicolasff Write pidfile when daemonized (GitHub issue #10)
authored
197 server_daemonize(s->cfg->pidfile);
07daf02 @davidk Re-init events after fork when daemonizing.
davidk authored
198
199 /* sometimes event mech gets lost on fork */
200 if(event_reinit(s->base) != 0) {
201 fprintf(stderr, "Error: event_reinit failed after fork");
202 }
2a84258 @nicolasff Add daemonize support.
authored
203 }
204
a8bccb4 @nicolasff Refactoring
authored
205 /* ignore sigpipe */
206 #ifdef SIGPIPE
207 signal(SIGPIPE, SIG_IGN);
208 #endif
209
0e061f6 @nicolasff Fixed log buf, removed spin lock.
authored
210 slog_init(s);
211
e978ff2 @nicolasff Handle SIGTERM & SIGINT (issue #10)
authored
212 /* install signal handlers */
213 server_install_signal_handlers(s);
9a2be34 @nicolasff Reopen logs on SIGHUP (GitHub issue #10)
authored
214
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
215 /* start worker threads */
216 for(i = 0; i < s->cfg->http_threads; ++i) {
217 worker_start(s->w[i]);
218 }
a8bccb4 @nicolasff Refactoring
authored
219
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
220 /* create socket */
df73255 @nicolasff More logs in server.c (socket creation)
authored
221 s->fd = socket_setup(s, s->cfg->http_host, s->cfg->http_port);
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
222 if(s->fd < 0) {
223 return -1;
d140778 @nicolasff Check socket state on startup.
authored
224 }
0de6719 @littlefrog Enable KEEPALIVE socket option to do with half connection.
littlefrog authored
225
226 /*set keepalive socket option to do with half connection*/
227 int keep_alive = 1;
228 setsockopt(s->fd , SOL_SOCKET, SO_KEEPALIVE, (void*)&keep_alive, sizeof(keep_alive));
03af442 @nicolasff Drop privileges.
authored
229
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
230 /* start http server */
231 event_set(&s->ev, s->fd, EV_READ | EV_PERSIST, server_can_accept, s);
232 event_base_set(s->base, &s->ev);
8916feb @nicolasff Add error message for failing event_add.
authored
233 ret = event_add(&s->ev, NULL);
234
235 if(ret < 0) {
236 slog(s, WEBDIS_ERROR, "Error calling event_add on socket", 0);
237 return -1;
238 }
a8bccb4 @nicolasff Refactoring
authored
239
a9cfcb1 @nicolasff Add version.h and log webdis version on startup (issue #81)
authored
240 slog(s, WEBDIS_INFO, "Webdis " WEBDIS_VERSION " up and running", 0);
a8bccb4 @nicolasff Refactoring
authored
241 event_base_dispatch(s->base);
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
242
243 return 0;
a8bccb4 @nicolasff Refactoring
authored
244 }
5b7aa50 @nicolasff Partial rewrite, adding WebSockets, threads, pool.
authored
245
Something went wrong with that request. Please try again.