1*3ae9e016SAsim Jamshed #define _LARGEFILE64_SOURCE
2*3ae9e016SAsim Jamshed #include <stdio.h>
3*3ae9e016SAsim Jamshed #include <stdlib.h>
4*3ae9e016SAsim Jamshed #include <unistd.h>
5*3ae9e016SAsim Jamshed #include <stdint.h>
6*3ae9e016SAsim Jamshed #include <sys/types.h>
7*3ae9e016SAsim Jamshed #include <sys/stat.h>
8*3ae9e016SAsim Jamshed #include <sys/socket.h>
9*3ae9e016SAsim Jamshed #include <netinet/in.h>
10*3ae9e016SAsim Jamshed #include <arpa/inet.h>
11*3ae9e016SAsim Jamshed #include <fcntl.h>
12*3ae9e016SAsim Jamshed #include <dirent.h>
13*3ae9e016SAsim Jamshed #include <string.h>
14*3ae9e016SAsim Jamshed #include <time.h>
15*3ae9e016SAsim Jamshed #include <pthread.h>
16*3ae9e016SAsim Jamshed #include <signal.h>
17*3ae9e016SAsim Jamshed
18*3ae9e016SAsim Jamshed #include <mos_api.h>
19*3ae9e016SAsim Jamshed #include "cpu.h"
20*3ae9e016SAsim Jamshed #include "http_parsing.h"
21*3ae9e016SAsim Jamshed #include "debug.h"
22*3ae9e016SAsim Jamshed #include "applib.h"
23*3ae9e016SAsim Jamshed
24*3ae9e016SAsim Jamshed #define CONFIG_FILE "config/epserver.conf"
25*3ae9e016SAsim Jamshed static struct conf_var g_conf[] = {
26*3ae9e016SAsim Jamshed { "core_limit", {0} },
27*3ae9e016SAsim Jamshed { "www_main", {0} },
28*3ae9e016SAsim Jamshed };
29*3ae9e016SAsim Jamshed #define NUM_CONF_VAR (sizeof(g_conf) / sizeof(struct conf_var))
30*3ae9e016SAsim Jamshed
31*3ae9e016SAsim Jamshed #define HTTP_HEADER_LEN 1024
32*3ae9e016SAsim Jamshed #define URL_LEN 128
33*3ae9e016SAsim Jamshed
34*3ae9e016SAsim Jamshed /* shinae 10.27.2014
35*3ae9e016SAsim Jamshed * SNDBUF_SIZE should be removed
36*3ae9e016SAsim Jamshed */
37*3ae9e016SAsim Jamshed #define SNDBUF_SIZE (8*1024)
38*3ae9e016SAsim Jamshed
39*3ae9e016SAsim Jamshed #define MAX_FILES 100
40*3ae9e016SAsim Jamshed int cores[MAX_CPUS] = {0};
41*3ae9e016SAsim Jamshed /*----------------------------------------------------------------------------*/
42*3ae9e016SAsim Jamshed struct mtcp_conf g_mcfg;
43*3ae9e016SAsim Jamshed /*----------------------------------------------------------------------------*/
44*3ae9e016SAsim Jamshed struct file_cache
45*3ae9e016SAsim Jamshed {
46*3ae9e016SAsim Jamshed char name[128];
47*3ae9e016SAsim Jamshed char fullname[256];
48*3ae9e016SAsim Jamshed uint64_t size;
49*3ae9e016SAsim Jamshed char *file;
50*3ae9e016SAsim Jamshed };
51*3ae9e016SAsim Jamshed /*----------------------------------------------------------------------------*/
52*3ae9e016SAsim Jamshed struct server_vars
53*3ae9e016SAsim Jamshed {
54*3ae9e016SAsim Jamshed char request[HTTP_HEADER_LEN];
55*3ae9e016SAsim Jamshed int recv_len;
56*3ae9e016SAsim Jamshed int request_len;
57*3ae9e016SAsim Jamshed long int total_read, total_sent;
58*3ae9e016SAsim Jamshed uint8_t done;
59*3ae9e016SAsim Jamshed uint8_t rspheader_sent;
60*3ae9e016SAsim Jamshed uint8_t keep_alive;
61*3ae9e016SAsim Jamshed
62*3ae9e016SAsim Jamshed int fidx; // file cache index
63*3ae9e016SAsim Jamshed char fname[128]; // file name
64*3ae9e016SAsim Jamshed long int fsize; // file size
65*3ae9e016SAsim Jamshed };
66*3ae9e016SAsim Jamshed /*----------------------------------------------------------------------------*/
67*3ae9e016SAsim Jamshed struct thread_context
68*3ae9e016SAsim Jamshed {
69*3ae9e016SAsim Jamshed mctx_t mctx;
70*3ae9e016SAsim Jamshed int listener;
71*3ae9e016SAsim Jamshed int ep;
72*3ae9e016SAsim Jamshed struct server_vars *svars;
73*3ae9e016SAsim Jamshed };
74*3ae9e016SAsim Jamshed /*----------------------------------------------------------------------------*/
75*3ae9e016SAsim Jamshed static int num_cores;
76*3ae9e016SAsim Jamshed static int core_limit;
77*3ae9e016SAsim Jamshed /*----------------------------------------------------------------------------*/
78*3ae9e016SAsim Jamshed char *www_main;
79*3ae9e016SAsim Jamshed static struct file_cache fcache[MAX_FILES];
80*3ae9e016SAsim Jamshed static int nfiles;
81*3ae9e016SAsim Jamshed /*----------------------------------------------------------------------------*/
82*3ae9e016SAsim Jamshed static int finished;
83*3ae9e016SAsim Jamshed /*----------------------------------------------------------------------------*/
84*3ae9e016SAsim Jamshed static char *
StatusCodeToString(int scode)85*3ae9e016SAsim Jamshed StatusCodeToString(int scode)
86*3ae9e016SAsim Jamshed {
87*3ae9e016SAsim Jamshed switch (scode) {
88*3ae9e016SAsim Jamshed case 200:
89*3ae9e016SAsim Jamshed return "OK";
90*3ae9e016SAsim Jamshed break;
91*3ae9e016SAsim Jamshed
92*3ae9e016SAsim Jamshed case 404:
93*3ae9e016SAsim Jamshed return "Not Found";
94*3ae9e016SAsim Jamshed break;
95*3ae9e016SAsim Jamshed }
96*3ae9e016SAsim Jamshed
97*3ae9e016SAsim Jamshed return NULL;
98*3ae9e016SAsim Jamshed }
99*3ae9e016SAsim Jamshed /*----------------------------------------------------------------------------*/
100*3ae9e016SAsim Jamshed static void
CleanServerVariable(struct server_vars * sv)101*3ae9e016SAsim Jamshed CleanServerVariable(struct server_vars *sv)
102*3ae9e016SAsim Jamshed {
103*3ae9e016SAsim Jamshed sv->recv_len = 0;
104*3ae9e016SAsim Jamshed sv->request_len = 0;
105*3ae9e016SAsim Jamshed sv->total_read = 0;
106*3ae9e016SAsim Jamshed sv->total_sent = 0;
107*3ae9e016SAsim Jamshed sv->done = 0;
108*3ae9e016SAsim Jamshed sv->rspheader_sent = 0;
109*3ae9e016SAsim Jamshed sv->keep_alive = 0;
110*3ae9e016SAsim Jamshed }
111*3ae9e016SAsim Jamshed /*----------------------------------------------------------------------------*/
112*3ae9e016SAsim Jamshed static void
CloseConnection(struct thread_context * ctx,int sockid,struct server_vars * sv)113*3ae9e016SAsim Jamshed CloseConnection(struct thread_context *ctx, int sockid, struct server_vars *sv)
114*3ae9e016SAsim Jamshed {
115*3ae9e016SAsim Jamshed mtcp_epoll_ctl(ctx->mctx, ctx->ep, MOS_EPOLL_CTL_DEL, sockid, NULL);
116*3ae9e016SAsim Jamshed mtcp_close(ctx->mctx, sockid);
117*3ae9e016SAsim Jamshed }
118*3ae9e016SAsim Jamshed /*----------------------------------------------------------------------------*/
119*3ae9e016SAsim Jamshed static int
SendUntilAvailable(struct thread_context * ctx,int sockid,struct server_vars * sv)120*3ae9e016SAsim Jamshed SendUntilAvailable(struct thread_context *ctx, int sockid, struct server_vars *sv)
121*3ae9e016SAsim Jamshed {
122*3ae9e016SAsim Jamshed int ret;
123*3ae9e016SAsim Jamshed int sent;
124*3ae9e016SAsim Jamshed int len;
125*3ae9e016SAsim Jamshed
126*3ae9e016SAsim Jamshed if (sv->done || !sv->rspheader_sent) {
127*3ae9e016SAsim Jamshed return 0;
128*3ae9e016SAsim Jamshed }
129*3ae9e016SAsim Jamshed
130*3ae9e016SAsim Jamshed sent = 0;
131*3ae9e016SAsim Jamshed ret = 1;
132*3ae9e016SAsim Jamshed while (ret > 0) {
133*3ae9e016SAsim Jamshed len = MIN(SNDBUF_SIZE, sv->fsize - sv->total_sent);
134*3ae9e016SAsim Jamshed if (len <= 0) {
135*3ae9e016SAsim Jamshed break;
136*3ae9e016SAsim Jamshed }
137*3ae9e016SAsim Jamshed ret = mtcp_write(ctx->mctx, sockid,
138*3ae9e016SAsim Jamshed fcache[sv->fidx].file + sv->total_sent, len);
139*3ae9e016SAsim Jamshed if (ret < 0) {
140*3ae9e016SAsim Jamshed if (errno != EAGAIN) {
141*3ae9e016SAsim Jamshed TRACE_ERROR("Socket %d: Sending HTTP response body failed. "
142*3ae9e016SAsim Jamshed "try: %d, sent: %d\n", sockid, len, ret);
143*3ae9e016SAsim Jamshed }
144*3ae9e016SAsim Jamshed break;
145*3ae9e016SAsim Jamshed }
146*3ae9e016SAsim Jamshed TRACE_APP("Socket %d: mtcp_write try: %d, ret: %d\n", sockid, len, ret);
147*3ae9e016SAsim Jamshed sent += ret;
148*3ae9e016SAsim Jamshed sv->total_sent += ret;
149*3ae9e016SAsim Jamshed }
150*3ae9e016SAsim Jamshed
151*3ae9e016SAsim Jamshed if (sv->total_sent >= fcache[sv->fidx].size) {
152*3ae9e016SAsim Jamshed struct mtcp_epoll_event ev;
153*3ae9e016SAsim Jamshed sv->done = TRUE;
154*3ae9e016SAsim Jamshed finished++;
155*3ae9e016SAsim Jamshed
156*3ae9e016SAsim Jamshed if (sv->keep_alive) {
157*3ae9e016SAsim Jamshed /* if keep-alive connection, wait for the incoming request */
158*3ae9e016SAsim Jamshed ev.events = MOS_EPOLLIN;
159*3ae9e016SAsim Jamshed ev.data.sock = sockid;
160*3ae9e016SAsim Jamshed mtcp_epoll_ctl(ctx->mctx, ctx->ep, MOS_EPOLL_CTL_MOD, sockid, &ev);
161*3ae9e016SAsim Jamshed
162*3ae9e016SAsim Jamshed CleanServerVariable(sv);
163*3ae9e016SAsim Jamshed } else {
164*3ae9e016SAsim Jamshed /* else, close connection */
165*3ae9e016SAsim Jamshed CloseConnection(ctx, sockid, sv);
166*3ae9e016SAsim Jamshed }
167*3ae9e016SAsim Jamshed }
168*3ae9e016SAsim Jamshed
169*3ae9e016SAsim Jamshed return sent;
170*3ae9e016SAsim Jamshed }
171*3ae9e016SAsim Jamshed /*----------------------------------------------------------------------------*/
172*3ae9e016SAsim Jamshed static int
HandleReadEvent(struct thread_context * ctx,int sockid,struct server_vars * sv)173*3ae9e016SAsim Jamshed HandleReadEvent(struct thread_context *ctx, int sockid, struct server_vars *sv)
174*3ae9e016SAsim Jamshed {
175*3ae9e016SAsim Jamshed struct mtcp_epoll_event ev;
176*3ae9e016SAsim Jamshed char buf[HTTP_HEADER_LEN];
177*3ae9e016SAsim Jamshed char url[URL_LEN];
178*3ae9e016SAsim Jamshed char response[HTTP_HEADER_LEN];
179*3ae9e016SAsim Jamshed int scode; // status code
180*3ae9e016SAsim Jamshed time_t t_now;
181*3ae9e016SAsim Jamshed char t_str[128];
182*3ae9e016SAsim Jamshed char keepalive_str[128];
183*3ae9e016SAsim Jamshed int rd;
184*3ae9e016SAsim Jamshed int i;
185*3ae9e016SAsim Jamshed int len;
186*3ae9e016SAsim Jamshed int sent;
187*3ae9e016SAsim Jamshed
188*3ae9e016SAsim Jamshed /* HTTP request handling */
189*3ae9e016SAsim Jamshed rd = mtcp_read(ctx->mctx, sockid, buf, HTTP_HEADER_LEN);
190*3ae9e016SAsim Jamshed if (rd <= 0) {
191*3ae9e016SAsim Jamshed return rd;
192*3ae9e016SAsim Jamshed }
193*3ae9e016SAsim Jamshed memcpy(sv->request + sv->recv_len,
194*3ae9e016SAsim Jamshed (char *)buf, MIN(rd, HTTP_HEADER_LEN - sv->recv_len));
195*3ae9e016SAsim Jamshed sv->recv_len += rd;
196*3ae9e016SAsim Jamshed //sv->request[rd] = '\0';
197*3ae9e016SAsim Jamshed //fprintf(stderr, "HTTP Request: \n%s", request);
198*3ae9e016SAsim Jamshed sv->request_len = find_http_header(sv->request, sv->recv_len);
199*3ae9e016SAsim Jamshed if (sv->request_len <= 0) {
200*3ae9e016SAsim Jamshed TRACE_ERROR("Socket %d: Failed to parse HTTP request header.\n"
201*3ae9e016SAsim Jamshed "read bytes: %d, recv_len: %d, "
202*3ae9e016SAsim Jamshed "request_len: %d, strlen: %ld, request: \n%s\n",
203*3ae9e016SAsim Jamshed sockid, rd, sv->recv_len,
204*3ae9e016SAsim Jamshed sv->request_len, strlen(sv->request), sv->request);
205*3ae9e016SAsim Jamshed return rd;
206*3ae9e016SAsim Jamshed }
207*3ae9e016SAsim Jamshed
208*3ae9e016SAsim Jamshed http_get_url(sv->request, sv->request_len, url, URL_LEN);
209*3ae9e016SAsim Jamshed TRACE_APP("Socket %d URL: %s\n", sockid, url);
210*3ae9e016SAsim Jamshed sprintf(sv->fname, "%s%s", www_main, url);
211*3ae9e016SAsim Jamshed TRACE_APP("Socket %d File name: %s\n", sockid, sv->fname);
212*3ae9e016SAsim Jamshed
213*3ae9e016SAsim Jamshed
214*3ae9e016SAsim Jamshed sv->keep_alive = FALSE;
215*3ae9e016SAsim Jamshed if (http_header_str_val(sv->request, CONN_HDR_FLD,
216*3ae9e016SAsim Jamshed sizeof(CONN_HDR_FLD)-1, keepalive_str, sizeof(keepalive_str))) {
217*3ae9e016SAsim Jamshed sv->keep_alive = !strcasecmp(keepalive_str, KEEP_ALIVE_STR);
218*3ae9e016SAsim Jamshed }
219*3ae9e016SAsim Jamshed
220*3ae9e016SAsim Jamshed /* Find file in cache */
221*3ae9e016SAsim Jamshed scode = 404;
222*3ae9e016SAsim Jamshed for (i = 0; i < nfiles; i++) {
223*3ae9e016SAsim Jamshed if (strcmp(sv->fname, fcache[i].fullname) == 0) {
224*3ae9e016SAsim Jamshed sv->fsize = fcache[i].size;
225*3ae9e016SAsim Jamshed sv->fidx = i;
226*3ae9e016SAsim Jamshed scode = 200;
227*3ae9e016SAsim Jamshed break;
228*3ae9e016SAsim Jamshed }
229*3ae9e016SAsim Jamshed }
230*3ae9e016SAsim Jamshed TRACE_APP("Socket %d File size: %ld (%ldMB)\n",
231*3ae9e016SAsim Jamshed sockid, sv->fsize, sv->fsize / 1024 / 1024);
232*3ae9e016SAsim Jamshed
233*3ae9e016SAsim Jamshed /* Response header handling */
234*3ae9e016SAsim Jamshed time(&t_now);
235*3ae9e016SAsim Jamshed strftime(t_str, 128, "%a, %d %b %Y %X GMT", gmtime(&t_now));
236*3ae9e016SAsim Jamshed if (sv->keep_alive)
237*3ae9e016SAsim Jamshed sprintf(keepalive_str, "Keep-Alive");
238*3ae9e016SAsim Jamshed else
239*3ae9e016SAsim Jamshed sprintf(keepalive_str, "Close");
240*3ae9e016SAsim Jamshed
241*3ae9e016SAsim Jamshed sprintf(response, "HTTP/1.1 %d %s\r\n"
242*3ae9e016SAsim Jamshed "Date: %s\r\n"
243*3ae9e016SAsim Jamshed "Server: Webserver on Middlebox TCP (Ubuntu)\r\n"
244*3ae9e016SAsim Jamshed "Content-Length: %ld\r\n"
245*3ae9e016SAsim Jamshed "Connection: %s\r\n\r\n",
246*3ae9e016SAsim Jamshed scode, StatusCodeToString(scode), t_str, sv->fsize, keepalive_str);
247*3ae9e016SAsim Jamshed len = strlen(response);
248*3ae9e016SAsim Jamshed TRACE_APP("Socket %d HTTP Response: \n%s", sockid, response);
249*3ae9e016SAsim Jamshed sent = mtcp_write(ctx->mctx, sockid, response, len);
250*3ae9e016SAsim Jamshed if (sent < len) {
251*3ae9e016SAsim Jamshed TRACE_ERROR("Socket %d: Sending HTTP response failed. "
252*3ae9e016SAsim Jamshed "try: %d, sent: %d\n", sockid, len, sent);
253*3ae9e016SAsim Jamshed CloseConnection(ctx, sockid, sv);
254*3ae9e016SAsim Jamshed }
255*3ae9e016SAsim Jamshed TRACE_APP("Socket %d Sent response header: try: %d, sent: %d\n",
256*3ae9e016SAsim Jamshed sockid, len, sent);
257*3ae9e016SAsim Jamshed assert(sent == len);
258*3ae9e016SAsim Jamshed sv->rspheader_sent = TRUE;
259*3ae9e016SAsim Jamshed
260*3ae9e016SAsim Jamshed ev.events = MOS_EPOLLIN | MOS_EPOLLOUT;
261*3ae9e016SAsim Jamshed ev.data.sock = sockid;
262*3ae9e016SAsim Jamshed mtcp_epoll_ctl(ctx->mctx, ctx->ep, MOS_EPOLL_CTL_MOD, sockid, &ev);
263*3ae9e016SAsim Jamshed
264*3ae9e016SAsim Jamshed SendUntilAvailable(ctx, sockid, sv);
265*3ae9e016SAsim Jamshed
266*3ae9e016SAsim Jamshed return rd;
267*3ae9e016SAsim Jamshed }
268*3ae9e016SAsim Jamshed /*----------------------------------------------------------------------------*/
269*3ae9e016SAsim Jamshed static int
AcceptConnection(struct thread_context * ctx,int listener)270*3ae9e016SAsim Jamshed AcceptConnection(struct thread_context *ctx, int listener)
271*3ae9e016SAsim Jamshed {
272*3ae9e016SAsim Jamshed mctx_t mctx = ctx->mctx;
273*3ae9e016SAsim Jamshed struct server_vars *sv;
274*3ae9e016SAsim Jamshed struct mtcp_epoll_event ev;
275*3ae9e016SAsim Jamshed int c;
276*3ae9e016SAsim Jamshed
277*3ae9e016SAsim Jamshed c = mtcp_accept(mctx, listener, NULL, NULL);
278*3ae9e016SAsim Jamshed
279*3ae9e016SAsim Jamshed if (c >= 0) {
280*3ae9e016SAsim Jamshed if (c >= MAX_FLOW_NUM) {
281*3ae9e016SAsim Jamshed TRACE_ERROR("Invalid socket id %d.\n", c);
282*3ae9e016SAsim Jamshed return -1;
283*3ae9e016SAsim Jamshed }
284*3ae9e016SAsim Jamshed
285*3ae9e016SAsim Jamshed sv = &ctx->svars[c];
286*3ae9e016SAsim Jamshed CleanServerVariable(sv);
287*3ae9e016SAsim Jamshed TRACE_APP("New connection %d accepted.\n", c);
288*3ae9e016SAsim Jamshed ev.events = MOS_EPOLLIN;
289*3ae9e016SAsim Jamshed ev.data.sock = c;
290*3ae9e016SAsim Jamshed mtcp_setsock_nonblock(ctx->mctx, c);
291*3ae9e016SAsim Jamshed mtcp_epoll_ctl(mctx, ctx->ep, MOS_EPOLL_CTL_ADD, c, &ev);
292*3ae9e016SAsim Jamshed TRACE_APP("Socket %d registered.\n", c);
293*3ae9e016SAsim Jamshed
294*3ae9e016SAsim Jamshed } else {
295*3ae9e016SAsim Jamshed if (errno != EAGAIN) {
296*3ae9e016SAsim Jamshed TRACE_ERROR("mtcp_accept() error %s\n",
297*3ae9e016SAsim Jamshed strerror(errno));
298*3ae9e016SAsim Jamshed }
299*3ae9e016SAsim Jamshed }
300*3ae9e016SAsim Jamshed
301*3ae9e016SAsim Jamshed return c;
302*3ae9e016SAsim Jamshed }
303*3ae9e016SAsim Jamshed /*----------------------------------------------------------------------------*/
304*3ae9e016SAsim Jamshed static int
CreateListeningSocket(struct thread_context * ctx)305*3ae9e016SAsim Jamshed CreateListeningSocket(struct thread_context *ctx)
306*3ae9e016SAsim Jamshed {
307*3ae9e016SAsim Jamshed int listener;
308*3ae9e016SAsim Jamshed struct mtcp_epoll_event ev;
309*3ae9e016SAsim Jamshed struct sockaddr_in saddr;
310*3ae9e016SAsim Jamshed int ret;
311*3ae9e016SAsim Jamshed
312*3ae9e016SAsim Jamshed /* create socket and set it as nonblocking */
313*3ae9e016SAsim Jamshed listener = mtcp_socket(ctx->mctx, AF_INET, SOCK_STREAM, 0);
314*3ae9e016SAsim Jamshed if (listener < 0) {
315*3ae9e016SAsim Jamshed TRACE_ERROR("Failed to create listening socket!\n");
316*3ae9e016SAsim Jamshed return -1;
317*3ae9e016SAsim Jamshed }
318*3ae9e016SAsim Jamshed ret = mtcp_setsock_nonblock(ctx->mctx, listener);
319*3ae9e016SAsim Jamshed if (ret < 0) {
320*3ae9e016SAsim Jamshed TRACE_ERROR("Failed to set socket in nonblocking mode.\n");
321*3ae9e016SAsim Jamshed return -1;
322*3ae9e016SAsim Jamshed }
323*3ae9e016SAsim Jamshed
324*3ae9e016SAsim Jamshed /* bind to port 80 */
325*3ae9e016SAsim Jamshed saddr.sin_family = AF_INET;
326*3ae9e016SAsim Jamshed saddr.sin_addr.s_addr = INADDR_ANY;
327*3ae9e016SAsim Jamshed saddr.sin_port = htons(80);
328*3ae9e016SAsim Jamshed ret = mtcp_bind(ctx->mctx, listener,
329*3ae9e016SAsim Jamshed (struct sockaddr *)&saddr, sizeof(struct sockaddr_in));
330*3ae9e016SAsim Jamshed if (ret < 0) {
331*3ae9e016SAsim Jamshed TRACE_ERROR("Failed to bind to the listening socket!\n");
332*3ae9e016SAsim Jamshed return -1;
333*3ae9e016SAsim Jamshed }
334*3ae9e016SAsim Jamshed
335*3ae9e016SAsim Jamshed /* listen (backlog: 4K) */
336*3ae9e016SAsim Jamshed ret = mtcp_listen(ctx->mctx, listener, 4096);
337*3ae9e016SAsim Jamshed if (ret < 0) {
338*3ae9e016SAsim Jamshed TRACE_ERROR("mtcp_listen() failed!\n");
339*3ae9e016SAsim Jamshed return -1;
340*3ae9e016SAsim Jamshed }
341*3ae9e016SAsim Jamshed
342*3ae9e016SAsim Jamshed /* wait for incoming accept events */
343*3ae9e016SAsim Jamshed ev.events = MOS_EPOLLIN;
344*3ae9e016SAsim Jamshed ev.data.sock = listener;
345*3ae9e016SAsim Jamshed mtcp_epoll_ctl(ctx->mctx, ctx->ep, MOS_EPOLL_CTL_ADD, listener, &ev);
346*3ae9e016SAsim Jamshed
347*3ae9e016SAsim Jamshed return listener;
348*3ae9e016SAsim Jamshed }
349*3ae9e016SAsim Jamshed /*----------------------------------------------------------------------------*/
350*3ae9e016SAsim Jamshed static void
GlobInitServer()351*3ae9e016SAsim Jamshed GlobInitServer()
352*3ae9e016SAsim Jamshed {
353*3ae9e016SAsim Jamshed DIR *dir;
354*3ae9e016SAsim Jamshed struct dirent *ent;
355*3ae9e016SAsim Jamshed int fd;
356*3ae9e016SAsim Jamshed int ret;
357*3ae9e016SAsim Jamshed uint64_t total_read;
358*3ae9e016SAsim Jamshed
359*3ae9e016SAsim Jamshed num_cores = GetNumCPUs();
360*3ae9e016SAsim Jamshed core_limit = num_cores;
361*3ae9e016SAsim Jamshed
362*3ae9e016SAsim Jamshed if (LoadConfig(CONFIG_FILE, g_conf, NUM_CONF_VAR))
363*3ae9e016SAsim Jamshed exit(-1);
364*3ae9e016SAsim Jamshed
365*3ae9e016SAsim Jamshed core_limit = atoi(g_conf[0].value);
366*3ae9e016SAsim Jamshed www_main = g_conf[1].value;
367*3ae9e016SAsim Jamshed
368*3ae9e016SAsim Jamshed /* open the directory to serve */
369*3ae9e016SAsim Jamshed dir = opendir(www_main);
370*3ae9e016SAsim Jamshed if (!dir) {
371*3ae9e016SAsim Jamshed TRACE_ERROR("Failed to open %s.\n", www_main);
372*3ae9e016SAsim Jamshed perror("opendir");
373*3ae9e016SAsim Jamshed exit(-1);
374*3ae9e016SAsim Jamshed }
375*3ae9e016SAsim Jamshed
376*3ae9e016SAsim Jamshed nfiles = 0;
377*3ae9e016SAsim Jamshed while ((ent = readdir(dir)) != NULL) {
378*3ae9e016SAsim Jamshed if (strcmp(ent->d_name, ".") == 0)
379*3ae9e016SAsim Jamshed continue;
380*3ae9e016SAsim Jamshed else if (strcmp(ent->d_name, "..") == 0)
381*3ae9e016SAsim Jamshed continue;
382*3ae9e016SAsim Jamshed
383*3ae9e016SAsim Jamshed strcpy(fcache[nfiles].name, ent->d_name);
384*3ae9e016SAsim Jamshed sprintf(fcache[nfiles].fullname, "%s/%s", www_main, ent->d_name);
385*3ae9e016SAsim Jamshed fd = open(fcache[nfiles].fullname, O_RDONLY);
386*3ae9e016SAsim Jamshed if (fd < 0) {
387*3ae9e016SAsim Jamshed perror("open");
388*3ae9e016SAsim Jamshed continue;
389*3ae9e016SAsim Jamshed } else {
390*3ae9e016SAsim Jamshed fcache[nfiles].size = lseek64(fd, 0, SEEK_END);
391*3ae9e016SAsim Jamshed lseek64(fd, 0, SEEK_SET);
392*3ae9e016SAsim Jamshed }
393*3ae9e016SAsim Jamshed
394*3ae9e016SAsim Jamshed fcache[nfiles].file = (char *)malloc(fcache[nfiles].size);
395*3ae9e016SAsim Jamshed if (!fcache[nfiles].file) {
396*3ae9e016SAsim Jamshed TRACE_ERROR("Failed to allocate memory for file %s\n",
397*3ae9e016SAsim Jamshed fcache[nfiles].name);
398*3ae9e016SAsim Jamshed perror("malloc");
399*3ae9e016SAsim Jamshed continue;
400*3ae9e016SAsim Jamshed }
401*3ae9e016SAsim Jamshed
402*3ae9e016SAsim Jamshed TRACE_INFO("Reading %s (%lu bytes)\n",
403*3ae9e016SAsim Jamshed fcache[nfiles].name, fcache[nfiles].size);
404*3ae9e016SAsim Jamshed total_read = 0;
405*3ae9e016SAsim Jamshed while (1) {
406*3ae9e016SAsim Jamshed ret = read(fd, fcache[nfiles].file + total_read,
407*3ae9e016SAsim Jamshed fcache[nfiles].size - total_read);
408*3ae9e016SAsim Jamshed if (ret < 0) {
409*3ae9e016SAsim Jamshed break;
410*3ae9e016SAsim Jamshed } else if (ret == 0) {
411*3ae9e016SAsim Jamshed break;
412*3ae9e016SAsim Jamshed }
413*3ae9e016SAsim Jamshed total_read += ret;
414*3ae9e016SAsim Jamshed }
415*3ae9e016SAsim Jamshed if (total_read < fcache[nfiles].size) {
416*3ae9e016SAsim Jamshed free(fcache[nfiles].file);
417*3ae9e016SAsim Jamshed continue;
418*3ae9e016SAsim Jamshed }
419*3ae9e016SAsim Jamshed close(fd);
420*3ae9e016SAsim Jamshed nfiles++;
421*3ae9e016SAsim Jamshed
422*3ae9e016SAsim Jamshed if (nfiles >= MAX_FILES)
423*3ae9e016SAsim Jamshed break;
424*3ae9e016SAsim Jamshed }
425*3ae9e016SAsim Jamshed
426*3ae9e016SAsim Jamshed finished = 0;
427*3ae9e016SAsim Jamshed
428*3ae9e016SAsim Jamshed return;
429*3ae9e016SAsim Jamshed }
430*3ae9e016SAsim Jamshed /*----------------------------------------------------------------------------*/
431*3ae9e016SAsim Jamshed static void
InitServer(mctx_t mctx,void ** app_ctx)432*3ae9e016SAsim Jamshed InitServer(mctx_t mctx, void **app_ctx)
433*3ae9e016SAsim Jamshed {
434*3ae9e016SAsim Jamshed struct thread_context *ctx;
435*3ae9e016SAsim Jamshed
436*3ae9e016SAsim Jamshed ctx = (struct thread_context *)calloc(1, sizeof(struct thread_context));
437*3ae9e016SAsim Jamshed if (!ctx) {
438*3ae9e016SAsim Jamshed TRACE_ERROR("Failed to create thread context!\n");
439*3ae9e016SAsim Jamshed exit(-1);
440*3ae9e016SAsim Jamshed }
441*3ae9e016SAsim Jamshed
442*3ae9e016SAsim Jamshed ctx->mctx = mctx;
443*3ae9e016SAsim Jamshed
444*3ae9e016SAsim Jamshed /* create epoll descriptor */
445*3ae9e016SAsim Jamshed ctx->ep = mtcp_epoll_create(mctx, MAX_EVENTS);
446*3ae9e016SAsim Jamshed if (ctx->ep < 0) {
447*3ae9e016SAsim Jamshed TRACE_ERROR("Failed to create epoll descriptor!\n");
448*3ae9e016SAsim Jamshed exit(-1);
449*3ae9e016SAsim Jamshed }
450*3ae9e016SAsim Jamshed
451*3ae9e016SAsim Jamshed /* allocate memory for server variables */
452*3ae9e016SAsim Jamshed ctx->svars = (struct server_vars *)
453*3ae9e016SAsim Jamshed calloc(MAX_FLOW_NUM, sizeof(struct server_vars));
454*3ae9e016SAsim Jamshed if (!ctx->svars) {
455*3ae9e016SAsim Jamshed TRACE_ERROR("Failed to create server_vars struct!\n");
456*3ae9e016SAsim Jamshed exit(-1);
457*3ae9e016SAsim Jamshed }
458*3ae9e016SAsim Jamshed
459*3ae9e016SAsim Jamshed ctx->listener = CreateListeningSocket(ctx);
460*3ae9e016SAsim Jamshed if (ctx->listener < 0) {
461*3ae9e016SAsim Jamshed TRACE_ERROR("Failed to create listening socket.\n");
462*3ae9e016SAsim Jamshed exit(-1);
463*3ae9e016SAsim Jamshed }
464*3ae9e016SAsim Jamshed
465*3ae9e016SAsim Jamshed *app_ctx = (void *)ctx;
466*3ae9e016SAsim Jamshed
467*3ae9e016SAsim Jamshed return;
468*3ae9e016SAsim Jamshed }
469*3ae9e016SAsim Jamshed /*----------------------------------------------------------------------------*/
470*3ae9e016SAsim Jamshed static void
RunServer(mctx_t mctx,void ** app_ctx)471*3ae9e016SAsim Jamshed RunServer(mctx_t mctx, void **app_ctx)
472*3ae9e016SAsim Jamshed {
473*3ae9e016SAsim Jamshed struct thread_context *ctx = (*app_ctx);
474*3ae9e016SAsim Jamshed int nevents;
475*3ae9e016SAsim Jamshed int i, ret;
476*3ae9e016SAsim Jamshed int do_accept;
477*3ae9e016SAsim Jamshed struct mtcp_epoll_event *events;
478*3ae9e016SAsim Jamshed
479*3ae9e016SAsim Jamshed assert(ctx);
480*3ae9e016SAsim Jamshed int ep = ctx->ep;
481*3ae9e016SAsim Jamshed
482*3ae9e016SAsim Jamshed events = (struct mtcp_epoll_event *)
483*3ae9e016SAsim Jamshed calloc(MAX_EVENTS, sizeof(struct mtcp_epoll_event));
484*3ae9e016SAsim Jamshed if (!events) {
485*3ae9e016SAsim Jamshed TRACE_ERROR("Failed to create event struct!\n");
486*3ae9e016SAsim Jamshed exit(-1);
487*3ae9e016SAsim Jamshed }
488*3ae9e016SAsim Jamshed
489*3ae9e016SAsim Jamshed while (1) {
490*3ae9e016SAsim Jamshed nevents = mtcp_epoll_wait(mctx, ep, events, MAX_EVENTS, -1);
491*3ae9e016SAsim Jamshed if (nevents < 0) {
492*3ae9e016SAsim Jamshed if (errno != EINTR)
493*3ae9e016SAsim Jamshed perror("mtcp_epoll_wait");
494*3ae9e016SAsim Jamshed break;
495*3ae9e016SAsim Jamshed }
496*3ae9e016SAsim Jamshed
497*3ae9e016SAsim Jamshed do_accept = FALSE;
498*3ae9e016SAsim Jamshed for (i = 0; i < nevents; i++) {
499*3ae9e016SAsim Jamshed
500*3ae9e016SAsim Jamshed if (events[i].data.sock == ctx->listener) {
501*3ae9e016SAsim Jamshed /* if the event is for the listener, accept connection */
502*3ae9e016SAsim Jamshed do_accept = TRUE;
503*3ae9e016SAsim Jamshed
504*3ae9e016SAsim Jamshed } else if (events[i].events & MOS_EPOLLERR) {
505*3ae9e016SAsim Jamshed int err;
506*3ae9e016SAsim Jamshed socklen_t len = sizeof(err);
507*3ae9e016SAsim Jamshed
508*3ae9e016SAsim Jamshed /* error on the connection */
509*3ae9e016SAsim Jamshed TRACE_APP("[CPU %d] Error on socket %d\n",
510*3ae9e016SAsim Jamshed core, events[i].data.sock);
511*3ae9e016SAsim Jamshed if (mtcp_getsockopt(mctx, events[i].data.sock,
512*3ae9e016SAsim Jamshed SOL_SOCKET, SO_ERROR, (void *)&err, &len) == 0) {
513*3ae9e016SAsim Jamshed if (err != ETIMEDOUT) {
514*3ae9e016SAsim Jamshed fprintf(stderr, "Error on socket %d: %s\n",
515*3ae9e016SAsim Jamshed events[i].data.sock, strerror(err));
516*3ae9e016SAsim Jamshed }
517*3ae9e016SAsim Jamshed } else {
518*3ae9e016SAsim Jamshed fprintf(stderr, "mtcp_getsockopt: %s (for sockid: %d)\n",
519*3ae9e016SAsim Jamshed strerror(errno), events[i].data.sock);
520*3ae9e016SAsim Jamshed exit(-1);
521*3ae9e016SAsim Jamshed }
522*3ae9e016SAsim Jamshed CloseConnection(ctx, events[i].data.sock,
523*3ae9e016SAsim Jamshed &ctx->svars[events[i].data.sock]);
524*3ae9e016SAsim Jamshed
525*3ae9e016SAsim Jamshed } else if (events[i].events & MOS_EPOLLIN) {
526*3ae9e016SAsim Jamshed ret = HandleReadEvent(ctx, events[i].data.sock,
527*3ae9e016SAsim Jamshed &ctx->svars[events[i].data.sock]);
528*3ae9e016SAsim Jamshed
529*3ae9e016SAsim Jamshed if (ret == 0) {
530*3ae9e016SAsim Jamshed /* connection closed by remote host */
531*3ae9e016SAsim Jamshed CloseConnection(ctx, events[i].data.sock,
532*3ae9e016SAsim Jamshed &ctx->svars[events[i].data.sock]);
533*3ae9e016SAsim Jamshed } else if (ret < 0) {
534*3ae9e016SAsim Jamshed /* if not EAGAIN, it's an error */
535*3ae9e016SAsim Jamshed if (errno != EAGAIN) {
536*3ae9e016SAsim Jamshed CloseConnection(ctx, events[i].data.sock,
537*3ae9e016SAsim Jamshed &ctx->svars[events[i].data.sock]);
538*3ae9e016SAsim Jamshed }
539*3ae9e016SAsim Jamshed }
540*3ae9e016SAsim Jamshed
541*3ae9e016SAsim Jamshed } else if (events[i].events & MOS_EPOLLOUT) {
542*3ae9e016SAsim Jamshed struct server_vars *sv = &ctx->svars[events[i].data.sock];
543*3ae9e016SAsim Jamshed if (sv->rspheader_sent) {
544*3ae9e016SAsim Jamshed SendUntilAvailable(ctx, events[i].data.sock, sv);
545*3ae9e016SAsim Jamshed } else {
546*3ae9e016SAsim Jamshed TRACE_APP("Socket %d: Response header not sent yet.\n",
547*3ae9e016SAsim Jamshed events[i].data.sock);
548*3ae9e016SAsim Jamshed }
549*3ae9e016SAsim Jamshed
550*3ae9e016SAsim Jamshed } else {
551*3ae9e016SAsim Jamshed assert(0);
552*3ae9e016SAsim Jamshed }
553*3ae9e016SAsim Jamshed }
554*3ae9e016SAsim Jamshed
555*3ae9e016SAsim Jamshed /* if do_accept flag is set, accept connections */
556*3ae9e016SAsim Jamshed if (do_accept) {
557*3ae9e016SAsim Jamshed while (1) {
558*3ae9e016SAsim Jamshed ret = AcceptConnection(ctx, ctx->listener);
559*3ae9e016SAsim Jamshed if (ret < 0)
560*3ae9e016SAsim Jamshed break;
561*3ae9e016SAsim Jamshed }
562*3ae9e016SAsim Jamshed }
563*3ae9e016SAsim Jamshed
564*3ae9e016SAsim Jamshed }
565*3ae9e016SAsim Jamshed
566*3ae9e016SAsim Jamshed return;
567*3ae9e016SAsim Jamshed }
568*3ae9e016SAsim Jamshed /*----------------------------------------------------------------------------*/
569*3ae9e016SAsim Jamshed void
RunApplication(mctx_t mctx)570*3ae9e016SAsim Jamshed RunApplication(mctx_t mctx)
571*3ae9e016SAsim Jamshed {
572*3ae9e016SAsim Jamshed void *app_ctx;
573*3ae9e016SAsim Jamshed
574*3ae9e016SAsim Jamshed app_ctx = (void *)calloc(1, sizeof(void *));
575*3ae9e016SAsim Jamshed if (!app_ctx) {
576*3ae9e016SAsim Jamshed TRACE_ERROR("calloc failure\n");
577*3ae9e016SAsim Jamshed return;
578*3ae9e016SAsim Jamshed }
579*3ae9e016SAsim Jamshed
580*3ae9e016SAsim Jamshed TRACE_INFO("run application on core %d\n", mctx->cpu);
581*3ae9e016SAsim Jamshed InitServer(mctx, &(app_ctx));
582*3ae9e016SAsim Jamshed RunServer(mctx, &(app_ctx));
583*3ae9e016SAsim Jamshed }
584*3ae9e016SAsim Jamshed /*----------------------------------------------------------------------------*/
585*3ae9e016SAsim Jamshed void *
RunMTCP(void * arg)586*3ae9e016SAsim Jamshed RunMTCP(void *arg)
587*3ae9e016SAsim Jamshed {
588*3ae9e016SAsim Jamshed int core = *(int *)arg;
589*3ae9e016SAsim Jamshed mctx_t mctx;
590*3ae9e016SAsim Jamshed
591*3ae9e016SAsim Jamshed mtcp_core_affinitize(core);
592*3ae9e016SAsim Jamshed
593*3ae9e016SAsim Jamshed /* mTCP Initialization */
594*3ae9e016SAsim Jamshed mctx = mtcp_create_context(core);
595*3ae9e016SAsim Jamshed if (!mctx) {
596*3ae9e016SAsim Jamshed pthread_exit(NULL);
597*3ae9e016SAsim Jamshed TRACE_ERROR("Failed to craete mtcp context.\n");
598*3ae9e016SAsim Jamshed return NULL;
599*3ae9e016SAsim Jamshed }
600*3ae9e016SAsim Jamshed
601*3ae9e016SAsim Jamshed /* Run application here */
602*3ae9e016SAsim Jamshed RunApplication(mctx);
603*3ae9e016SAsim Jamshed
604*3ae9e016SAsim Jamshed /* mTCP Tear Down */
605*3ae9e016SAsim Jamshed mtcp_destroy_context(mctx);
606*3ae9e016SAsim Jamshed
607*3ae9e016SAsim Jamshed return NULL;
608*3ae9e016SAsim Jamshed }
609*3ae9e016SAsim Jamshed /*----------------------------------------------------------------------------*/
610*3ae9e016SAsim Jamshed int
main(int argc,char ** argv)611*3ae9e016SAsim Jamshed main(int argc, char **argv)
612*3ae9e016SAsim Jamshed {
613*3ae9e016SAsim Jamshed int ret/*, i*/;
614*3ae9e016SAsim Jamshed int current_core = -1;
615*3ae9e016SAsim Jamshed char *fname = "config/mos.conf";
616*3ae9e016SAsim Jamshed
617*3ae9e016SAsim Jamshed int opt;
618*3ae9e016SAsim Jamshed while ((opt = getopt(argc, argv, "f:c:")) != -1) {
619*3ae9e016SAsim Jamshed switch (opt) {
620*3ae9e016SAsim Jamshed case 'f':
621*3ae9e016SAsim Jamshed fname = optarg;
622*3ae9e016SAsim Jamshed break;
623*3ae9e016SAsim Jamshed case 'c':
624*3ae9e016SAsim Jamshed current_core = atoi(optarg);
625*3ae9e016SAsim Jamshed if (current_core >= MAX_CPUS) {
626*3ae9e016SAsim Jamshed TRACE_ERROR("Invalid core id!\n");
627*3ae9e016SAsim Jamshed exit(EXIT_FAILURE);
628*3ae9e016SAsim Jamshed }
629*3ae9e016SAsim Jamshed break;
630*3ae9e016SAsim Jamshed default:
631*3ae9e016SAsim Jamshed printf("Usage: %s [-f config_file]\n", argv[0]);
632*3ae9e016SAsim Jamshed return 0;
633*3ae9e016SAsim Jamshed }
634*3ae9e016SAsim Jamshed
635*3ae9e016SAsim Jamshed }
636*3ae9e016SAsim Jamshed
637*3ae9e016SAsim Jamshed core_limit = sysconf(_SC_NPROCESSORS_ONLN);
638*3ae9e016SAsim Jamshed
639*3ae9e016SAsim Jamshed ret = mtcp_init(fname);
640*3ae9e016SAsim Jamshed if (ret) {
641*3ae9e016SAsim Jamshed TRACE_ERROR("Failed to initialize mtcp.\n");
642*3ae9e016SAsim Jamshed exit(EXIT_FAILURE);
643*3ae9e016SAsim Jamshed }
644*3ae9e016SAsim Jamshed
645*3ae9e016SAsim Jamshed if (current_core < 0) {
646*3ae9e016SAsim Jamshed TRACE_ERROR("Invalid core id.\n");
647*3ae9e016SAsim Jamshed exit(EXIT_FAILURE);
648*3ae9e016SAsim Jamshed }
649*3ae9e016SAsim Jamshed
650*3ae9e016SAsim Jamshed mtcp_getconf(&g_mcfg);
651*3ae9e016SAsim Jamshed
652*3ae9e016SAsim Jamshed core_limit = g_mcfg.num_cores;
653*3ae9e016SAsim Jamshed
654*3ae9e016SAsim Jamshed GlobInitServer();
655*3ae9e016SAsim Jamshed
656*3ae9e016SAsim Jamshed RunMTCP(¤t_core);
657*3ae9e016SAsim Jamshed
658*3ae9e016SAsim Jamshed mtcp_destroy();
659*3ae9e016SAsim Jamshed return 0;
660*3ae9e016SAsim Jamshed }
661*3ae9e016SAsim Jamshed /*----------------------------------------------------------------------------*/
662