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