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