1*76404edcSAsim Jamshed #include <stdio.h>
2*76404edcSAsim Jamshed #include <stdlib.h>
3*76404edcSAsim Jamshed #include <string.h>
4*76404edcSAsim Jamshed #include <unistd.h>
5*76404edcSAsim Jamshed #include <stdint.h>
6*76404edcSAsim Jamshed #include <time.h>
7*76404edcSAsim Jamshed #include <sys/time.h>
8*76404edcSAsim Jamshed #include <sys/types.h>
9*76404edcSAsim Jamshed #include <sys/stat.h>
10*76404edcSAsim Jamshed #include <fcntl.h>
11*76404edcSAsim Jamshed #include <pthread.h>
12*76404edcSAsim Jamshed #include <signal.h>
13*76404edcSAsim Jamshed #include <sys/socket.h>
14*76404edcSAsim Jamshed #include <netinet/in.h>
15*76404edcSAsim Jamshed #include <arpa/inet.h>
16*76404edcSAsim Jamshed #include <sys/queue.h>
17*76404edcSAsim Jamshed #include <assert.h>
18*76404edcSAsim Jamshed 
19*76404edcSAsim Jamshed #include <mos_api.h>
20*76404edcSAsim Jamshed #include "cpu.h"
21*76404edcSAsim Jamshed #include "rss.h"
22*76404edcSAsim Jamshed #include "http_parsing.h"
23*76404edcSAsim Jamshed #include "debug.h"
24*76404edcSAsim Jamshed #include "applib.h"
25*76404edcSAsim Jamshed 
26*76404edcSAsim Jamshed #define CONFIG_FILE       "config/epwget.conf"
27*76404edcSAsim Jamshed static struct conf_var g_conf[] = {
28*76404edcSAsim Jamshed 	{ "url",               {0} },
29*76404edcSAsim Jamshed 	{ "total_flows",       {0} },
30*76404edcSAsim Jamshed 	{ "core_limit",        {0} },
31*76404edcSAsim Jamshed 	{ "total_concurrency", {0} },
32*76404edcSAsim Jamshed 	{ "dest_port",         {0} },
33*76404edcSAsim Jamshed };
34*76404edcSAsim Jamshed #define NUM_CONF_VAR (sizeof(g_conf) / sizeof(struct conf_var))
35*76404edcSAsim Jamshed 
36*76404edcSAsim Jamshed #define PORT_NUM 80
37*76404edcSAsim Jamshed //#define PORT_NUM 3333
38*76404edcSAsim Jamshed 
39*76404edcSAsim Jamshed #define MAX_URL_LEN 128
40*76404edcSAsim Jamshed #define MAX_FILE_LEN 128
41*76404edcSAsim Jamshed #define HTTP_HEADER_LEN 1024
42*76404edcSAsim Jamshed 
43*76404edcSAsim Jamshed #define IP_RANGE 1
44*76404edcSAsim Jamshed #define MAX_IP_STR_LEN 16
45*76404edcSAsim Jamshed 
46*76404edcSAsim Jamshed #define BUF_SIZE (8*1024)
47*76404edcSAsim Jamshed 
48*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
49*76404edcSAsim Jamshed struct mtcp_conf g_mcfg;
50*76404edcSAsim Jamshed static pthread_t mtcp_thread[MAX_CPUS];
51*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
52*76404edcSAsim Jamshed static mctx_t g_mctx[MAX_CPUS];
53*76404edcSAsim Jamshed static int done[MAX_CPUS];
54*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
55*76404edcSAsim Jamshed static int num_cores;
56*76404edcSAsim Jamshed static int core_limit;
57*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
58*76404edcSAsim Jamshed static int fio = FALSE;
59*76404edcSAsim Jamshed static char outfile[MAX_FILE_LEN + 1];
60*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
61*76404edcSAsim Jamshed static char host[MAX_IP_STR_LEN + 1];
62*76404edcSAsim Jamshed static char path[MAX_URL_LEN + 1];
63*76404edcSAsim Jamshed static in_addr_t daddr;
64*76404edcSAsim Jamshed static in_port_t dport;
65*76404edcSAsim Jamshed static in_addr_t saddr;
66*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
67*76404edcSAsim Jamshed static int total_flows;
68*76404edcSAsim Jamshed static int flows[MAX_CPUS];
69*76404edcSAsim Jamshed static int flowcnt = 0;
70*76404edcSAsim Jamshed static int concurrency;
71*76404edcSAsim Jamshed static int max_fds;
72*76404edcSAsim Jamshed static uint16_t dest_port;
73*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
74*76404edcSAsim Jamshed struct wget_stat
75*76404edcSAsim Jamshed {
76*76404edcSAsim Jamshed 	uint64_t waits;
77*76404edcSAsim Jamshed 	uint64_t events;
78*76404edcSAsim Jamshed 	uint64_t connects;
79*76404edcSAsim Jamshed 	uint64_t reads;
80*76404edcSAsim Jamshed 	uint64_t writes;
81*76404edcSAsim Jamshed 	uint64_t completes;
82*76404edcSAsim Jamshed 
83*76404edcSAsim Jamshed 	uint64_t errors;
84*76404edcSAsim Jamshed 	uint64_t timedout;
85*76404edcSAsim Jamshed 
86*76404edcSAsim Jamshed 	uint64_t sum_resp_time;
87*76404edcSAsim Jamshed 	uint64_t max_resp_time;
88*76404edcSAsim Jamshed };
89*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
90*76404edcSAsim Jamshed struct thread_context
91*76404edcSAsim Jamshed {
92*76404edcSAsim Jamshed 	int core;
93*76404edcSAsim Jamshed 
94*76404edcSAsim Jamshed 	mctx_t mctx;
95*76404edcSAsim Jamshed 	int ep;
96*76404edcSAsim Jamshed 	struct wget_vars *wvars;
97*76404edcSAsim Jamshed 
98*76404edcSAsim Jamshed 	int target;
99*76404edcSAsim Jamshed 	int started;
100*76404edcSAsim Jamshed 	int errors;
101*76404edcSAsim Jamshed 	int incompletes;
102*76404edcSAsim Jamshed 	int done;
103*76404edcSAsim Jamshed 	int pending;
104*76404edcSAsim Jamshed 
105*76404edcSAsim Jamshed 	int maxevents;
106*76404edcSAsim Jamshed 	struct mtcp_epoll_event *events;
107*76404edcSAsim Jamshed 
108*76404edcSAsim Jamshed 	struct wget_stat stat;
109*76404edcSAsim Jamshed };
110*76404edcSAsim Jamshed typedef struct thread_context* thread_context_t;
111*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
112*76404edcSAsim Jamshed struct wget_vars
113*76404edcSAsim Jamshed {
114*76404edcSAsim Jamshed 	int request_sent;
115*76404edcSAsim Jamshed 
116*76404edcSAsim Jamshed 	char response[HTTP_HEADER_LEN];
117*76404edcSAsim Jamshed 	int resp_len;
118*76404edcSAsim Jamshed 	int headerset;
119*76404edcSAsim Jamshed 	uint32_t header_len;
120*76404edcSAsim Jamshed 	uint64_t file_len;
121*76404edcSAsim Jamshed 	uint64_t recv;
122*76404edcSAsim Jamshed 	uint64_t write;
123*76404edcSAsim Jamshed 
124*76404edcSAsim Jamshed 	struct timeval t_start;
125*76404edcSAsim Jamshed 	struct timeval t_end;
126*76404edcSAsim Jamshed 
127*76404edcSAsim Jamshed 	int fd;
128*76404edcSAsim Jamshed };
129*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
130*76404edcSAsim Jamshed static struct thread_context *g_ctx[MAX_CPUS];
131*76404edcSAsim Jamshed static struct wget_stat *g_stat[MAX_CPUS];
132*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
133*76404edcSAsim Jamshed static thread_context_t
134*76404edcSAsim Jamshed CreateContext(mctx_t mctx)
135*76404edcSAsim Jamshed {
136*76404edcSAsim Jamshed 	thread_context_t ctx;
137*76404edcSAsim Jamshed 
138*76404edcSAsim Jamshed 	ctx = (thread_context_t)calloc(1, sizeof(struct thread_context));
139*76404edcSAsim Jamshed 	if (!ctx) {
140*76404edcSAsim Jamshed 		perror("malloc");
141*76404edcSAsim Jamshed 		TRACE_ERROR("Failed to allocate memory for thread context.\n");
142*76404edcSAsim Jamshed 		return NULL;
143*76404edcSAsim Jamshed 	}
144*76404edcSAsim Jamshed 
145*76404edcSAsim Jamshed 	ctx->mctx = mctx;
146*76404edcSAsim Jamshed 	ctx->core = mctx->cpu;
147*76404edcSAsim Jamshed 
148*76404edcSAsim Jamshed 	g_mctx[ctx->core] = mctx;
149*76404edcSAsim Jamshed 
150*76404edcSAsim Jamshed 	return ctx;
151*76404edcSAsim Jamshed }
152*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
153*76404edcSAsim Jamshed static void
154*76404edcSAsim Jamshed DestroyContext(thread_context_t ctx)
155*76404edcSAsim Jamshed {
156*76404edcSAsim Jamshed 	free(ctx);
157*76404edcSAsim Jamshed }
158*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
159*76404edcSAsim Jamshed static inline int
160*76404edcSAsim Jamshed CreateConnection(thread_context_t ctx)
161*76404edcSAsim Jamshed {
162*76404edcSAsim Jamshed 	mctx_t mctx = ctx->mctx;
163*76404edcSAsim Jamshed 	struct mtcp_epoll_event ev;
164*76404edcSAsim Jamshed 	struct sockaddr_in addr;
165*76404edcSAsim Jamshed 	int sockid;
166*76404edcSAsim Jamshed 	int ret;
167*76404edcSAsim Jamshed 
168*76404edcSAsim Jamshed 	assert(mctx);
169*76404edcSAsim Jamshed 
170*76404edcSAsim Jamshed 	errno = 0;
171*76404edcSAsim Jamshed 	sockid = mtcp_socket(mctx, AF_INET, SOCK_STREAM, 0);
172*76404edcSAsim Jamshed 	if (sockid < 0) {
173*76404edcSAsim Jamshed 		TRACE_INFO("Failed to create socket! (%s)\n",
174*76404edcSAsim Jamshed 			   strerror(errno));
175*76404edcSAsim Jamshed 		return -1;
176*76404edcSAsim Jamshed 	}
177*76404edcSAsim Jamshed 	memset(&ctx->wvars[sockid], 0, sizeof(struct wget_vars));
178*76404edcSAsim Jamshed 	ret = mtcp_setsock_nonblock(mctx, sockid);
179*76404edcSAsim Jamshed 	if (ret < 0) {
180*76404edcSAsim Jamshed 		TRACE_ERROR("Failed to set socket in nonblocking mode.\n");
181*76404edcSAsim Jamshed 		exit(-1);
182*76404edcSAsim Jamshed 	}
183*76404edcSAsim Jamshed 
184*76404edcSAsim Jamshed 	addr.sin_family = AF_INET;
185*76404edcSAsim Jamshed 	addr.sin_addr.s_addr = daddr;
186*76404edcSAsim Jamshed 	addr.sin_port = dport;
187*76404edcSAsim Jamshed 
188*76404edcSAsim Jamshed 	ret = mtcp_connect(mctx, sockid,
189*76404edcSAsim Jamshed 			(struct sockaddr *)&addr, sizeof(struct sockaddr_in));
190*76404edcSAsim Jamshed 	if (ret < 0) {
191*76404edcSAsim Jamshed 		if (errno != EINPROGRESS) {
192*76404edcSAsim Jamshed 			perror("mtcp_connect");
193*76404edcSAsim Jamshed 			mtcp_close(mctx, sockid);
194*76404edcSAsim Jamshed 			return -1;
195*76404edcSAsim Jamshed 		}
196*76404edcSAsim Jamshed 	}
197*76404edcSAsim Jamshed 
198*76404edcSAsim Jamshed 	ctx->started++;
199*76404edcSAsim Jamshed 	ctx->pending++;
200*76404edcSAsim Jamshed 	ctx->stat.connects++;
201*76404edcSAsim Jamshed 
202*76404edcSAsim Jamshed 	ev.events = MOS_EPOLLOUT;
203*76404edcSAsim Jamshed 	ev.data.sock = sockid;
204*76404edcSAsim Jamshed 	mtcp_epoll_ctl(mctx, ctx->ep, MOS_EPOLL_CTL_ADD, sockid, &ev);
205*76404edcSAsim Jamshed 
206*76404edcSAsim Jamshed 	return sockid;
207*76404edcSAsim Jamshed }
208*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
209*76404edcSAsim Jamshed static inline void
210*76404edcSAsim Jamshed CloseConnection(thread_context_t ctx, int sockid)
211*76404edcSAsim Jamshed {
212*76404edcSAsim Jamshed 	mtcp_epoll_ctl(ctx->mctx, ctx->ep, MOS_EPOLL_CTL_DEL, sockid, NULL);
213*76404edcSAsim Jamshed 	mtcp_close(ctx->mctx, sockid);
214*76404edcSAsim Jamshed 	ctx->pending--;
215*76404edcSAsim Jamshed 	ctx->done++;
216*76404edcSAsim Jamshed 	assert(ctx->pending >= 0);
217*76404edcSAsim Jamshed 	while (/*ctx->pending*/ mtcp_get_connection_cnt(ctx->mctx) < concurrency && ctx->started < ctx->target) {
218*76404edcSAsim Jamshed 		if (CreateConnection(ctx) < 0) {
219*76404edcSAsim Jamshed 			done[ctx->core] = TRUE;
220*76404edcSAsim Jamshed 			break;
221*76404edcSAsim Jamshed 		}
222*76404edcSAsim Jamshed 	}
223*76404edcSAsim Jamshed }
224*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
225*76404edcSAsim Jamshed static inline int
226*76404edcSAsim Jamshed SendHTTPRequest(thread_context_t ctx, int sockid, struct wget_vars *wv)
227*76404edcSAsim Jamshed {
228*76404edcSAsim Jamshed 	char request[HTTP_HEADER_LEN];
229*76404edcSAsim Jamshed 	struct mtcp_epoll_event ev;
230*76404edcSAsim Jamshed 	int wr;
231*76404edcSAsim Jamshed 	int len;
232*76404edcSAsim Jamshed 
233*76404edcSAsim Jamshed 	wv->headerset = FALSE;
234*76404edcSAsim Jamshed 	wv->recv = 0;
235*76404edcSAsim Jamshed 	wv->header_len = wv->file_len = 0;
236*76404edcSAsim Jamshed 
237*76404edcSAsim Jamshed 	snprintf(request, HTTP_HEADER_LEN, "GET %s HTTP/1.0\r\n"
238*76404edcSAsim Jamshed 			"User-Agent: Wget/1.12 (linux-gnu)\r\n"
239*76404edcSAsim Jamshed 			"Accept: */*\r\n"
240*76404edcSAsim Jamshed 			"Host: %s\r\n"
241*76404edcSAsim Jamshed //			"Connection: Keep-Alive\r\n\r\n",
242*76404edcSAsim Jamshed 			"Connection: Close\r\n\r\n",
243*76404edcSAsim Jamshed 			path, host);
244*76404edcSAsim Jamshed 	len = strlen(request);
245*76404edcSAsim Jamshed 
246*76404edcSAsim Jamshed 	wr = mtcp_write(ctx->mctx, sockid, request, len);
247*76404edcSAsim Jamshed 	if (wr < len) {
248*76404edcSAsim Jamshed 		TRACE_ERROR("Socket %d: Sending HTTP request failed. "
249*76404edcSAsim Jamshed 				"try: %d, sent: %d\n", sockid, len, wr);
250*76404edcSAsim Jamshed 		CloseConnection(ctx, sockid);
251*76404edcSAsim Jamshed 	}
252*76404edcSAsim Jamshed 	ctx->stat.writes += wr;
253*76404edcSAsim Jamshed 	TRACE_APP("Socket %d HTTP Request of %d bytes. sent.\n", sockid, wr);
254*76404edcSAsim Jamshed 	wv->request_sent = TRUE;
255*76404edcSAsim Jamshed 
256*76404edcSAsim Jamshed 	ev.events = MOS_EPOLLIN;
257*76404edcSAsim Jamshed 	ev.data.sock = sockid;
258*76404edcSAsim Jamshed 	mtcp_epoll_ctl(ctx->mctx, ctx->ep, MOS_EPOLL_CTL_MOD, sockid, &ev);
259*76404edcSAsim Jamshed 
260*76404edcSAsim Jamshed 	gettimeofday(&wv->t_start, NULL);
261*76404edcSAsim Jamshed 
262*76404edcSAsim Jamshed 	char fname[MAX_FILE_LEN + 1];
263*76404edcSAsim Jamshed 	if (fio) {
264*76404edcSAsim Jamshed 		snprintf(fname, MAX_FILE_LEN, "%s.%d", outfile, flowcnt++);
265*76404edcSAsim Jamshed 		wv->fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
266*76404edcSAsim Jamshed 		if (wv->fd < 0) {
267*76404edcSAsim Jamshed 			TRACE_APP("Failed to open file descriptor for %s\n", fname);
268*76404edcSAsim Jamshed 			exit(1);
269*76404edcSAsim Jamshed 		}
270*76404edcSAsim Jamshed 	}
271*76404edcSAsim Jamshed 
272*76404edcSAsim Jamshed 	return 0;
273*76404edcSAsim Jamshed }
274*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
275*76404edcSAsim Jamshed static inline int
276*76404edcSAsim Jamshed DownloadComplete(thread_context_t ctx, int sockid, struct wget_vars *wv)
277*76404edcSAsim Jamshed {
278*76404edcSAsim Jamshed #ifdef APP
279*76404edcSAsim Jamshed 	mctx_t mctx = ctx->mctx;
280*76404edcSAsim Jamshed #endif
281*76404edcSAsim Jamshed 	uint64_t tdiff;
282*76404edcSAsim Jamshed 
283*76404edcSAsim Jamshed 	TRACE_APP("Socket %d File download complete!\n", sockid);
284*76404edcSAsim Jamshed 	gettimeofday(&wv->t_end, NULL);
285*76404edcSAsim Jamshed 	CloseConnection(ctx, sockid);
286*76404edcSAsim Jamshed 	ctx->stat.completes++;
287*76404edcSAsim Jamshed 
288*76404edcSAsim Jamshed 	if (wv->recv - wv->header_len != wv->file_len) {
289*76404edcSAsim Jamshed 		fprintf(stderr, "Response size mismatch! "
290*76404edcSAsim Jamshed 						"actual recved: %ld,  expected to recved: %ld\n",
291*76404edcSAsim Jamshed 						wv->recv-wv->header_len, wv->file_len);
292*76404edcSAsim Jamshed 	}
293*76404edcSAsim Jamshed 
294*76404edcSAsim Jamshed 	tdiff = (wv->t_end.tv_sec - wv->t_start.tv_sec) * 1000000 +
295*76404edcSAsim Jamshed 			(wv->t_end.tv_usec - wv->t_start.tv_usec);
296*76404edcSAsim Jamshed 	TRACE_APP("Socket %d Total received bytes: %lu (%luMB)\n",
297*76404edcSAsim Jamshed 			sockid, wv->recv, wv->recv / 1000000);
298*76404edcSAsim Jamshed 	TRACE_APP("Socket %d Total spent time: %lu us\n", sockid, tdiff);
299*76404edcSAsim Jamshed 	if (tdiff > 0) {
300*76404edcSAsim Jamshed 		TRACE_APP("Socket %d Average bandwidth: %lf[MB/s]\n",
301*76404edcSAsim Jamshed 				sockid, (double)wv->recv / tdiff);
302*76404edcSAsim Jamshed 	}
303*76404edcSAsim Jamshed 	ctx->stat.sum_resp_time += tdiff;
304*76404edcSAsim Jamshed 	if (tdiff > ctx->stat.max_resp_time)
305*76404edcSAsim Jamshed 		ctx->stat.max_resp_time = tdiff;
306*76404edcSAsim Jamshed 
307*76404edcSAsim Jamshed 	if (fio && wv->fd > 0)
308*76404edcSAsim Jamshed 		close(wv->fd);
309*76404edcSAsim Jamshed 
310*76404edcSAsim Jamshed 	return 0;
311*76404edcSAsim Jamshed }
312*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
313*76404edcSAsim Jamshed static inline int
314*76404edcSAsim Jamshed HandleReadEvent(thread_context_t ctx, int sockid, struct wget_vars *wv)
315*76404edcSAsim Jamshed {
316*76404edcSAsim Jamshed 	mctx_t mctx = ctx->mctx;
317*76404edcSAsim Jamshed 	char buf[BUF_SIZE];
318*76404edcSAsim Jamshed 	char *pbuf;
319*76404edcSAsim Jamshed 	int rd, copy_len;
320*76404edcSAsim Jamshed 
321*76404edcSAsim Jamshed 	rd = 1;
322*76404edcSAsim Jamshed 	while (rd > 0) {
323*76404edcSAsim Jamshed 		rd = mtcp_read(mctx, sockid, buf, BUF_SIZE);
324*76404edcSAsim Jamshed 		if (rd <= 0)
325*76404edcSAsim Jamshed 			break;
326*76404edcSAsim Jamshed 		ctx->stat.reads += rd;
327*76404edcSAsim Jamshed 
328*76404edcSAsim Jamshed 		TRACE_APP("Socket %d: mtcp_read ret: %d, total_recv: %lu, "
329*76404edcSAsim Jamshed 				"header_set: %d, header_len: %u, file_len: %lu\n",
330*76404edcSAsim Jamshed 				sockid, rd, wv->recv + rd,
331*76404edcSAsim Jamshed 				wv->headerset, wv->header_len, wv->file_len);
332*76404edcSAsim Jamshed 
333*76404edcSAsim Jamshed 		pbuf = buf;
334*76404edcSAsim Jamshed 		if (!wv->headerset) {
335*76404edcSAsim Jamshed 			copy_len = MIN(rd, HTTP_HEADER_LEN - wv->resp_len);
336*76404edcSAsim Jamshed 			memcpy(wv->response + wv->resp_len, buf, copy_len);
337*76404edcSAsim Jamshed 			wv->resp_len += copy_len;
338*76404edcSAsim Jamshed 			wv->header_len = find_http_header(wv->response, wv->resp_len);
339*76404edcSAsim Jamshed 			if (wv->header_len > 0) {
340*76404edcSAsim Jamshed 				wv->response[wv->header_len] = '\0';
341*76404edcSAsim Jamshed 				wv->file_len = http_header_long_val(wv->response,
342*76404edcSAsim Jamshed 						CONTENT_LENGTH_HDR, sizeof(CONTENT_LENGTH_HDR) - 1);
343*76404edcSAsim Jamshed 				TRACE_APP("Socket %d Parsed response header. "
344*76404edcSAsim Jamshed 						"Header length: %u, File length: %lu (%luMB)\n",
345*76404edcSAsim Jamshed 						sockid, wv->header_len,
346*76404edcSAsim Jamshed 						wv->file_len, wv->file_len / 1024 / 1024);
347*76404edcSAsim Jamshed 				wv->headerset = TRUE;
348*76404edcSAsim Jamshed 				wv->recv += (rd - (wv->resp_len - wv->header_len));
349*76404edcSAsim Jamshed 				rd = (wv->resp_len - wv->header_len);
350*76404edcSAsim Jamshed 
351*76404edcSAsim Jamshed 				pbuf += (rd - (wv->resp_len - wv->header_len));
352*76404edcSAsim Jamshed 
353*76404edcSAsim Jamshed 			} else {
354*76404edcSAsim Jamshed 				/* failed to parse response header */
355*76404edcSAsim Jamshed 				wv->recv += rd;
356*76404edcSAsim Jamshed 				rd = 0;
357*76404edcSAsim Jamshed 				ctx->stat.errors++;
358*76404edcSAsim Jamshed 				ctx->errors++;
359*76404edcSAsim Jamshed 				CloseConnection(ctx, sockid);
360*76404edcSAsim Jamshed 				return 0;
361*76404edcSAsim Jamshed 			}
362*76404edcSAsim Jamshed 		}
363*76404edcSAsim Jamshed 		wv->recv += rd;
364*76404edcSAsim Jamshed 
365*76404edcSAsim Jamshed 		if (fio && wv->fd > 0) {
366*76404edcSAsim Jamshed 			int wr = 0;
367*76404edcSAsim Jamshed 			while (wr < rd) {
368*76404edcSAsim Jamshed 				int _wr = write(wv->fd, pbuf + wr, rd - wr);
369*76404edcSAsim Jamshed 				assert (_wr == rd - wr);
370*76404edcSAsim Jamshed 				 if (_wr < 0) {
371*76404edcSAsim Jamshed 					 perror("write");
372*76404edcSAsim Jamshed 					 TRACE_ERROR("Failed to write.\n");
373*76404edcSAsim Jamshed 					 assert(0);
374*76404edcSAsim Jamshed 					 break;
375*76404edcSAsim Jamshed 				 }
376*76404edcSAsim Jamshed 				 wr += _wr;
377*76404edcSAsim Jamshed 				 wv->write += _wr;
378*76404edcSAsim Jamshed 			}
379*76404edcSAsim Jamshed 		}
380*76404edcSAsim Jamshed 
381*76404edcSAsim Jamshed 		if (wv->header_len && (wv->recv >= wv->header_len + wv->file_len)) {
382*76404edcSAsim Jamshed 			break;
383*76404edcSAsim Jamshed 		}
384*76404edcSAsim Jamshed 	}
385*76404edcSAsim Jamshed 
386*76404edcSAsim Jamshed 	if (rd > 0) {
387*76404edcSAsim Jamshed 		if (wv->header_len && (wv->recv >= wv->header_len + wv->file_len)) {
388*76404edcSAsim Jamshed 			TRACE_APP("Socket %d Done Write: "
389*76404edcSAsim Jamshed 					"header: %u file: %lu recv: %lu write: %lu\n",
390*76404edcSAsim Jamshed 					sockid, wv->header_len, wv->file_len,
391*76404edcSAsim Jamshed 					wv->recv - wv->header_len, wv->write);
392*76404edcSAsim Jamshed 			DownloadComplete(ctx, sockid, wv);
393*76404edcSAsim Jamshed 
394*76404edcSAsim Jamshed 			return 0;
395*76404edcSAsim Jamshed 		}
396*76404edcSAsim Jamshed 
397*76404edcSAsim Jamshed 	} else if (rd == 0) {
398*76404edcSAsim Jamshed 		/* connection closed by remote host */
399*76404edcSAsim Jamshed 		TRACE_DBG("Socket %d connection closed with server.\n", sockid);
400*76404edcSAsim Jamshed 
401*76404edcSAsim Jamshed 		if (wv->header_len && (wv->recv >= wv->header_len + wv->file_len)) {
402*76404edcSAsim Jamshed 			DownloadComplete(ctx, sockid, wv);
403*76404edcSAsim Jamshed 		} else {
404*76404edcSAsim Jamshed 			ctx->stat.errors++;
405*76404edcSAsim Jamshed 			ctx->incompletes++;
406*76404edcSAsim Jamshed 			CloseConnection(ctx, sockid);
407*76404edcSAsim Jamshed 		}
408*76404edcSAsim Jamshed 
409*76404edcSAsim Jamshed 	} else if (rd < 0) {
410*76404edcSAsim Jamshed 		if (errno != EAGAIN) {
411*76404edcSAsim Jamshed 			TRACE_DBG("Socket %d: mtcp_read() error %s\n",
412*76404edcSAsim Jamshed 					sockid, strerror(errno));
413*76404edcSAsim Jamshed 			ctx->stat.errors++;
414*76404edcSAsim Jamshed 			ctx->errors++;
415*76404edcSAsim Jamshed 			CloseConnection(ctx, sockid);
416*76404edcSAsim Jamshed 		}
417*76404edcSAsim Jamshed 	}
418*76404edcSAsim Jamshed 
419*76404edcSAsim Jamshed 	return 0;
420*76404edcSAsim Jamshed }
421*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
422*76404edcSAsim Jamshed static void
423*76404edcSAsim Jamshed PrintStats()
424*76404edcSAsim Jamshed {
425*76404edcSAsim Jamshed 	struct wget_stat total = {0};
426*76404edcSAsim Jamshed 	struct wget_stat *st;
427*76404edcSAsim Jamshed 	uint64_t avg_resp_time;
428*76404edcSAsim Jamshed 	uint64_t total_resp_time = 0;
429*76404edcSAsim Jamshed 	int i;
430*76404edcSAsim Jamshed 
431*76404edcSAsim Jamshed 	for (i = 0; i < core_limit; i++) {
432*76404edcSAsim Jamshed 		st = g_stat[i];
433*76404edcSAsim Jamshed 		if (!st)
434*76404edcSAsim Jamshed 			continue;
435*76404edcSAsim Jamshed 		avg_resp_time = st->completes? st->sum_resp_time / st->completes : 0;
436*76404edcSAsim Jamshed 
437*76404edcSAsim Jamshed 		total.waits += st->waits;
438*76404edcSAsim Jamshed 		total.events += st->events;
439*76404edcSAsim Jamshed 		total.connects += st->connects;
440*76404edcSAsim Jamshed 		total.reads += st->reads;
441*76404edcSAsim Jamshed 		total.writes += st->writes;
442*76404edcSAsim Jamshed 		total.completes += st->completes;
443*76404edcSAsim Jamshed 		total_resp_time += avg_resp_time;
444*76404edcSAsim Jamshed 		if (st->max_resp_time > total.max_resp_time)
445*76404edcSAsim Jamshed 			total.max_resp_time = st->max_resp_time;
446*76404edcSAsim Jamshed 		total.errors += st->errors;
447*76404edcSAsim Jamshed 		total.timedout += st->timedout;
448*76404edcSAsim Jamshed 
449*76404edcSAsim Jamshed 		memset(st, 0, sizeof(struct wget_stat));
450*76404edcSAsim Jamshed 	}
451*76404edcSAsim Jamshed 	fprintf(stderr, "[ ALL ] connect: %7lu, read: %4lu MB, write: %4lu MB, "
452*76404edcSAsim Jamshed 			"completes: %7lu (resp_time avg: %4lu, max: %6lu us)\n",
453*76404edcSAsim Jamshed 			total.connects,
454*76404edcSAsim Jamshed 			total.reads / 1000 / 1000, total.writes / 1000 / 1000,
455*76404edcSAsim Jamshed 			total.completes, total_resp_time / core_limit, total.max_resp_time);
456*76404edcSAsim Jamshed }
457*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
458*76404edcSAsim Jamshed static void
459*76404edcSAsim Jamshed GlbInitWget()
460*76404edcSAsim Jamshed {
461*76404edcSAsim Jamshed 	struct mtcp_conf mcfg;
462*76404edcSAsim Jamshed 	char *url;
463*76404edcSAsim Jamshed 	int total_concurrency = 0;
464*76404edcSAsim Jamshed 	int flow_per_thread;
465*76404edcSAsim Jamshed 	int flow_remainder_cnt;
466*76404edcSAsim Jamshed 	int i;
467*76404edcSAsim Jamshed 
468*76404edcSAsim Jamshed 	num_cores = GetNumCPUs();
469*76404edcSAsim Jamshed 	core_limit = num_cores;
470*76404edcSAsim Jamshed 	concurrency = 100;
471*76404edcSAsim Jamshed 	total_flows = -1;
472*76404edcSAsim Jamshed 
473*76404edcSAsim Jamshed 	LoadConfig(CONFIG_FILE, g_conf, NUM_CONF_VAR);
474*76404edcSAsim Jamshed 
475*76404edcSAsim Jamshed 	url = g_conf[0].value;
476*76404edcSAsim Jamshed 	total_flows = atoi(g_conf[1].value);
477*76404edcSAsim Jamshed 	core_limit = atoi(g_conf[2].value);
478*76404edcSAsim Jamshed 	total_concurrency = atoi(g_conf[3].value);
479*76404edcSAsim Jamshed 	dest_port = atoi(g_conf[4].value);
480*76404edcSAsim Jamshed 
481*76404edcSAsim Jamshed 	if ((strlen(url) == 0)
482*76404edcSAsim Jamshed 			|| (strlen(url) > MAX_URL_LEN)
483*76404edcSAsim Jamshed 			|| (total_flows <= 0)) {
484*76404edcSAsim Jamshed 		TRACE_INFO("Invalid configuration\n");
485*76404edcSAsim Jamshed 		exit(0);
486*76404edcSAsim Jamshed 	}
487*76404edcSAsim Jamshed 
488*76404edcSAsim Jamshed 	char* slash_p = strchr(url, '/');
489*76404edcSAsim Jamshed 	if (slash_p) {
490*76404edcSAsim Jamshed 		strncpy(host, url, slash_p - url);
491*76404edcSAsim Jamshed 		strncpy(path, strchr(url, '/'), MAX_URL_LEN);
492*76404edcSAsim Jamshed 	} else {
493*76404edcSAsim Jamshed 		strncpy(host, url, MAX_IP_STR_LEN);
494*76404edcSAsim Jamshed 		strncpy(path, "/", 1);
495*76404edcSAsim Jamshed 	}
496*76404edcSAsim Jamshed 
497*76404edcSAsim Jamshed 	daddr = inet_addr(host);
498*76404edcSAsim Jamshed 	dport = (dest_port == 0) ? htons(PORT_NUM) : htons(dest_port);
499*76404edcSAsim Jamshed 	saddr = INADDR_ANY;
500*76404edcSAsim Jamshed 
501*76404edcSAsim Jamshed 	if (total_flows < core_limit) {
502*76404edcSAsim Jamshed 		core_limit = total_flows;
503*76404edcSAsim Jamshed 	}
504*76404edcSAsim Jamshed 
505*76404edcSAsim Jamshed 	/* per-core concurrency = total_concurrency / # cores */
506*76404edcSAsim Jamshed 	if (total_concurrency > 0)
507*76404edcSAsim Jamshed 		concurrency = total_concurrency / core_limit;
508*76404edcSAsim Jamshed 
509*76404edcSAsim Jamshed 	/* set the max number of fds 3x larger than concurrency */
510*76404edcSAsim Jamshed 	max_fds = concurrency * 3;
511*76404edcSAsim Jamshed 
512*76404edcSAsim Jamshed 	TRACE_CONFIG("Application configuration:\n");
513*76404edcSAsim Jamshed 	TRACE_CONFIG("URL: %s\n", path);
514*76404edcSAsim Jamshed 	TRACE_CONFIG("# of total_flows: %d\n", total_flows);
515*76404edcSAsim Jamshed 	TRACE_CONFIG("# of cores: %d\n", core_limit);
516*76404edcSAsim Jamshed 	TRACE_CONFIG("Concurrency: %d\n", total_concurrency);
517*76404edcSAsim Jamshed 
518*76404edcSAsim Jamshed 	mtcp_getconf(&mcfg);
519*76404edcSAsim Jamshed 	mcfg.max_concurrency = max_fds;
520*76404edcSAsim Jamshed 	mcfg.max_num_buffers = max_fds;
521*76404edcSAsim Jamshed 	mtcp_setconf(&mcfg);
522*76404edcSAsim Jamshed 
523*76404edcSAsim Jamshed 	flow_per_thread = total_flows / core_limit;
524*76404edcSAsim Jamshed 	flow_remainder_cnt = total_flows % core_limit;
525*76404edcSAsim Jamshed 
526*76404edcSAsim Jamshed 	for (i = 0; i < MAX_CPUS; i++) {
527*76404edcSAsim Jamshed 		done[i] = FALSE;
528*76404edcSAsim Jamshed 		flows[i] = flow_per_thread;
529*76404edcSAsim Jamshed 
530*76404edcSAsim Jamshed 		if (flow_remainder_cnt-- > 0)
531*76404edcSAsim Jamshed 			flows[i]++;
532*76404edcSAsim Jamshed 	}
533*76404edcSAsim Jamshed 
534*76404edcSAsim Jamshed 	return;
535*76404edcSAsim Jamshed }
536*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
537*76404edcSAsim Jamshed static void
538*76404edcSAsim Jamshed InitWget(mctx_t mctx, void **app_ctx)
539*76404edcSAsim Jamshed {
540*76404edcSAsim Jamshed 	thread_context_t ctx;
541*76404edcSAsim Jamshed 	int ep;
542*76404edcSAsim Jamshed 
543*76404edcSAsim Jamshed 	assert(mctx);
544*76404edcSAsim Jamshed 
545*76404edcSAsim Jamshed 	int core = mctx->cpu;
546*76404edcSAsim Jamshed 
547*76404edcSAsim Jamshed 	ctx = CreateContext(mctx);
548*76404edcSAsim Jamshed 	if (!ctx)
549*76404edcSAsim Jamshed 		exit(-1);
550*76404edcSAsim Jamshed 	g_ctx[core] = ctx;
551*76404edcSAsim Jamshed 	g_stat[core] = &ctx->stat;
552*76404edcSAsim Jamshed 	srand(time(NULL));
553*76404edcSAsim Jamshed 
554*76404edcSAsim Jamshed 	mtcp_init_rss(mctx, saddr, IP_RANGE, daddr, dport);
555*76404edcSAsim Jamshed 
556*76404edcSAsim Jamshed 	if (flows[core] == 0) {
557*76404edcSAsim Jamshed 		TRACE_DBG("Application thread %d finished.\n", core);
558*76404edcSAsim Jamshed 		exit(-1);
559*76404edcSAsim Jamshed 	}
560*76404edcSAsim Jamshed 	ctx->target = flows[core];
561*76404edcSAsim Jamshed 
562*76404edcSAsim Jamshed 	/* Initialization */
563*76404edcSAsim Jamshed 	ctx->maxevents = max_fds * 3;
564*76404edcSAsim Jamshed 	ep = mtcp_epoll_create(mctx, ctx->maxevents);
565*76404edcSAsim Jamshed 	if (ep < 0) {
566*76404edcSAsim Jamshed 		TRACE_ERROR("Failed to create epoll struct!n");
567*76404edcSAsim Jamshed 		exit(EXIT_FAILURE);
568*76404edcSAsim Jamshed 	}
569*76404edcSAsim Jamshed 	ctx->events = (struct mtcp_epoll_event *)
570*76404edcSAsim Jamshed 			calloc(ctx->maxevents, sizeof(struct mtcp_epoll_event));
571*76404edcSAsim Jamshed 	if (!ctx->events) {
572*76404edcSAsim Jamshed 		TRACE_ERROR("Failed to allocate events!\n");
573*76404edcSAsim Jamshed 		exit(EXIT_FAILURE);
574*76404edcSAsim Jamshed 	}
575*76404edcSAsim Jamshed 	ctx->ep = ep;
576*76404edcSAsim Jamshed 
577*76404edcSAsim Jamshed 	ctx->wvars = (struct wget_vars *)calloc(max_fds, sizeof(struct wget_vars));
578*76404edcSAsim Jamshed 	if (!ctx->wvars) {
579*76404edcSAsim Jamshed 		TRACE_ERROR("Failed to create wget variables!\n");
580*76404edcSAsim Jamshed 		exit(EXIT_FAILURE);
581*76404edcSAsim Jamshed 	}
582*76404edcSAsim Jamshed 
583*76404edcSAsim Jamshed 	ctx->started = ctx->done = ctx->pending = 0;
584*76404edcSAsim Jamshed 	ctx->errors = ctx->incompletes = 0;
585*76404edcSAsim Jamshed 
586*76404edcSAsim Jamshed 	*app_ctx = ctx;
587*76404edcSAsim Jamshed 
588*76404edcSAsim Jamshed 	return;
589*76404edcSAsim Jamshed }
590*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
591*76404edcSAsim Jamshed static void
592*76404edcSAsim Jamshed RunWget(mctx_t mctx, void **app_ctx)
593*76404edcSAsim Jamshed {
594*76404edcSAsim Jamshed 	struct in_addr daddr_in;
595*76404edcSAsim Jamshed 	struct timeval cur_tv, prev_tv;
596*76404edcSAsim Jamshed 	int nevents;
597*76404edcSAsim Jamshed 	int i;
598*76404edcSAsim Jamshed 
599*76404edcSAsim Jamshed 	assert(mctx);
600*76404edcSAsim Jamshed 	assert(*app_ctx);
601*76404edcSAsim Jamshed 
602*76404edcSAsim Jamshed 	thread_context_t ctx = *app_ctx;
603*76404edcSAsim Jamshed 	int core = ctx->core;
604*76404edcSAsim Jamshed 
605*76404edcSAsim Jamshed 	daddr_in.s_addr = daddr;
606*76404edcSAsim Jamshed 	fprintf(stderr, "Thread %d handles %d flows. connecting to %s:%u\n",
607*76404edcSAsim Jamshed 			core, flows[core], inet_ntoa(daddr_in), ntohs(dport));
608*76404edcSAsim Jamshed 
609*76404edcSAsim Jamshed 	gettimeofday(&cur_tv, NULL);
610*76404edcSAsim Jamshed 	prev_tv = cur_tv;
611*76404edcSAsim Jamshed 
612*76404edcSAsim Jamshed 	while (!done[core]) {
613*76404edcSAsim Jamshed 		gettimeofday(&cur_tv, NULL);
614*76404edcSAsim Jamshed 
615*76404edcSAsim Jamshed 		/* print statistics every second */
616*76404edcSAsim Jamshed 		if (core == 0 && cur_tv.tv_sec > prev_tv.tv_sec) {
617*76404edcSAsim Jamshed 			PrintStats();
618*76404edcSAsim Jamshed 			prev_tv = cur_tv;
619*76404edcSAsim Jamshed 		}
620*76404edcSAsim Jamshed 
621*76404edcSAsim Jamshed 		while (/*ctx->pending*/ mtcp_get_connection_cnt(ctx->mctx) < concurrency && ctx->started < ctx->target) {
622*76404edcSAsim Jamshed 			if (CreateConnection(ctx) < 0) {
623*76404edcSAsim Jamshed 				done[core] = TRUE;
624*76404edcSAsim Jamshed 				break;
625*76404edcSAsim Jamshed 			}
626*76404edcSAsim Jamshed 		}
627*76404edcSAsim Jamshed 
628*76404edcSAsim Jamshed 		nevents = mtcp_epoll_wait(mctx, ctx->ep,
629*76404edcSAsim Jamshed 				ctx->events, ctx->maxevents, ctx->pending ? -1 : 10);
630*76404edcSAsim Jamshed 		ctx->stat.waits++;
631*76404edcSAsim Jamshed 
632*76404edcSAsim Jamshed 		if (nevents < 0) {
633*76404edcSAsim Jamshed 			if (errno != EINTR) {
634*76404edcSAsim Jamshed 				TRACE_ERROR("mtcp_epoll_wait failed! ret: %d\n", nevents);
635*76404edcSAsim Jamshed 			}
636*76404edcSAsim Jamshed 			done[core] = TRUE;
637*76404edcSAsim Jamshed 			break;
638*76404edcSAsim Jamshed 		} else {
639*76404edcSAsim Jamshed 			ctx->stat.events += nevents;
640*76404edcSAsim Jamshed 		}
641*76404edcSAsim Jamshed 
642*76404edcSAsim Jamshed 		for (i = 0; i < nevents; i++) {
643*76404edcSAsim Jamshed 
644*76404edcSAsim Jamshed 			if (ctx->events[i].events & MOS_EPOLLERR) {
645*76404edcSAsim Jamshed 				int err;
646*76404edcSAsim Jamshed 				socklen_t len = sizeof(err);
647*76404edcSAsim Jamshed 
648*76404edcSAsim Jamshed 				TRACE_APP("[CPU %d] Error on socket %d\n",
649*76404edcSAsim Jamshed 						core, ctx->events[i].data.sockid);
650*76404edcSAsim Jamshed 				ctx->stat.errors++;
651*76404edcSAsim Jamshed 				ctx->errors++;
652*76404edcSAsim Jamshed 				if (mtcp_getsockopt(mctx, ctx->events[i].data.sock,
653*76404edcSAsim Jamshed 							SOL_SOCKET, SO_ERROR, (void *)&err, &len) == 0) {
654*76404edcSAsim Jamshed 					if (err == ETIMEDOUT)
655*76404edcSAsim Jamshed 						ctx->stat.timedout++;
656*76404edcSAsim Jamshed 				}
657*76404edcSAsim Jamshed 				CloseConnection(ctx, ctx->events[i].data.sock);
658*76404edcSAsim Jamshed 
659*76404edcSAsim Jamshed 			} else if (ctx->events[i].events & MOS_EPOLLIN) {
660*76404edcSAsim Jamshed 				HandleReadEvent(ctx,
661*76404edcSAsim Jamshed 						ctx->events[i].data.sock,
662*76404edcSAsim Jamshed 						&ctx->wvars[ctx->events[i].data.sock]);
663*76404edcSAsim Jamshed 
664*76404edcSAsim Jamshed 			} else if (ctx->events[i].events == MOS_EPOLLOUT) {
665*76404edcSAsim Jamshed 				struct wget_vars *wv = &ctx->wvars[ctx->events[i].data.sock];
666*76404edcSAsim Jamshed 
667*76404edcSAsim Jamshed 				if (!wv->request_sent) {
668*76404edcSAsim Jamshed 					SendHTTPRequest(ctx, ctx->events[i].data.sock, wv);
669*76404edcSAsim Jamshed 				} else {
670*76404edcSAsim Jamshed 					//TRACE_DBG("Request already sent.\n");
671*76404edcSAsim Jamshed 				}
672*76404edcSAsim Jamshed 
673*76404edcSAsim Jamshed 			} else {
674*76404edcSAsim Jamshed 				TRACE_ERROR("Socket %d: event: %s\n",
675*76404edcSAsim Jamshed 						ctx->events[i].data.sock,
676*76404edcSAsim Jamshed 						EventToString(ctx->events[i].events));
677*76404edcSAsim Jamshed 				assert(0);
678*76404edcSAsim Jamshed 			}
679*76404edcSAsim Jamshed 		}
680*76404edcSAsim Jamshed 
681*76404edcSAsim Jamshed 		if (ctx->done >= ctx->target) {
682*76404edcSAsim Jamshed 			fprintf(stdout, "Completed %d connections, "
683*76404edcSAsim Jamshed 					"errors: %d incompletes: %d\n",
684*76404edcSAsim Jamshed 					ctx->done, ctx->errors, ctx->incompletes);
685*76404edcSAsim Jamshed 			break;
686*76404edcSAsim Jamshed 		}
687*76404edcSAsim Jamshed 	}
688*76404edcSAsim Jamshed 
689*76404edcSAsim Jamshed 	TRACE_INFO("Wget thread %d waiting for mtcp to be destroyed.\n", core);
690*76404edcSAsim Jamshed 
691*76404edcSAsim Jamshed 	g_stat[core] = NULL;
692*76404edcSAsim Jamshed 	g_ctx[core] = NULL;
693*76404edcSAsim Jamshed 	DestroyContext(ctx);
694*76404edcSAsim Jamshed 
695*76404edcSAsim Jamshed 	return;
696*76404edcSAsim Jamshed }
697*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
698*76404edcSAsim Jamshed void
699*76404edcSAsim Jamshed RunApplication(mctx_t mctx)
700*76404edcSAsim Jamshed {
701*76404edcSAsim Jamshed 	void *app_ctx;
702*76404edcSAsim Jamshed 
703*76404edcSAsim Jamshed 	app_ctx = (void *)calloc(1, sizeof(void *));
704*76404edcSAsim Jamshed 	if (!app_ctx) {
705*76404edcSAsim Jamshed 		TRACE_ERROR("calloc failure\n");
706*76404edcSAsim Jamshed 		return;
707*76404edcSAsim Jamshed 	}
708*76404edcSAsim Jamshed 
709*76404edcSAsim Jamshed 	TRACE_INFO("run application on core %d\n", mctx->cpu);
710*76404edcSAsim Jamshed 	InitWget(mctx, &(app_ctx));
711*76404edcSAsim Jamshed 	RunWget(mctx, &(app_ctx));
712*76404edcSAsim Jamshed }
713*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
714*76404edcSAsim Jamshed void *
715*76404edcSAsim Jamshed RunMTCP(void *arg)
716*76404edcSAsim Jamshed {
717*76404edcSAsim Jamshed 	int core = *(int *)arg;
718*76404edcSAsim Jamshed 	mctx_t mctx;
719*76404edcSAsim Jamshed 
720*76404edcSAsim Jamshed 	mtcp_core_affinitize(core);
721*76404edcSAsim Jamshed 
722*76404edcSAsim Jamshed 	/* mTCP Initialization */
723*76404edcSAsim Jamshed 	mctx = mtcp_create_context(core);
724*76404edcSAsim Jamshed 	if (!mctx) {
725*76404edcSAsim Jamshed 		pthread_exit(NULL);
726*76404edcSAsim Jamshed 		TRACE_ERROR("Failed to craete mtcp context.\n");
727*76404edcSAsim Jamshed 		return NULL;
728*76404edcSAsim Jamshed 	}
729*76404edcSAsim Jamshed 
730*76404edcSAsim Jamshed 	/* Run application here */
731*76404edcSAsim Jamshed 	RunApplication(mctx);
732*76404edcSAsim Jamshed 
733*76404edcSAsim Jamshed 	/* mTCP Tear Down */
734*76404edcSAsim Jamshed 	mtcp_destroy_context(mctx);
735*76404edcSAsim Jamshed 	pthread_exit(NULL);
736*76404edcSAsim Jamshed 
737*76404edcSAsim Jamshed 	return NULL;
738*76404edcSAsim Jamshed }
739*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
740*76404edcSAsim Jamshed int
741*76404edcSAsim Jamshed main(int argc, char **argv)
742*76404edcSAsim Jamshed {
743*76404edcSAsim Jamshed 	int ret, i;
744*76404edcSAsim Jamshed 	int cores[MAX_CPUS];
745*76404edcSAsim Jamshed 	char *fname = "config/mos.conf";
746*76404edcSAsim Jamshed 
747*76404edcSAsim Jamshed 	int opt;
748*76404edcSAsim Jamshed 	while ((opt = getopt(argc, argv, "f:")) != -1) {
749*76404edcSAsim Jamshed 		switch (opt) {
750*76404edcSAsim Jamshed 			case 'f':
751*76404edcSAsim Jamshed 				fname = optarg;
752*76404edcSAsim Jamshed 				break;
753*76404edcSAsim Jamshed 			default:
754*76404edcSAsim Jamshed 				printf("Usage: %s [-f config_file]\n", argv[0]);
755*76404edcSAsim Jamshed 				return 0;
756*76404edcSAsim Jamshed 		}
757*76404edcSAsim Jamshed 
758*76404edcSAsim Jamshed 	}
759*76404edcSAsim Jamshed 
760*76404edcSAsim Jamshed 	core_limit = sysconf(_SC_NPROCESSORS_ONLN);
761*76404edcSAsim Jamshed 
762*76404edcSAsim Jamshed 	ret = mtcp_init(fname);
763*76404edcSAsim Jamshed 	if (ret) {
764*76404edcSAsim Jamshed 		TRACE_ERROR("Failed to initialize mtcp.\n");
765*76404edcSAsim Jamshed 		exit(EXIT_FAILURE);
766*76404edcSAsim Jamshed 	}
767*76404edcSAsim Jamshed 
768*76404edcSAsim Jamshed 	mtcp_getconf(&g_mcfg);
769*76404edcSAsim Jamshed 
770*76404edcSAsim Jamshed 	core_limit = g_mcfg.num_cores;
771*76404edcSAsim Jamshed 
772*76404edcSAsim Jamshed 	GlbInitWget();
773*76404edcSAsim Jamshed 
774*76404edcSAsim Jamshed 	for (i = 0; i < core_limit; i++) {
775*76404edcSAsim Jamshed 		cores[i] = i;
776*76404edcSAsim Jamshed 
777*76404edcSAsim Jamshed 		/* Run mtcp thread */
778*76404edcSAsim Jamshed 		if ((g_mcfg.cpu_mask & (1L << i)) &&
779*76404edcSAsim Jamshed 			pthread_create(&mtcp_thread[i], NULL, RunMTCP, (void *)&cores[i])) {
780*76404edcSAsim Jamshed 			perror("pthread_create");
781*76404edcSAsim Jamshed 			TRACE_ERROR("Failed to create msg_test thread.\n");
782*76404edcSAsim Jamshed 			exit(-1);
783*76404edcSAsim Jamshed 		}
784*76404edcSAsim Jamshed 	}
785*76404edcSAsim Jamshed 
786*76404edcSAsim Jamshed 	for (i = 0; i < core_limit; i++) {
787*76404edcSAsim Jamshed 		if (g_mcfg.cpu_mask & (1L << i))
788*76404edcSAsim Jamshed 			pthread_join(mtcp_thread[i], NULL);
789*76404edcSAsim Jamshed 		TRACE_INFO("Message test thread %d joined.\n", i);
790*76404edcSAsim Jamshed 	}
791*76404edcSAsim Jamshed 
792*76404edcSAsim Jamshed 	mtcp_destroy();
793*76404edcSAsim Jamshed 	return 0;
794*76404edcSAsim Jamshed }
795*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
796