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(&current_core);
657*3ae9e016SAsim Jamshed 
658*3ae9e016SAsim Jamshed 	mtcp_destroy();
659*3ae9e016SAsim Jamshed 	return 0;
660*3ae9e016SAsim Jamshed }
661*3ae9e016SAsim Jamshed /*----------------------------------------------------------------------------*/
662