176404edcSAsim Jamshed #include <stdio.h>
276404edcSAsim Jamshed #include <stdlib.h>
376404edcSAsim Jamshed #include <string.h>
476404edcSAsim Jamshed #include <unistd.h>
576404edcSAsim Jamshed #include <stdint.h>
676404edcSAsim Jamshed #include <time.h>
776404edcSAsim Jamshed #include <sys/time.h>
876404edcSAsim Jamshed #include <sys/types.h>
976404edcSAsim Jamshed #include <sys/stat.h>
1076404edcSAsim Jamshed #include <fcntl.h>
1176404edcSAsim Jamshed #include <pthread.h>
1276404edcSAsim Jamshed #include <signal.h>
1376404edcSAsim Jamshed #include <sys/socket.h>
1476404edcSAsim Jamshed #include <netinet/in.h>
1576404edcSAsim Jamshed #include <arpa/inet.h>
1676404edcSAsim Jamshed #include <sys/queue.h>
1776404edcSAsim Jamshed #include <assert.h>
1876404edcSAsim Jamshed 
1976404edcSAsim Jamshed #include <mos_api.h>
2076404edcSAsim Jamshed #include "cpu.h"
2176404edcSAsim Jamshed #include "rss.h"
2276404edcSAsim Jamshed #include "http_parsing.h"
2376404edcSAsim Jamshed #include "debug.h"
2476404edcSAsim Jamshed #include "applib.h"
2576404edcSAsim Jamshed 
2676404edcSAsim Jamshed #define CONFIG_FILE       "config/epwget.conf"
2776404edcSAsim Jamshed static struct conf_var g_conf[] = {
2876404edcSAsim Jamshed 	{ "url",               {0} },
2976404edcSAsim Jamshed 	{ "total_flows",       {0} },
3076404edcSAsim Jamshed 	{ "core_limit",        {0} },
3176404edcSAsim Jamshed 	{ "total_concurrency", {0} },
3276404edcSAsim Jamshed 	{ "dest_port",         {0} },
3376404edcSAsim Jamshed };
3476404edcSAsim Jamshed #define NUM_CONF_VAR (sizeof(g_conf) / sizeof(struct conf_var))
3576404edcSAsim Jamshed 
3676404edcSAsim Jamshed #define PORT_NUM 80
3776404edcSAsim Jamshed //#define PORT_NUM 3333
3876404edcSAsim Jamshed 
3976404edcSAsim Jamshed #define MAX_URL_LEN 128
4076404edcSAsim Jamshed #define MAX_FILE_LEN 128
4176404edcSAsim Jamshed #define HTTP_HEADER_LEN 1024
4276404edcSAsim Jamshed 
4376404edcSAsim Jamshed #define IP_RANGE 1
4476404edcSAsim Jamshed #define MAX_IP_STR_LEN 16
4576404edcSAsim Jamshed 
4676404edcSAsim Jamshed #define BUF_SIZE (8*1024)
4776404edcSAsim Jamshed 
4876404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
4976404edcSAsim Jamshed struct mtcp_conf g_mcfg;
5076404edcSAsim Jamshed static pthread_t mtcp_thread[MAX_CPUS];
5176404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
5276404edcSAsim Jamshed static mctx_t g_mctx[MAX_CPUS];
5376404edcSAsim Jamshed static int done[MAX_CPUS];
5476404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
5576404edcSAsim Jamshed static int num_cores;
5676404edcSAsim Jamshed static int core_limit;
5776404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
5876404edcSAsim Jamshed static int fio = FALSE;
5976404edcSAsim Jamshed static char outfile[MAX_FILE_LEN + 1];
6076404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
6176404edcSAsim Jamshed static char host[MAX_IP_STR_LEN + 1];
6276404edcSAsim Jamshed static char path[MAX_URL_LEN + 1];
6376404edcSAsim Jamshed static in_addr_t daddr;
6476404edcSAsim Jamshed static in_port_t dport;
6576404edcSAsim Jamshed static in_addr_t saddr;
6676404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
6776404edcSAsim Jamshed static int total_flows;
6876404edcSAsim Jamshed static int flows[MAX_CPUS];
6976404edcSAsim Jamshed static int flowcnt = 0;
7076404edcSAsim Jamshed static int concurrency;
7176404edcSAsim Jamshed static int max_fds;
7276404edcSAsim Jamshed static uint16_t dest_port;
7376404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
7476404edcSAsim Jamshed struct wget_stat
7576404edcSAsim Jamshed {
7676404edcSAsim Jamshed 	uint64_t waits;
7776404edcSAsim Jamshed 	uint64_t events;
7876404edcSAsim Jamshed 	uint64_t connects;
7976404edcSAsim Jamshed 	uint64_t reads;
8076404edcSAsim Jamshed 	uint64_t writes;
8176404edcSAsim Jamshed 	uint64_t completes;
8276404edcSAsim Jamshed 
8376404edcSAsim Jamshed 	uint64_t errors;
8476404edcSAsim Jamshed 	uint64_t timedout;
8576404edcSAsim Jamshed 
8676404edcSAsim Jamshed 	uint64_t sum_resp_time;
8776404edcSAsim Jamshed 	uint64_t max_resp_time;
8876404edcSAsim Jamshed };
8976404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
9076404edcSAsim Jamshed struct thread_context
9176404edcSAsim Jamshed {
9276404edcSAsim Jamshed 	int core;
9376404edcSAsim Jamshed 
9476404edcSAsim Jamshed 	mctx_t mctx;
9576404edcSAsim Jamshed 	int ep;
9676404edcSAsim Jamshed 	struct wget_vars *wvars;
9776404edcSAsim Jamshed 
9876404edcSAsim Jamshed 	int target;
9976404edcSAsim Jamshed 	int started;
10076404edcSAsim Jamshed 	int errors;
10176404edcSAsim Jamshed 	int incompletes;
10276404edcSAsim Jamshed 	int done;
10376404edcSAsim Jamshed 	int pending;
10476404edcSAsim Jamshed 
10576404edcSAsim Jamshed 	int maxevents;
10676404edcSAsim Jamshed 	struct mtcp_epoll_event *events;
10776404edcSAsim Jamshed 
10876404edcSAsim Jamshed 	struct wget_stat stat;
10976404edcSAsim Jamshed };
11076404edcSAsim Jamshed typedef struct thread_context* thread_context_t;
11176404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
11276404edcSAsim Jamshed struct wget_vars
11376404edcSAsim Jamshed {
11476404edcSAsim Jamshed 	int request_sent;
11576404edcSAsim Jamshed 
11676404edcSAsim Jamshed 	char response[HTTP_HEADER_LEN];
11776404edcSAsim Jamshed 	int resp_len;
11876404edcSAsim Jamshed 	int headerset;
11976404edcSAsim Jamshed 	uint32_t header_len;
12076404edcSAsim Jamshed 	uint64_t file_len;
12176404edcSAsim Jamshed 	uint64_t recv;
12276404edcSAsim Jamshed 	uint64_t write;
12376404edcSAsim Jamshed 
12476404edcSAsim Jamshed 	struct timeval t_start;
12576404edcSAsim Jamshed 	struct timeval t_end;
12676404edcSAsim Jamshed 
12776404edcSAsim Jamshed 	int fd;
12876404edcSAsim Jamshed };
12976404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
130*1c9bc629SAsim Jamshed static struct thread_context *g_ctx[MAX_CPUS] = {0};
131*1c9bc629SAsim Jamshed static struct wget_stat *g_stat[MAX_CPUS] = {0};
13276404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
13376404edcSAsim Jamshed static thread_context_t
13476404edcSAsim Jamshed CreateContext(mctx_t mctx)
13576404edcSAsim Jamshed {
13676404edcSAsim Jamshed 	thread_context_t ctx;
13776404edcSAsim Jamshed 
13876404edcSAsim Jamshed 	ctx = (thread_context_t)calloc(1, sizeof(struct thread_context));
13976404edcSAsim Jamshed 	if (!ctx) {
14076404edcSAsim Jamshed 		perror("malloc");
14176404edcSAsim Jamshed 		TRACE_ERROR("Failed to allocate memory for thread context.\n");
14276404edcSAsim Jamshed 		return NULL;
14376404edcSAsim Jamshed 	}
14476404edcSAsim Jamshed 
14576404edcSAsim Jamshed 	ctx->mctx = mctx;
14676404edcSAsim Jamshed 	ctx->core = mctx->cpu;
14776404edcSAsim Jamshed 
14876404edcSAsim Jamshed 	g_mctx[ctx->core] = mctx;
14976404edcSAsim Jamshed 
15076404edcSAsim Jamshed 	return ctx;
15176404edcSAsim Jamshed }
15276404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
15376404edcSAsim Jamshed static void
15476404edcSAsim Jamshed DestroyContext(thread_context_t ctx)
15576404edcSAsim Jamshed {
156*1c9bc629SAsim Jamshed 	g_stat[ctx->core] = NULL;
15776404edcSAsim Jamshed 	free(ctx);
15876404edcSAsim Jamshed }
15976404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
16076404edcSAsim Jamshed static inline int
16176404edcSAsim Jamshed CreateConnection(thread_context_t ctx)
16276404edcSAsim Jamshed {
16376404edcSAsim Jamshed 	mctx_t mctx = ctx->mctx;
16476404edcSAsim Jamshed 	struct mtcp_epoll_event ev;
16576404edcSAsim Jamshed 	struct sockaddr_in addr;
16676404edcSAsim Jamshed 	int sockid;
16776404edcSAsim Jamshed 	int ret;
16876404edcSAsim Jamshed 
16976404edcSAsim Jamshed 	assert(mctx);
17076404edcSAsim Jamshed 
17176404edcSAsim Jamshed 	errno = 0;
17276404edcSAsim Jamshed 	sockid = mtcp_socket(mctx, AF_INET, SOCK_STREAM, 0);
17376404edcSAsim Jamshed 	if (sockid < 0) {
17476404edcSAsim Jamshed 		TRACE_INFO("Failed to create socket! (%s)\n",
17576404edcSAsim Jamshed 			   strerror(errno));
17676404edcSAsim Jamshed 		return -1;
17776404edcSAsim Jamshed 	}
17876404edcSAsim Jamshed 	memset(&ctx->wvars[sockid], 0, sizeof(struct wget_vars));
17976404edcSAsim Jamshed 	ret = mtcp_setsock_nonblock(mctx, sockid);
18076404edcSAsim Jamshed 	if (ret < 0) {
18176404edcSAsim Jamshed 		TRACE_ERROR("Failed to set socket in nonblocking mode.\n");
18276404edcSAsim Jamshed 		exit(-1);
18376404edcSAsim Jamshed 	}
18476404edcSAsim Jamshed 
18576404edcSAsim Jamshed 	addr.sin_family = AF_INET;
18676404edcSAsim Jamshed 	addr.sin_addr.s_addr = daddr;
18776404edcSAsim Jamshed 	addr.sin_port = dport;
18876404edcSAsim Jamshed 
18976404edcSAsim Jamshed 	ret = mtcp_connect(mctx, sockid,
19076404edcSAsim Jamshed 			(struct sockaddr *)&addr, sizeof(struct sockaddr_in));
19176404edcSAsim Jamshed 	if (ret < 0) {
19276404edcSAsim Jamshed 		if (errno != EINPROGRESS) {
19376404edcSAsim Jamshed 			perror("mtcp_connect");
19476404edcSAsim Jamshed 			mtcp_close(mctx, sockid);
19576404edcSAsim Jamshed 			return -1;
19676404edcSAsim Jamshed 		}
19776404edcSAsim Jamshed 	}
19876404edcSAsim Jamshed 
19976404edcSAsim Jamshed 	ctx->started++;
20076404edcSAsim Jamshed 	ctx->pending++;
20176404edcSAsim Jamshed 	ctx->stat.connects++;
20276404edcSAsim Jamshed 
20376404edcSAsim Jamshed 	ev.events = MOS_EPOLLOUT;
20476404edcSAsim Jamshed 	ev.data.sock = sockid;
20576404edcSAsim Jamshed 	mtcp_epoll_ctl(mctx, ctx->ep, MOS_EPOLL_CTL_ADD, sockid, &ev);
20676404edcSAsim Jamshed 
20776404edcSAsim Jamshed 	return sockid;
20876404edcSAsim Jamshed }
20976404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
21076404edcSAsim Jamshed static inline void
21176404edcSAsim Jamshed CloseConnection(thread_context_t ctx, int sockid)
21276404edcSAsim Jamshed {
21376404edcSAsim Jamshed 	mtcp_epoll_ctl(ctx->mctx, ctx->ep, MOS_EPOLL_CTL_DEL, sockid, NULL);
21476404edcSAsim Jamshed 	mtcp_close(ctx->mctx, sockid);
21576404edcSAsim Jamshed 	ctx->pending--;
21676404edcSAsim Jamshed 	ctx->done++;
21776404edcSAsim Jamshed 	assert(ctx->pending >= 0);
21876404edcSAsim Jamshed 	while (/*ctx->pending*/ mtcp_get_connection_cnt(ctx->mctx) < concurrency && ctx->started < ctx->target) {
21976404edcSAsim Jamshed 		if (CreateConnection(ctx) < 0) {
22076404edcSAsim Jamshed 			done[ctx->core] = TRUE;
22176404edcSAsim Jamshed 			break;
22276404edcSAsim Jamshed 		}
22376404edcSAsim Jamshed 	}
22476404edcSAsim Jamshed }
22576404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
22676404edcSAsim Jamshed static inline int
22776404edcSAsim Jamshed SendHTTPRequest(thread_context_t ctx, int sockid, struct wget_vars *wv)
22876404edcSAsim Jamshed {
22976404edcSAsim Jamshed 	char request[HTTP_HEADER_LEN];
23076404edcSAsim Jamshed 	struct mtcp_epoll_event ev;
23176404edcSAsim Jamshed 	int wr;
23276404edcSAsim Jamshed 	int len;
23376404edcSAsim Jamshed 
23476404edcSAsim Jamshed 	wv->headerset = FALSE;
23576404edcSAsim Jamshed 	wv->recv = 0;
23676404edcSAsim Jamshed 	wv->header_len = wv->file_len = 0;
23776404edcSAsim Jamshed 
23876404edcSAsim Jamshed 	snprintf(request, HTTP_HEADER_LEN, "GET %s HTTP/1.0\r\n"
23976404edcSAsim Jamshed 			"User-Agent: Wget/1.12 (linux-gnu)\r\n"
24076404edcSAsim Jamshed 			"Accept: */*\r\n"
24176404edcSAsim Jamshed 			"Host: %s\r\n"
24276404edcSAsim Jamshed //			"Connection: Keep-Alive\r\n\r\n",
24376404edcSAsim Jamshed 			"Connection: Close\r\n\r\n",
24476404edcSAsim Jamshed 			path, host);
24576404edcSAsim Jamshed 	len = strlen(request);
24676404edcSAsim Jamshed 
24776404edcSAsim Jamshed 	wr = mtcp_write(ctx->mctx, sockid, request, len);
24876404edcSAsim Jamshed 	if (wr < len) {
24976404edcSAsim Jamshed 		TRACE_ERROR("Socket %d: Sending HTTP request failed. "
25076404edcSAsim Jamshed 				"try: %d, sent: %d\n", sockid, len, wr);
25176404edcSAsim Jamshed 		CloseConnection(ctx, sockid);
25276404edcSAsim Jamshed 	}
25376404edcSAsim Jamshed 	ctx->stat.writes += wr;
25476404edcSAsim Jamshed 	TRACE_APP("Socket %d HTTP Request of %d bytes. sent.\n", sockid, wr);
25576404edcSAsim Jamshed 	wv->request_sent = TRUE;
25676404edcSAsim Jamshed 
25776404edcSAsim Jamshed 	ev.events = MOS_EPOLLIN;
25876404edcSAsim Jamshed 	ev.data.sock = sockid;
25976404edcSAsim Jamshed 	mtcp_epoll_ctl(ctx->mctx, ctx->ep, MOS_EPOLL_CTL_MOD, sockid, &ev);
26076404edcSAsim Jamshed 
26176404edcSAsim Jamshed 	gettimeofday(&wv->t_start, NULL);
26276404edcSAsim Jamshed 
26376404edcSAsim Jamshed 	char fname[MAX_FILE_LEN + 1];
26476404edcSAsim Jamshed 	if (fio) {
26576404edcSAsim Jamshed 		snprintf(fname, MAX_FILE_LEN, "%s.%d", outfile, flowcnt++);
26676404edcSAsim Jamshed 		wv->fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
26776404edcSAsim Jamshed 		if (wv->fd < 0) {
26876404edcSAsim Jamshed 			TRACE_APP("Failed to open file descriptor for %s\n", fname);
26976404edcSAsim Jamshed 			exit(1);
27076404edcSAsim Jamshed 		}
27176404edcSAsim Jamshed 	}
27276404edcSAsim Jamshed 
27376404edcSAsim Jamshed 	return 0;
27476404edcSAsim Jamshed }
27576404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
27676404edcSAsim Jamshed static inline int
27776404edcSAsim Jamshed DownloadComplete(thread_context_t ctx, int sockid, struct wget_vars *wv)
27876404edcSAsim Jamshed {
27976404edcSAsim Jamshed #ifdef APP
28076404edcSAsim Jamshed 	mctx_t mctx = ctx->mctx;
28176404edcSAsim Jamshed #endif
28276404edcSAsim Jamshed 	uint64_t tdiff;
28376404edcSAsim Jamshed 
28476404edcSAsim Jamshed 	TRACE_APP("Socket %d File download complete!\n", sockid);
28576404edcSAsim Jamshed 	gettimeofday(&wv->t_end, NULL);
28676404edcSAsim Jamshed 	CloseConnection(ctx, sockid);
28776404edcSAsim Jamshed 	ctx->stat.completes++;
28876404edcSAsim Jamshed 
28976404edcSAsim Jamshed 	if (wv->recv - wv->header_len != wv->file_len) {
29076404edcSAsim Jamshed 		fprintf(stderr, "Response size mismatch! "
29176404edcSAsim Jamshed 						"actual recved: %ld,  expected to recved: %ld\n",
29276404edcSAsim Jamshed 						wv->recv-wv->header_len, wv->file_len);
29376404edcSAsim Jamshed 	}
29476404edcSAsim Jamshed 
29576404edcSAsim Jamshed 	tdiff = (wv->t_end.tv_sec - wv->t_start.tv_sec) * 1000000 +
29676404edcSAsim Jamshed 			(wv->t_end.tv_usec - wv->t_start.tv_usec);
29776404edcSAsim Jamshed 	TRACE_APP("Socket %d Total received bytes: %lu (%luMB)\n",
29876404edcSAsim Jamshed 			sockid, wv->recv, wv->recv / 1000000);
29976404edcSAsim Jamshed 	TRACE_APP("Socket %d Total spent time: %lu us\n", sockid, tdiff);
30076404edcSAsim Jamshed 	if (tdiff > 0) {
30176404edcSAsim Jamshed 		TRACE_APP("Socket %d Average bandwidth: %lf[MB/s]\n",
30276404edcSAsim Jamshed 				sockid, (double)wv->recv / tdiff);
30376404edcSAsim Jamshed 	}
30476404edcSAsim Jamshed 	ctx->stat.sum_resp_time += tdiff;
30576404edcSAsim Jamshed 	if (tdiff > ctx->stat.max_resp_time)
30676404edcSAsim Jamshed 		ctx->stat.max_resp_time = tdiff;
30776404edcSAsim Jamshed 
30876404edcSAsim Jamshed 	if (fio && wv->fd > 0)
30976404edcSAsim Jamshed 		close(wv->fd);
31076404edcSAsim Jamshed 
31176404edcSAsim Jamshed 	return 0;
31276404edcSAsim Jamshed }
31376404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
31476404edcSAsim Jamshed static inline int
31576404edcSAsim Jamshed HandleReadEvent(thread_context_t ctx, int sockid, struct wget_vars *wv)
31676404edcSAsim Jamshed {
31776404edcSAsim Jamshed 	mctx_t mctx = ctx->mctx;
31876404edcSAsim Jamshed 	char buf[BUF_SIZE];
31976404edcSAsim Jamshed 	char *pbuf;
32076404edcSAsim Jamshed 	int rd, copy_len;
32176404edcSAsim Jamshed 
32276404edcSAsim Jamshed 	rd = 1;
32376404edcSAsim Jamshed 	while (rd > 0) {
32476404edcSAsim Jamshed 		rd = mtcp_read(mctx, sockid, buf, BUF_SIZE);
32576404edcSAsim Jamshed 		if (rd <= 0)
32676404edcSAsim Jamshed 			break;
32776404edcSAsim Jamshed 		ctx->stat.reads += rd;
32876404edcSAsim Jamshed 
32976404edcSAsim Jamshed 		TRACE_APP("Socket %d: mtcp_read ret: %d, total_recv: %lu, "
33076404edcSAsim Jamshed 				"header_set: %d, header_len: %u, file_len: %lu\n",
33176404edcSAsim Jamshed 				sockid, rd, wv->recv + rd,
33276404edcSAsim Jamshed 				wv->headerset, wv->header_len, wv->file_len);
33376404edcSAsim Jamshed 
33476404edcSAsim Jamshed 		pbuf = buf;
33576404edcSAsim Jamshed 		if (!wv->headerset) {
33676404edcSAsim Jamshed 			copy_len = MIN(rd, HTTP_HEADER_LEN - wv->resp_len);
33776404edcSAsim Jamshed 			memcpy(wv->response + wv->resp_len, buf, copy_len);
33876404edcSAsim Jamshed 			wv->resp_len += copy_len;
33976404edcSAsim Jamshed 			wv->header_len = find_http_header(wv->response, wv->resp_len);
34076404edcSAsim Jamshed 			if (wv->header_len > 0) {
34176404edcSAsim Jamshed 				wv->response[wv->header_len] = '\0';
34276404edcSAsim Jamshed 				wv->file_len = http_header_long_val(wv->response,
34376404edcSAsim Jamshed 						CONTENT_LENGTH_HDR, sizeof(CONTENT_LENGTH_HDR) - 1);
34476404edcSAsim Jamshed 				TRACE_APP("Socket %d Parsed response header. "
34576404edcSAsim Jamshed 						"Header length: %u, File length: %lu (%luMB)\n",
34676404edcSAsim Jamshed 						sockid, wv->header_len,
34776404edcSAsim Jamshed 						wv->file_len, wv->file_len / 1024 / 1024);
34876404edcSAsim Jamshed 				wv->headerset = TRUE;
34976404edcSAsim Jamshed 				wv->recv += (rd - (wv->resp_len - wv->header_len));
35076404edcSAsim Jamshed 
35176404edcSAsim Jamshed 				pbuf += (rd - (wv->resp_len - wv->header_len));
352d8823779SAsim Jamshed 				rd = (wv->resp_len - wv->header_len);
35376404edcSAsim Jamshed 
35476404edcSAsim Jamshed 			} else {
35576404edcSAsim Jamshed 				/* failed to parse response header */
35676404edcSAsim Jamshed 				wv->recv += rd;
35776404edcSAsim Jamshed 				rd = 0;
35876404edcSAsim Jamshed 				ctx->stat.errors++;
35976404edcSAsim Jamshed 				ctx->errors++;
36076404edcSAsim Jamshed 				CloseConnection(ctx, sockid);
36176404edcSAsim Jamshed 				return 0;
36276404edcSAsim Jamshed 			}
36376404edcSAsim Jamshed 		}
36476404edcSAsim Jamshed 		wv->recv += rd;
36576404edcSAsim Jamshed 
36676404edcSAsim Jamshed 		if (fio && wv->fd > 0) {
36776404edcSAsim Jamshed 			int wr = 0;
36876404edcSAsim Jamshed 			while (wr < rd) {
36976404edcSAsim Jamshed 				int _wr = write(wv->fd, pbuf + wr, rd - wr);
37076404edcSAsim Jamshed 				assert (_wr == rd - wr);
37176404edcSAsim Jamshed 				 if (_wr < 0) {
37276404edcSAsim Jamshed 					 perror("write");
37376404edcSAsim Jamshed 					 TRACE_ERROR("Failed to write.\n");
37476404edcSAsim Jamshed 					 assert(0);
37576404edcSAsim Jamshed 					 break;
37676404edcSAsim Jamshed 				 }
37776404edcSAsim Jamshed 				 wr += _wr;
37876404edcSAsim Jamshed 				 wv->write += _wr;
37976404edcSAsim Jamshed 			}
38076404edcSAsim Jamshed 		}
38176404edcSAsim Jamshed 
38276404edcSAsim Jamshed 		if (wv->header_len && (wv->recv >= wv->header_len + wv->file_len)) {
38376404edcSAsim Jamshed 			break;
38476404edcSAsim Jamshed 		}
38576404edcSAsim Jamshed 	}
38676404edcSAsim Jamshed 
38776404edcSAsim Jamshed 	if (rd > 0) {
38876404edcSAsim Jamshed 		if (wv->header_len && (wv->recv >= wv->header_len + wv->file_len)) {
38976404edcSAsim Jamshed 			TRACE_APP("Socket %d Done Write: "
39076404edcSAsim Jamshed 					"header: %u file: %lu recv: %lu write: %lu\n",
39176404edcSAsim Jamshed 					sockid, wv->header_len, wv->file_len,
39276404edcSAsim Jamshed 					wv->recv - wv->header_len, wv->write);
39376404edcSAsim Jamshed 			DownloadComplete(ctx, sockid, wv);
39476404edcSAsim Jamshed 
39576404edcSAsim Jamshed 			return 0;
39676404edcSAsim Jamshed 		}
39776404edcSAsim Jamshed 
39876404edcSAsim Jamshed 	} else if (rd == 0) {
39976404edcSAsim Jamshed 		/* connection closed by remote host */
40076404edcSAsim Jamshed 		TRACE_DBG("Socket %d connection closed with server.\n", sockid);
40176404edcSAsim Jamshed 
40276404edcSAsim Jamshed 		if (wv->header_len && (wv->recv >= wv->header_len + wv->file_len)) {
40376404edcSAsim Jamshed 			DownloadComplete(ctx, sockid, wv);
40476404edcSAsim Jamshed 		} else {
40576404edcSAsim Jamshed 			ctx->stat.errors++;
40676404edcSAsim Jamshed 			ctx->incompletes++;
40776404edcSAsim Jamshed 			CloseConnection(ctx, sockid);
40876404edcSAsim Jamshed 		}
40976404edcSAsim Jamshed 
41076404edcSAsim Jamshed 	} else if (rd < 0) {
41176404edcSAsim Jamshed 		if (errno != EAGAIN) {
41276404edcSAsim Jamshed 			TRACE_DBG("Socket %d: mtcp_read() error %s\n",
41376404edcSAsim Jamshed 					sockid, strerror(errno));
41476404edcSAsim Jamshed 			ctx->stat.errors++;
41576404edcSAsim Jamshed 			ctx->errors++;
41676404edcSAsim Jamshed 			CloseConnection(ctx, sockid);
41776404edcSAsim Jamshed 		}
41876404edcSAsim Jamshed 	}
41976404edcSAsim Jamshed 
42076404edcSAsim Jamshed 	return 0;
42176404edcSAsim Jamshed }
42276404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
42376404edcSAsim Jamshed static void
42476404edcSAsim Jamshed PrintStats()
42576404edcSAsim Jamshed {
42676404edcSAsim Jamshed 	struct wget_stat total = {0};
42776404edcSAsim Jamshed 	struct wget_stat *st;
42876404edcSAsim Jamshed 	uint64_t avg_resp_time;
42976404edcSAsim Jamshed 	uint64_t total_resp_time = 0;
43076404edcSAsim Jamshed 	int i;
43176404edcSAsim Jamshed 
43276404edcSAsim Jamshed 	for (i = 0; i < core_limit; i++) {
43376404edcSAsim Jamshed 		st = g_stat[i];
43476404edcSAsim Jamshed 		if (!st)
43576404edcSAsim Jamshed 			continue;
43676404edcSAsim Jamshed 		avg_resp_time = st->completes? st->sum_resp_time / st->completes : 0;
43776404edcSAsim Jamshed 
43876404edcSAsim Jamshed 		total.waits += st->waits;
43976404edcSAsim Jamshed 		total.events += st->events;
44076404edcSAsim Jamshed 		total.connects += st->connects;
44176404edcSAsim Jamshed 		total.reads += st->reads;
44276404edcSAsim Jamshed 		total.writes += st->writes;
44376404edcSAsim Jamshed 		total.completes += st->completes;
44476404edcSAsim Jamshed 		total_resp_time += avg_resp_time;
44576404edcSAsim Jamshed 		if (st->max_resp_time > total.max_resp_time)
44676404edcSAsim Jamshed 			total.max_resp_time = st->max_resp_time;
44776404edcSAsim Jamshed 		total.errors += st->errors;
44876404edcSAsim Jamshed 		total.timedout += st->timedout;
44976404edcSAsim Jamshed 
45076404edcSAsim Jamshed 		memset(st, 0, sizeof(struct wget_stat));
45176404edcSAsim Jamshed 	}
45276404edcSAsim Jamshed 	fprintf(stderr, "[ ALL ] connect: %7lu, read: %4lu MB, write: %4lu MB, "
45376404edcSAsim Jamshed 			"completes: %7lu (resp_time avg: %4lu, max: %6lu us)\n",
45476404edcSAsim Jamshed 			total.connects,
455e160edcaSAsim Jamshed 			total.reads / 1024 / 1024, total.writes / 1024 / 1024,
45676404edcSAsim Jamshed 			total.completes, total_resp_time / core_limit, total.max_resp_time);
45776404edcSAsim Jamshed }
45876404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
45976404edcSAsim Jamshed static void
46076404edcSAsim Jamshed GlbInitWget()
46176404edcSAsim Jamshed {
46276404edcSAsim Jamshed 	struct mtcp_conf mcfg;
46376404edcSAsim Jamshed 	char *url;
46476404edcSAsim Jamshed 	int total_concurrency = 0;
46576404edcSAsim Jamshed 	int flow_per_thread;
46676404edcSAsim Jamshed 	int flow_remainder_cnt;
46776404edcSAsim Jamshed 	int i;
46876404edcSAsim Jamshed 
46976404edcSAsim Jamshed 	num_cores = GetNumCPUs();
47076404edcSAsim Jamshed 	core_limit = num_cores;
47176404edcSAsim Jamshed 	concurrency = 100;
47276404edcSAsim Jamshed 	total_flows = -1;
47376404edcSAsim Jamshed 
47476404edcSAsim Jamshed 	LoadConfig(CONFIG_FILE, g_conf, NUM_CONF_VAR);
47576404edcSAsim Jamshed 
47676404edcSAsim Jamshed 	url = g_conf[0].value;
47776404edcSAsim Jamshed 	total_flows = atoi(g_conf[1].value);
47876404edcSAsim Jamshed 	core_limit = atoi(g_conf[2].value);
47976404edcSAsim Jamshed 	total_concurrency = atoi(g_conf[3].value);
48076404edcSAsim Jamshed 	dest_port = atoi(g_conf[4].value);
48176404edcSAsim Jamshed 
48276404edcSAsim Jamshed 	if ((strlen(url) == 0)
48376404edcSAsim Jamshed 			|| (strlen(url) > MAX_URL_LEN)
48476404edcSAsim Jamshed 			|| (total_flows <= 0)) {
48576404edcSAsim Jamshed 		TRACE_INFO("Invalid configuration\n");
48676404edcSAsim Jamshed 		exit(0);
48776404edcSAsim Jamshed 	}
48876404edcSAsim Jamshed 
48976404edcSAsim Jamshed 	char* slash_p = strchr(url, '/');
49076404edcSAsim Jamshed 	if (slash_p) {
49176404edcSAsim Jamshed 		strncpy(host, url, slash_p - url);
49276404edcSAsim Jamshed 		strncpy(path, strchr(url, '/'), MAX_URL_LEN);
49376404edcSAsim Jamshed 	} else {
49476404edcSAsim Jamshed 		strncpy(host, url, MAX_IP_STR_LEN);
49576404edcSAsim Jamshed 		strncpy(path, "/", 1);
49676404edcSAsim Jamshed 	}
49776404edcSAsim Jamshed 
49876404edcSAsim Jamshed 	daddr = inet_addr(host);
49976404edcSAsim Jamshed 	dport = (dest_port == 0) ? htons(PORT_NUM) : htons(dest_port);
50076404edcSAsim Jamshed 	saddr = INADDR_ANY;
50176404edcSAsim Jamshed 
50276404edcSAsim Jamshed 	if (total_flows < core_limit) {
50376404edcSAsim Jamshed 		core_limit = total_flows;
50476404edcSAsim Jamshed 	}
50576404edcSAsim Jamshed 
50676404edcSAsim Jamshed 	/* per-core concurrency = total_concurrency / # cores */
50776404edcSAsim Jamshed 	if (total_concurrency > 0)
50876404edcSAsim Jamshed 		concurrency = total_concurrency / core_limit;
50976404edcSAsim Jamshed 
51076404edcSAsim Jamshed 	/* set the max number of fds 3x larger than concurrency */
51176404edcSAsim Jamshed 	max_fds = concurrency * 3;
51276404edcSAsim Jamshed 
51376404edcSAsim Jamshed 	TRACE_CONFIG("Application configuration:\n");
51476404edcSAsim Jamshed 	TRACE_CONFIG("URL: %s\n", path);
51576404edcSAsim Jamshed 	TRACE_CONFIG("# of total_flows: %d\n", total_flows);
51676404edcSAsim Jamshed 	TRACE_CONFIG("# of cores: %d\n", core_limit);
51776404edcSAsim Jamshed 	TRACE_CONFIG("Concurrency: %d\n", total_concurrency);
51876404edcSAsim Jamshed 
51976404edcSAsim Jamshed 	mtcp_getconf(&mcfg);
52076404edcSAsim Jamshed 	mcfg.max_concurrency = max_fds;
52176404edcSAsim Jamshed 	mcfg.max_num_buffers = max_fds;
52276404edcSAsim Jamshed 	mtcp_setconf(&mcfg);
52376404edcSAsim Jamshed 
52476404edcSAsim Jamshed 	flow_per_thread = total_flows / core_limit;
52576404edcSAsim Jamshed 	flow_remainder_cnt = total_flows % core_limit;
52676404edcSAsim Jamshed 
52776404edcSAsim Jamshed 	for (i = 0; i < MAX_CPUS; i++) {
52876404edcSAsim Jamshed 		done[i] = FALSE;
52976404edcSAsim Jamshed 		flows[i] = flow_per_thread;
53076404edcSAsim Jamshed 
53176404edcSAsim Jamshed 		if (flow_remainder_cnt-- > 0)
53276404edcSAsim Jamshed 			flows[i]++;
53376404edcSAsim Jamshed 	}
53476404edcSAsim Jamshed 
53576404edcSAsim Jamshed 	return;
53676404edcSAsim Jamshed }
53776404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
53876404edcSAsim Jamshed static void
53976404edcSAsim Jamshed InitWget(mctx_t mctx, void **app_ctx)
54076404edcSAsim Jamshed {
54176404edcSAsim Jamshed 	thread_context_t ctx;
54276404edcSAsim Jamshed 	int ep;
54376404edcSAsim Jamshed 
54476404edcSAsim Jamshed 	assert(mctx);
54576404edcSAsim Jamshed 
54676404edcSAsim Jamshed 	int core = mctx->cpu;
54776404edcSAsim Jamshed 
54876404edcSAsim Jamshed 	ctx = CreateContext(mctx);
54976404edcSAsim Jamshed 	if (!ctx)
55076404edcSAsim Jamshed 		exit(-1);
55176404edcSAsim Jamshed 	g_ctx[core] = ctx;
55276404edcSAsim Jamshed 	g_stat[core] = &ctx->stat;
55376404edcSAsim Jamshed 	srand(time(NULL));
55476404edcSAsim Jamshed 
55576404edcSAsim Jamshed 	mtcp_init_rss(mctx, saddr, IP_RANGE, daddr, dport);
55676404edcSAsim Jamshed 
55776404edcSAsim Jamshed 	if (flows[core] == 0) {
55876404edcSAsim Jamshed 		TRACE_DBG("Application thread %d finished.\n", core);
55976404edcSAsim Jamshed 		exit(-1);
56076404edcSAsim Jamshed 	}
56176404edcSAsim Jamshed 	ctx->target = flows[core];
56276404edcSAsim Jamshed 
56376404edcSAsim Jamshed 	/* Initialization */
56476404edcSAsim Jamshed 	ctx->maxevents = max_fds * 3;
56576404edcSAsim Jamshed 	ep = mtcp_epoll_create(mctx, ctx->maxevents);
56676404edcSAsim Jamshed 	if (ep < 0) {
56776404edcSAsim Jamshed 		TRACE_ERROR("Failed to create epoll struct!n");
56876404edcSAsim Jamshed 		exit(EXIT_FAILURE);
56976404edcSAsim Jamshed 	}
57076404edcSAsim Jamshed 	ctx->events = (struct mtcp_epoll_event *)
57176404edcSAsim Jamshed 			calloc(ctx->maxevents, sizeof(struct mtcp_epoll_event));
57276404edcSAsim Jamshed 	if (!ctx->events) {
57376404edcSAsim Jamshed 		TRACE_ERROR("Failed to allocate events!\n");
57476404edcSAsim Jamshed 		exit(EXIT_FAILURE);
57576404edcSAsim Jamshed 	}
57676404edcSAsim Jamshed 	ctx->ep = ep;
57776404edcSAsim Jamshed 
57876404edcSAsim Jamshed 	ctx->wvars = (struct wget_vars *)calloc(max_fds, sizeof(struct wget_vars));
57976404edcSAsim Jamshed 	if (!ctx->wvars) {
58076404edcSAsim Jamshed 		TRACE_ERROR("Failed to create wget variables!\n");
58176404edcSAsim Jamshed 		exit(EXIT_FAILURE);
58276404edcSAsim Jamshed 	}
58376404edcSAsim Jamshed 
58476404edcSAsim Jamshed 	ctx->started = ctx->done = ctx->pending = 0;
58576404edcSAsim Jamshed 	ctx->errors = ctx->incompletes = 0;
58676404edcSAsim Jamshed 
58776404edcSAsim Jamshed 	*app_ctx = ctx;
58876404edcSAsim Jamshed 
58976404edcSAsim Jamshed 	return;
59076404edcSAsim Jamshed }
59176404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
59276404edcSAsim Jamshed static void
59376404edcSAsim Jamshed RunWget(mctx_t mctx, void **app_ctx)
59476404edcSAsim Jamshed {
59576404edcSAsim Jamshed 	struct in_addr daddr_in;
59676404edcSAsim Jamshed 	struct timeval cur_tv, prev_tv;
59776404edcSAsim Jamshed 	int nevents;
59876404edcSAsim Jamshed 	int i;
59976404edcSAsim Jamshed 
60076404edcSAsim Jamshed 	assert(mctx);
60176404edcSAsim Jamshed 	assert(*app_ctx);
60276404edcSAsim Jamshed 
60376404edcSAsim Jamshed 	thread_context_t ctx = *app_ctx;
60476404edcSAsim Jamshed 	int core = ctx->core;
60576404edcSAsim Jamshed 
60676404edcSAsim Jamshed 	daddr_in.s_addr = daddr;
60776404edcSAsim Jamshed 	fprintf(stderr, "Thread %d handles %d flows. connecting to %s:%u\n",
60876404edcSAsim Jamshed 			core, flows[core], inet_ntoa(daddr_in), ntohs(dport));
60976404edcSAsim Jamshed 
61076404edcSAsim Jamshed 	gettimeofday(&cur_tv, NULL);
61176404edcSAsim Jamshed 	prev_tv = cur_tv;
61276404edcSAsim Jamshed 
61376404edcSAsim Jamshed 	while (!done[core]) {
61476404edcSAsim Jamshed 		gettimeofday(&cur_tv, NULL);
61576404edcSAsim Jamshed 
61676404edcSAsim Jamshed 		/* print statistics every second */
61776404edcSAsim Jamshed 		if (core == 0 && cur_tv.tv_sec > prev_tv.tv_sec) {
61876404edcSAsim Jamshed 			PrintStats();
61976404edcSAsim Jamshed 			prev_tv = cur_tv;
62076404edcSAsim Jamshed 		}
62176404edcSAsim Jamshed 
62276404edcSAsim Jamshed 		while (/*ctx->pending*/ mtcp_get_connection_cnt(ctx->mctx) < concurrency && ctx->started < ctx->target) {
62376404edcSAsim Jamshed 			if (CreateConnection(ctx) < 0) {
62476404edcSAsim Jamshed 				done[core] = TRUE;
62576404edcSAsim Jamshed 				break;
62676404edcSAsim Jamshed 			}
62776404edcSAsim Jamshed 		}
62876404edcSAsim Jamshed 
62976404edcSAsim Jamshed 		nevents = mtcp_epoll_wait(mctx, ctx->ep,
63076404edcSAsim Jamshed 				ctx->events, ctx->maxevents, ctx->pending ? -1 : 10);
63176404edcSAsim Jamshed 		ctx->stat.waits++;
63276404edcSAsim Jamshed 
63376404edcSAsim Jamshed 		if (nevents < 0) {
63476404edcSAsim Jamshed 			if (errno != EINTR) {
63576404edcSAsim Jamshed 				TRACE_ERROR("mtcp_epoll_wait failed! ret: %d\n", nevents);
63676404edcSAsim Jamshed 			}
63776404edcSAsim Jamshed 			done[core] = TRUE;
63876404edcSAsim Jamshed 			break;
63976404edcSAsim Jamshed 		} else {
64076404edcSAsim Jamshed 			ctx->stat.events += nevents;
64176404edcSAsim Jamshed 		}
64276404edcSAsim Jamshed 
64376404edcSAsim Jamshed 		for (i = 0; i < nevents; i++) {
64476404edcSAsim Jamshed 
64576404edcSAsim Jamshed 			if (ctx->events[i].events & MOS_EPOLLERR) {
64676404edcSAsim Jamshed 				int err;
64776404edcSAsim Jamshed 				socklen_t len = sizeof(err);
64876404edcSAsim Jamshed 
64976404edcSAsim Jamshed 				TRACE_APP("[CPU %d] Error on socket %d\n",
65076404edcSAsim Jamshed 						core, ctx->events[i].data.sockid);
65176404edcSAsim Jamshed 				ctx->stat.errors++;
65276404edcSAsim Jamshed 				ctx->errors++;
65376404edcSAsim Jamshed 				if (mtcp_getsockopt(mctx, ctx->events[i].data.sock,
65476404edcSAsim Jamshed 							SOL_SOCKET, SO_ERROR, (void *)&err, &len) == 0) {
65576404edcSAsim Jamshed 					if (err == ETIMEDOUT)
65676404edcSAsim Jamshed 						ctx->stat.timedout++;
65776404edcSAsim Jamshed 				}
65876404edcSAsim Jamshed 				CloseConnection(ctx, ctx->events[i].data.sock);
65976404edcSAsim Jamshed 
66076404edcSAsim Jamshed 			} else if (ctx->events[i].events & MOS_EPOLLIN) {
66176404edcSAsim Jamshed 				HandleReadEvent(ctx,
66276404edcSAsim Jamshed 						ctx->events[i].data.sock,
66376404edcSAsim Jamshed 						&ctx->wvars[ctx->events[i].data.sock]);
66476404edcSAsim Jamshed 
66576404edcSAsim Jamshed 			} else if (ctx->events[i].events == MOS_EPOLLOUT) {
66676404edcSAsim Jamshed 				struct wget_vars *wv = &ctx->wvars[ctx->events[i].data.sock];
66776404edcSAsim Jamshed 
66876404edcSAsim Jamshed 				if (!wv->request_sent) {
66976404edcSAsim Jamshed 					SendHTTPRequest(ctx, ctx->events[i].data.sock, wv);
67076404edcSAsim Jamshed 				} else {
67176404edcSAsim Jamshed 					//TRACE_DBG("Request already sent.\n");
67276404edcSAsim Jamshed 				}
67376404edcSAsim Jamshed 
67476404edcSAsim Jamshed 			} else {
67576404edcSAsim Jamshed 				TRACE_ERROR("Socket %d: event: %s\n",
67676404edcSAsim Jamshed 						ctx->events[i].data.sock,
67776404edcSAsim Jamshed 						EventToString(ctx->events[i].events));
67876404edcSAsim Jamshed 				assert(0);
67976404edcSAsim Jamshed 			}
68076404edcSAsim Jamshed 		}
68176404edcSAsim Jamshed 
68276404edcSAsim Jamshed 		if (ctx->done >= ctx->target) {
68376404edcSAsim Jamshed 			fprintf(stdout, "Completed %d connections, "
68476404edcSAsim Jamshed 					"errors: %d incompletes: %d\n",
68576404edcSAsim Jamshed 					ctx->done, ctx->errors, ctx->incompletes);
68676404edcSAsim Jamshed 			break;
68776404edcSAsim Jamshed 		}
68876404edcSAsim Jamshed 	}
68976404edcSAsim Jamshed 
69076404edcSAsim Jamshed 	TRACE_INFO("Wget thread %d waiting for mtcp to be destroyed.\n", core);
69176404edcSAsim Jamshed 
69276404edcSAsim Jamshed 	g_stat[core] = NULL;
69376404edcSAsim Jamshed 	g_ctx[core] = NULL;
69476404edcSAsim Jamshed 	DestroyContext(ctx);
69576404edcSAsim Jamshed 
69676404edcSAsim Jamshed 	return;
69776404edcSAsim Jamshed }
69876404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
69976404edcSAsim Jamshed void
70076404edcSAsim Jamshed RunApplication(mctx_t mctx)
70176404edcSAsim Jamshed {
70276404edcSAsim Jamshed 	void *app_ctx;
70376404edcSAsim Jamshed 
70476404edcSAsim Jamshed 	app_ctx = (void *)calloc(1, sizeof(void *));
70576404edcSAsim Jamshed 	if (!app_ctx) {
70676404edcSAsim Jamshed 		TRACE_ERROR("calloc failure\n");
70776404edcSAsim Jamshed 		return;
70876404edcSAsim Jamshed 	}
70976404edcSAsim Jamshed 
71076404edcSAsim Jamshed 	TRACE_INFO("run application on core %d\n", mctx->cpu);
71176404edcSAsim Jamshed 	InitWget(mctx, &(app_ctx));
71276404edcSAsim Jamshed 	RunWget(mctx, &(app_ctx));
71376404edcSAsim Jamshed }
71476404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
71576404edcSAsim Jamshed void *
71676404edcSAsim Jamshed RunMTCP(void *arg)
71776404edcSAsim Jamshed {
71876404edcSAsim Jamshed 	int core = *(int *)arg;
71976404edcSAsim Jamshed 	mctx_t mctx;
72076404edcSAsim Jamshed 
72176404edcSAsim Jamshed 	mtcp_core_affinitize(core);
72276404edcSAsim Jamshed 
72376404edcSAsim Jamshed 	/* mTCP Initialization */
72476404edcSAsim Jamshed 	mctx = mtcp_create_context(core);
72576404edcSAsim Jamshed 	if (!mctx) {
72676404edcSAsim Jamshed 		pthread_exit(NULL);
72776404edcSAsim Jamshed 		TRACE_ERROR("Failed to craete mtcp context.\n");
72876404edcSAsim Jamshed 		return NULL;
72976404edcSAsim Jamshed 	}
73076404edcSAsim Jamshed 
73176404edcSAsim Jamshed 	/* Run application here */
73276404edcSAsim Jamshed 	RunApplication(mctx);
73376404edcSAsim Jamshed 
73476404edcSAsim Jamshed 	/* mTCP Tear Down */
73576404edcSAsim Jamshed 	mtcp_destroy_context(mctx);
73676404edcSAsim Jamshed 	pthread_exit(NULL);
73776404edcSAsim Jamshed 
73876404edcSAsim Jamshed 	return NULL;
73976404edcSAsim Jamshed }
74076404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
74176404edcSAsim Jamshed int
74276404edcSAsim Jamshed main(int argc, char **argv)
74376404edcSAsim Jamshed {
74476404edcSAsim Jamshed 	int ret, i;
74576404edcSAsim Jamshed 	int cores[MAX_CPUS];
74676404edcSAsim Jamshed 	char *fname = "config/mos.conf";
74776404edcSAsim Jamshed 
74876404edcSAsim Jamshed 	int opt;
74976404edcSAsim Jamshed 	while ((opt = getopt(argc, argv, "f:")) != -1) {
75076404edcSAsim Jamshed 		switch (opt) {
75176404edcSAsim Jamshed 			case 'f':
75276404edcSAsim Jamshed 				fname = optarg;
75376404edcSAsim Jamshed 				break;
75476404edcSAsim Jamshed 			default:
75576404edcSAsim Jamshed 				printf("Usage: %s [-f config_file]\n", argv[0]);
75676404edcSAsim Jamshed 				return 0;
75776404edcSAsim Jamshed 		}
75876404edcSAsim Jamshed 
75976404edcSAsim Jamshed 	}
76076404edcSAsim Jamshed 
76176404edcSAsim Jamshed 	core_limit = sysconf(_SC_NPROCESSORS_ONLN);
76276404edcSAsim Jamshed 
76376404edcSAsim Jamshed 	ret = mtcp_init(fname);
76476404edcSAsim Jamshed 	if (ret) {
76576404edcSAsim Jamshed 		TRACE_ERROR("Failed to initialize mtcp.\n");
76676404edcSAsim Jamshed 		exit(EXIT_FAILURE);
76776404edcSAsim Jamshed 	}
76876404edcSAsim Jamshed 
76976404edcSAsim Jamshed 	mtcp_getconf(&g_mcfg);
77076404edcSAsim Jamshed 
77176404edcSAsim Jamshed 	core_limit = g_mcfg.num_cores;
77276404edcSAsim Jamshed 
77376404edcSAsim Jamshed 	GlbInitWget();
77476404edcSAsim Jamshed 
77576404edcSAsim Jamshed 	for (i = 0; i < core_limit; i++) {
77676404edcSAsim Jamshed 		cores[i] = i;
77776404edcSAsim Jamshed 
77876404edcSAsim Jamshed 		/* Run mtcp thread */
77976404edcSAsim Jamshed 		if ((g_mcfg.cpu_mask & (1L << i)) &&
78076404edcSAsim Jamshed 			pthread_create(&mtcp_thread[i], NULL, RunMTCP, (void *)&cores[i])) {
78176404edcSAsim Jamshed 			perror("pthread_create");
78276404edcSAsim Jamshed 			TRACE_ERROR("Failed to create msg_test thread.\n");
78376404edcSAsim Jamshed 			exit(-1);
78476404edcSAsim Jamshed 		}
78576404edcSAsim Jamshed 	}
78676404edcSAsim Jamshed 
78776404edcSAsim Jamshed 	for (i = 0; i < core_limit; i++) {
78876404edcSAsim Jamshed 		if (g_mcfg.cpu_mask & (1L << i))
78976404edcSAsim Jamshed 			pthread_join(mtcp_thread[i], NULL);
79076404edcSAsim Jamshed 		TRACE_INFO("Message test thread %d joined.\n", i);
79176404edcSAsim Jamshed 	}
79276404edcSAsim Jamshed 
79376404edcSAsim Jamshed 	mtcp_destroy();
79476404edcSAsim Jamshed 	return 0;
79576404edcSAsim Jamshed }
79676404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
797