xref: /mOS-networking-stack/core/src/mos_api.c (revision 861ea7df)
1 #include <assert.h>
2 #include <ctype.h>
3 #include <string.h>
4 #ifdef ENABLE_DEBUG_EVENT
5 #include <stdarg.h>
6 #endif
7 
8 #include "mtcp.h"
9 #include "mos_api.h"
10 #include "debug.h"
11 #include "config.h"
12 #include "ip_in.h"
13 #include "tcp_out.h"
14 /*----------------------------------------------------------------------------*/
15 #define MAX(x, y) (((x) > (y)) ? (x) : (y))
16 #define MIN(x, y) (((x) < (y)) ? (x) : (y))
17 #define SKIP_SPACES(x) while (*x && isspace((int)*x)) x++;
18 #define SKIP_CHAR(x) while((*x) && !isspace(*x)) x++;
19 
20 #define KW_AND       "and "
21 #define KW_OR        "or "
22 #define KW_NOT       "not "
23 #define KW_TCP       "tcp"
24 #define KW_NOT_TCP   "!tcp"
25 #define KW_NOT_TCP2  "not tcp"
26 #define KW_SRC       "src "
27 #define KW_DST       "dst "
28 #define KW_HOST      "host "
29 #define KW_NET       "net "
30 #define KW_MASK      "mask "
31 #define KW_PORT      "port "
32 #define KW_PORTRANGE "portrange "
33 /*----------------------------------------------------------------------------*/
34 int
35 IsValidFlowRule(char *cf)
36 {
37 	char *word;
38 	int skip_word = 0;
39 
40 	/* '!tcp' or 'not tcp' are also not supported in TCP flow filter */
41 	if (strstr(cf, KW_NOT_TCP) || strstr(cf, KW_NOT_TCP2)) {
42 		TRACE_ERROR("'!tcp' or 'not tcp' is not a valid rule for TCP flow monitor.\n");
43 		return FALSE;
44 	}
45 
46 	/* verify that the rule contains flow-related keywords only */
47 	word = cf;
48 	SKIP_SPACES(word);
49 
50 	/* while (browse the rule by words) */
51 	while (*word) {
52 		if (skip_word) {
53 			skip_word = 0;
54 			SKIP_CHAR(word);
55 			SKIP_SPACES(word);
56 			continue;
57 		}
58 		/* parse the keyword */
59 		/* case "tcp" "src" "dst" "not' "and" "or" -> move to the next word */
60 		if (!strncmp(word, KW_TCP, sizeof(KW_TCP) - 1) ||
61 			!strncmp(word, KW_SRC, sizeof(KW_SRC) - 1) ||
62 			!strncmp(word, KW_DST, sizeof(KW_DST) - 1) ||
63 			!strncmp(word, KW_NOT, sizeof(KW_NOT) - 1) ||
64 			!strncmp(word, KW_AND, sizeof(KW_AND) - 1) ||
65 			!strncmp(word, KW_OR, sizeof(KW_OR) - 1)) {
66 			skip_word = 0;
67 		}
68 		/* case "net" "mask" "port" "portrange" -> skip a word (= param) */
69 		else if (!strncmp(word, KW_HOST, sizeof(KW_HOST) - 1) ||
70 				 !strncmp(word, KW_NET, sizeof(KW_NET) - 1) ||
71 				 !strncmp(word, KW_MASK, sizeof(KW_MASK) - 1) ||
72 				 !strncmp(word, KW_PORT, sizeof(KW_PORT) - 1) ||
73 				 !strncmp(word, KW_PORTRANGE, sizeof(KW_PORTRANGE) - 1)) {
74 			skip_word = 1;
75 		}
76 		/* default (rule has any invalid keyword) -> return error */
77 		else {
78 			TRACE_ERROR("Invalid keyword in filter (%s)\n", word);
79 			return FALSE;
80 		}
81 
82 		SKIP_CHAR(word);
83 		SKIP_SPACES(word);
84 	}
85 
86 	return TRUE;
87 }
88 /*----------------------------------------------------------------------------*/
89 /* Assign an address range (specified by ft) to monitor via sock */
90 int
91 mtcp_bind_monitor_filter(mctx_t mctx, int sockid, monitor_filter_t ft)
92 {
93 	socket_map_t sock;
94 	mtcp_manager_t mtcp;
95 
96 	mtcp = GetMTCPManager(mctx);
97 	if (!mtcp) {
98 		errno = EACCES;
99 		return -1;
100 	}
101 
102 	/* if filter is not set, do nothing and return */
103 	if (ft == NULL) {
104 		TRACE_ERROR("filter not set!\n");
105 		return 0;
106 	}
107 
108 	/* retrieve the socket */
109 	if (sockid < 0 || sockid >= g_config.mos->max_concurrency) {
110 		errno = EBADF;
111 		TRACE_ERROR("sockid is invalid!\n");
112 		return -1;
113 	}
114 	sock = &mtcp->msmap[sockid];
115 
116 	/* check socket type */
117 	switch (sock->socktype) {
118 	case MOS_SOCK_MONITOR_RAW:
119 		/* For MONITOR_RAW type, allow any bpf rule */
120 		if (!ft->raw_pkt_filter) {
121 			TRACE_ERROR("raw pkt filter is null");
122 			return 0;
123 		}
124 		if (SET_BPFFILTER(&sock->monitor_listener->raw_pkt_fcode,
125 						  ft->raw_pkt_filter) < 0) {
126 			TRACE_ERROR("Invalid filter expression!\n");
127 			errno = EINVAL;
128 			return -1;
129 		}
130 		break;
131 	case MOS_SOCK_MONITOR_STREAM:
132 		/* For MONITOR_STREAM_PASSIVE type, restrict to flow-level keywords */
133 		if (ft->stream_syn_filter) {
134 			if (!IsValidFlowRule(ft->stream_syn_filter)) {
135 				errno = EINVAL;
136 				return -1;
137 			}
138 			if (SET_BPFFILTER(&sock->monitor_listener->stream_syn_fcode,
139 							  ft->stream_syn_filter) < 0) {
140 				TRACE_ERROR("Invalid filter expression!\n");
141 				errno = EINVAL;
142 				return -1;
143 			}
144 		}
145 		if (ft->stream_orphan_filter) {
146 			if (!IsValidFlowRule(ft->stream_orphan_filter)) {
147 				errno = EINVAL;
148 				return -1;
149 			}
150 			if (SET_BPFFILTER(&sock->monitor_listener->stream_orphan_fcode,
151 							  ft->stream_orphan_filter) < 0) {
152 				TRACE_ERROR("Invalid filter expression!\n");
153 				errno = EINVAL;
154 				return -1;
155 			}
156 		}
157 		break;
158 	default:
159 		/* return error for other socket types */
160 		errno = ENOPROTOOPT;
161 		TRACE_ERROR("Invalid sock type!\n");
162 		return -1;
163 	}
164 
165 	return 0;
166 }
167 /*----------------------------------------------------------------------------*/
168 void
169 mtcp_app_join(mctx_t mctx)
170 {
171 	mtcp_manager_t mtcp = GetMTCPManager(mctx);
172 	if (!mtcp) return;
173 
174 	RunPassiveLoop(mtcp);
175 	return;
176 }
177 /*----------------------------------------------------------------------------*/
178 /* Callback only functions */
179 /*----------------------------------------------------------------------------*/
180 void
181 mtcp_set_uctx(mctx_t mctx, int msock, void *uctx)
182 {
183 	mtcp_manager_t mtcp;
184 
185 	mtcp = GetMTCPManager(mctx);
186 	if (!mtcp) {
187 		return;
188 	}
189 
190 	/* check if the calling thread is in MOS context */
191 	if (mtcp->ctx->thread != pthread_self())
192 		return;
193 
194 	if (msock < 0 || msock >= g_config.mos->max_concurrency) {
195 		TRACE_API("Socket id %d out of range.\n", msock);
196 		errno = EBADF;
197 		return;
198 	}
199 
200 	socket_map_t socket = &mtcp->msmap[msock];
201 	if (socket->socktype == MOS_SOCK_MONITOR_STREAM_ACTIVE)
202 		socket->monitor_stream->uctx = uctx;
203 	else if (socket->socktype == MOS_SOCK_MONITOR_STREAM ||
204 			 socket->socktype == MOS_SOCK_MONITOR_RAW)
205 		socket->monitor_listener->uctx = uctx;
206 }
207 /*----------------------------------------------------------------------------*/
208 void *
209 mtcp_get_uctx(mctx_t mctx, int msock)
210 {
211 	mtcp_manager_t mtcp;
212 
213 	mtcp = GetMTCPManager(mctx);
214 	if (!mtcp) {
215 		errno = EACCES;
216 		return NULL;
217 	}
218 
219 	/* check if the calling thread is in MOS context */
220 	if (mtcp->ctx->thread != pthread_self()) {
221 		errno = EPERM;
222 		return NULL;
223 	}
224 
225 	if (msock < 0 || msock >= g_config.mos->max_concurrency) {
226 		TRACE_API("Socket id %d out of range.\n", msock);
227 		errno = EBADF;
228 		return NULL;
229 	}
230 
231 	socket_map_t socket = &mtcp->msmap[msock];
232 	if (socket->socktype == MOS_SOCK_MONITOR_STREAM_ACTIVE)
233 		return socket->monitor_stream->uctx;
234 	else if (socket->socktype == MOS_SOCK_MONITOR_STREAM ||
235 			 socket->socktype == MOS_SOCK_MONITOR_RAW)
236 		return socket->monitor_listener->uctx;
237 	else
238 		return NULL;
239 }
240 /*----------------------------------------------------------------------------*/
241 ssize_t
242 mtcp_peek(mctx_t mctx, int msock, int side, char *buf, size_t len)
243 {
244 	int copylen, rc;
245 	struct tcp_stream *cur_stream;
246 	mtcp_manager_t mtcp;
247 	socket_map_t sock;
248 
249 	copylen = rc = 0;
250 	mtcp = GetMTCPManager(mctx);
251 	if (!mtcp) {
252 		errno = EACCES;
253 		return -1;
254 	}
255 
256 	/* check if the calling thread is in MOS context */
257 	if (mtcp->ctx->thread != pthread_self()) {
258 		errno = EPERM;
259 		return -1;
260 	}
261 
262 	/* check if the socket is monitor stream */
263 	sock = &mtcp->msmap[msock];
264 	if (sock->socktype != MOS_SOCK_MONITOR_STREAM_ACTIVE) {
265 		TRACE_DBG("Invalid socket type!\n");
266 		errno = EBADF;
267 		return -1;
268 	}
269 
270 	if (side != MOS_SIDE_CLI && side != MOS_SIDE_SVR) {
271 		TRACE_ERROR("Invalid side requested!\n");
272 		exit(EXIT_FAILURE);
273 		return -1;
274 	}
275 
276 	struct tcp_stream *mstrm = sock->monitor_stream->stream;
277 	cur_stream = (side == mstrm->side) ? mstrm : mstrm->pair_stream;
278 
279 	if (!cur_stream || !cur_stream->buffer_mgmt) {
280 		TRACE_DBG("Stream is NULL!! or buffer management is disabled\n");
281 		errno = EINVAL;
282 		return -1;
283 	}
284 
285 	/* Check if the read was not just due to syn-ack recv */
286 	if (cur_stream->rcvvar != NULL &&
287 	    cur_stream->rcvvar->rcvbuf != NULL) {
288 		tcprb_t *rcvbuf = cur_stream->rcvvar->rcvbuf;
289 		loff_t *poff = &sock->monitor_stream->peek_offset[cur_stream->side];
290 
291 		rc = tcprb_ppeek(rcvbuf, (uint8_t *)buf, len, *poff);
292 		if (rc < 0) {
293 			errno = ENODATA;
294 			return -1;
295 		}
296 
297 		*poff += rc;
298 		UNUSED(copylen);
299 
300 		return rc;
301 	} else {
302 		TRACE_DBG("Stream hasn't yet been initialized!\n");
303 		rc = 0;
304 	}
305 
306 	return rc;
307 }
308 /*----------------------------------------------------------------------------*/
309 /**
310  * Copies from the frags.. returns no. of bytes copied to buf
311  */
312 static inline int
313 ExtractPayloadFromFrags(struct tcp_ring_buffer *rcvbuf, char *buf,
314 						size_t count, off_t seq_num)
315 {
316 	int cpbytesleft;
317 	struct fragment_ctx *it;
318 
319 	it = rcvbuf->fctx;
320 	cpbytesleft = count;
321 	/* go through each frag */
322 	while (it) {
323 		/* first check whether sequent number matches */
324 		if (TCP_SEQ_BETWEEN(seq_num, it->seq, it->seq + it->len)) {
325 			/* copy buf starting from seq# seq_num */
326 			/* copy the MIN of seq-range and bytes to be copied */
327 			memcpy(buf + count - cpbytesleft,
328 			       rcvbuf->head + seq_num - rcvbuf->head_seq,
329 			       MIN(it->len - (seq_num - it->seq), cpbytesleft));
330 			/* update target seq num */
331 			seq_num += it->len - (seq_num - it->seq);
332 			/* update cpbytes left */
333 			cpbytesleft -= it->len - (seq_num - it->seq);
334 			if (cpbytesleft == 0)
335 				break;
336 		}
337 		it = it->next;
338 	}
339 
340 	count -= cpbytesleft;
341 
342 	/* return number of bytes copied */
343 	return count;
344 }
345 /*----------------------------------------------------------------------------*/
346 /* Please see in-code comments for description */
347 ssize_t
348 mtcp_ppeek(mctx_t mctx, int msock, int side,
349 			  char *buf, size_t count, uint64_t off)
350 {
351 	mtcp_manager_t mtcp;
352 	struct tcp_stream *cur_stream;
353 	int rc;
354 	socket_map_t sock;
355 
356 	mtcp = GetMTCPManager(mctx);
357 	if (!mtcp) {
358 		errno = EACCES;
359 		goto ppeek_error;
360 	}
361 
362 	/* check if the calling thread is in MOS context */
363 	if (mtcp->ctx->thread != pthread_self()) {
364 		errno = EPERM;
365 		goto ppeek_error;
366 	}
367 
368 	/* check if the socket is monitor stream */
369 	sock = &mtcp->msmap[msock];
370 	if (sock->socktype != MOS_SOCK_MONITOR_STREAM_ACTIVE) {
371 		TRACE_DBG("Invalid socket type!\n");
372 		errno = ESOCKTNOSUPPORT;
373 		goto ppeek_error;
374 	}
375 
376 	if (side != MOS_SIDE_CLI && side != MOS_SIDE_SVR) {
377 		TRACE_ERROR("Invalid side requested!\n");
378 		exit(EXIT_FAILURE);
379 		return -1;
380 	}
381 
382 	struct tcp_stream *mstrm = sock->monitor_stream->stream;
383 	cur_stream = (side == mstrm->side) ? mstrm : mstrm->pair_stream;
384 
385 	if (!cur_stream || !cur_stream->buffer_mgmt) {
386 		TRACE_DBG("Stream is either NULL or ring buffer is not managed!!\n");
387 		errno = EACCES;
388 		goto ppeek_error;
389 	}
390 
391 	rc = 0;
392 	/* Check if the read was not just due to syn-ack recv */
393 	if (cur_stream->rcvvar != NULL &&
394 	    cur_stream->rcvvar->rcvbuf != NULL) {
395 		tcprb_t *rcvbuf = cur_stream->rcvvar->rcvbuf;
396 		return tcprb_ppeek(rcvbuf, (uint8_t *)buf, count, off);
397 	} else {
398 		errno = EPERM;
399 		goto ppeek_error;
400 	}
401 
402 	return rc;
403 
404  ppeek_error:
405 	return -1;
406 }
407 /*----------------------------------------------------------------------------*/
408 #ifdef MTCP_CB_GETCURPKT_CREATE_COPY
409 static __thread unsigned char local_frame[ETHERNET_FRAME_LEN];
410 inline struct pkt_info *
411 ClonePacketCtx(struct pkt_info *to, unsigned char *frame, struct pkt_info *from)
412 {
413 	/* memcpy the entire ethernet frame */
414 	assert(from);
415 	assert(from->eth_len > 0);
416 	assert(from->eth_len <= ETHERNET_FRAME_LEN);
417 	memcpy(frame, from->ethh, from->eth_len);
418 
419 	/* only memcpy till the last field before ethh */
420 	/* memcpy(to, from, PCTX_COPY_LEN); */
421 	memcpy(to, from, PKT_INFO_LEN);
422 	/* set iph */
423 	to->ethh = (struct ethhdr *)frame;
424 	/* set iph */
425 	to->iph = from->iph ?
426 		(struct iphdr *)((uint8_t *)(frame + ETHERNET_HEADER_LEN)) : NULL;
427 	if (to->iph) {
428 		/* set tcph */
429 		to->tcph = from->tcph ?
430 			(struct tcphdr *)(((uint8_t *)(to->iph)) + (to->iph->ihl<<2)) : NULL;
431 		if (to->tcph)
432 			/* set payload */
433 			to->payload = from->tcph ?
434 				((uint8_t *)(to->tcph) + (to->tcph->doff<<2)) : NULL;
435 	}
436 	return to;
437 }
438 /*----------------------------------------------------------------------------*/
439 int
440 mtcp_getlastpkt(mctx_t mctx, int sock, int side, struct pkt_info *pkt)
441 {
442 	mtcp_manager_t mtcp;
443 	socket_map_t socket;
444 	struct pkt_ctx *cur_pkt_ctx;
445 
446 	mtcp = GetMTCPManager(mctx);
447 	if (!mtcp) {
448 		errno = EACCES;
449 		return -1;
450 	}
451 
452 	/* check if the calling thread is in MOS context */
453 	if (mtcp->ctx->thread != pthread_self()) {
454 		errno = EPERM;
455 		return -1;
456 	}
457 
458 	/* check if the socket is monitor stream */
459 	socket = &mtcp->msmap[sock];
460 #ifndef RECORDPKT_PER_STREAM
461 	switch (socket->socktype) {
462 	case MOS_SOCK_MONITOR_STREAM_ACTIVE:
463 	case MOS_SOCK_MONITOR_RAW:
464 	case MOS_SOCK_MONITOR_STREAM:
465 		if (mtcp->pctx == NULL) {
466 			errno = EACCES;
467 			return -1;
468 		}
469 		cur_pkt_ctx = mtcp->pctx;
470 		break;
471 	default:
472 		TRACE_DBG("Invalid socket type!\n");
473 		errno = EBADF;
474 		return -1;
475 	}
476 #else /* RECORDPKT_PER_STREAM */
477 	struct tcp_stream *cur_stream;
478 	if (socket->socktype == MOS_SOCK_MONITOR_STREAM_ACTIVE) {
479 		if (side != MOS_SIDE_CLI && side != MOS_SIDE_SVR) {
480 			TRACE_ERROR("Invalid side requested!\n");
481 			exit(EXIT_FAILURE);
482 			return -1;
483 		}
484 
485 		struct tcp_stream *mstrm = socket->monitor_stream->stream;
486 		cur_stream = (side == mstrm->side) ? mstrm : mstrm->pair_stream;
487 
488 		cur_pkt_ctx = &cur_stream->last_pctx;
489 		if (!cur_pkt_ctx->p.ethh) {
490 			errno = ENODATA;
491 			return -1;
492 		}
493 	} else if (socket->socktype == MOS_SOCK_MONITOR_RAW) {
494 		cur_pkt_ctx = mtcp->pctx;
495 	} else if (socket->socktype == MOS_SOCK_MONITOR_STREAM) {
496 		/*
497 		 * if it is a monitor socket, then this means that
498 		 * this is a request for an orphan tcp packet
499 		 */
500 		cur_pkt_ctx = mtcp->pctx;
501 	} else {
502 		TRACE_DBG("Invalid socket type!\n");
503 		errno = EBADF;
504 		return -1;
505 	}
506 #endif /* !RECORDPKT_PER_STREAM */
507 	ClonePacketCtx(pkt, local_frame, &(cur_pkt_ctx->p));
508 	return 0;
509 }
510 #else
511 /*----------------------------------------------------------------------------*/
512 int
513 mtcp_getlastpkt(mctx_t mctx, int sock, int side, struct pkt_ctx **pctx)
514 {
515 	mtcp_manager_t mtcp;
516 
517 	mtcp = GetMTCPManager(mctx);
518 	if (!mtcp) {
519 		errno = EACCES;
520 		return -1;
521 	}
522 
523 	/* check if the calling thread is in MOS context */
524 	if (mtcp->ctx->thread != pthread_self()) {
525 		errno = EPERM;
526 		return -1;
527 	}
528 	/* just pass direct pointer */
529 	*pctx = mtcp->pctx;
530 
531 	return 0;
532 }
533 #endif
534 /*----------------------------------------------------------------------------*/
535 int
536 mtcp_sendpkt(mctx_t mctx, int sock, const struct pkt_info *pkt)
537 {
538 	mtcp_manager_t mtcp;
539 	socket_map_t socket;
540 
541 	mtcp = GetMTCPManager(mctx);
542 	if (!mtcp || !pkt) {
543 		errno = EACCES;
544 		return -1;
545 	}
546 
547 	/* check if the calling thread is in MOS context */
548 	if (mtcp->ctx->thread != pthread_self()) {
549 		errno = EPERM;
550 		return -1;
551 	}
552 
553 	/* check if the socket is monitor stream */
554 	socket = &mtcp->msmap[sock];
555 
556 	if (!(pkt->iph) || !(pkt->tcph)) {
557 		errno = ENODATA;
558 		TRACE_INFO("mtcp_sendpkt() only supports TCP packet for now.\n");
559 		return -1;
560 	}
561 
562 	if (socket->socktype == MOS_SOCK_MONITOR_STREAM_ACTIVE) {
563 		SendTCPPacketStandalone(mtcp,
564 				   pkt->iph->saddr, pkt->tcph->source,
565 				   pkt->iph->daddr, pkt->tcph->dest,
566 				   htonl(pkt->tcph->seq), htonl(pkt->tcph->ack_seq),
567 				   ntohs(pkt->tcph->window), TCP_FLAG_ACK,
568 				   pkt->payload, pkt->payloadlen,
569 				   socket->monitor_stream->stream->rcvvar->ts_recent,
570 				   socket->monitor_stream->stream->rcvvar->ts_lastack_rcvd,
571 				   pkt->iph->id, pkt->in_ifidx);
572 
573 
574 	}
575 
576 	return 0;
577 }
578 /*----------------------------------------------------------------------------*/
579 /** Disable events from the monitor stream socket
580  * @param [in] mtcp: mtcp_manager
581  * @param [in] sock: socket
582  *
583  * returns 0 on success, -1 on failure
584  *
585  * This is used for flow management based monitoring sockets
586  */
587 int
588 RemoveMonitorEvents(mtcp_manager_t mtcp, socket_map_t socket, int side)
589 {
590 	struct mon_stream *mstream;
591 	struct mon_listener *mlistener;
592 
593 	if (mtcp == NULL) {
594 		TRACE_DBG("mtcp is not defined!!!\n");
595 		errno = EACCES;
596 		return -1;
597 	}
598 
599 	switch (socket->socktype) {
600 	case MOS_SOCK_MONITOR_STREAM_ACTIVE:
601 		mstream = socket->monitor_stream;
602 		if (mstream == NULL) {
603 			TRACE_ERROR("Mon Stream does not exist!\n");
604 			/* exit(-1); */
605 			errno = ENODATA;
606 			return -1;
607 		}
608 
609 		if (side == MOS_SIDE_SVR) mstream->server_mon = 0;
610 		else if (side == MOS_SIDE_CLI) mstream->client_mon = 0;
611 
612 		if (mstream->server_mon == 0 && mstream->client_mon == 0) {
613 #ifdef NEWEV
614 			/*
615 			 * if stree_dontcare is NULL, then we know that all
616 			 * events have already been disabled
617 			 */
618 			if (mstream->stree_pre_rcv != NULL) {
619 				stree_dec_ref(mtcp->ev_store, mstream->stree_dontcare);
620 				stree_dec_ref(mtcp->ev_store, mstream->stree_pre_rcv);
621 				stree_dec_ref(mtcp->ev_store, mstream->stree_post_snd);
622 
623 				mstream->stree_dontcare = NULL;
624 				mstream->stree_pre_rcv = NULL;
625 				mstream->stree_post_snd = NULL;
626 			}
627 #else
628 			/* no error checking over here..
629 			 * but its okay.. this code is
630 			 * deprecated
631 			 */
632 			CleanupEvP(&mstream->dontcare_evp);
633 			CleanupEvP(&mstream->pre_tcp_evp);
634 			CleanupEvP(&mstream->post_tcp_evp);
635 #endif
636 		}
637 		break;
638 	case MOS_SOCK_MONITOR_STREAM:
639 		mlistener = socket->monitor_listener;
640 		if (mlistener == NULL) {
641 			TRACE_ERROR("Mon listener does not exist!\n");
642 			errno = ENODATA;
643 			return -1;
644 		}
645 
646 		if (side == MOS_SIDE_SVR) mlistener->server_mon = 0;
647 		else if (side == MOS_SIDE_CLI) mlistener->client_mon = 0;
648 
649 		if (mlistener->server_mon == 0 && mlistener->client_mon == 0) {
650 #ifdef NEWEV
651 			/*
652 			 * if stree_dontcare is NULL, then we know that all
653 			 * events have already been disabled
654 			 */
655 			if (mlistener->stree_pre_rcv != NULL) {
656 				stree_dec_ref(mtcp->ev_store, mlistener->stree_dontcare);
657 				stree_dec_ref(mtcp->ev_store, mlistener->stree_pre_rcv);
658 				stree_dec_ref(mtcp->ev_store, mlistener->stree_post_snd);
659 
660 				mlistener->stree_dontcare = NULL;
661 				mlistener->stree_pre_rcv = NULL;
662 				mlistener->stree_post_snd = NULL;
663 			}
664 #else
665 			/* no error checking over here..
666 			 * but its okay.. this code is
667 			 * deprecated
668 			 */
669 			CleanupEvB(mtcp, &mlistener->dontcare_evb);
670 			CleanupEvB(mtcp, &mlistener->pre_tcp_evb);
671 			CleanupEvB(mtcp, &mlistener->post_tcp_evb);
672 #endif
673 		}
674 		break;
675 	default:
676 		TRACE_ERROR("Invalid socket type!\n");
677 	}
678 
679 	return 0;
680 }
681 /*----------------------------------------------------------------------------*/
682 /**
683  * Disable monitoring based on side variable.
684  */
685 int
686 mtcp_cb_stop(mctx_t mctx, int sock, int side)
687 {
688 	mtcp_manager_t mtcp;
689 	socket_map_t socket;
690 	struct tcp_stream *stream;
691 	struct socket_map *walk;
692 	uint8_t mgmt;
693 
694 	mtcp = GetMTCPManager(mctx);
695 	if (!mtcp) {
696 		errno = EACCES;
697 		return -1;
698 	}
699 
700 	socket = &mtcp->msmap[sock];
701 
702 	/* works for both monitor listener and stream sockets */
703 	RemoveMonitorEvents(mtcp, socket, side);
704 
705 	/* passive monitoring socket is not connected to any stream */
706 	if (socket->socktype == MOS_SOCK_MONITOR_STREAM) {
707 	  /* it should return an EPERM error instead of quitting silently */
708 	  errno = EPERM;
709 	  return -1;
710 	}
711 
712 	if (side == MOS_SIDE_CLI) {
713 		/* see if the associated stream requires monitoring any more */
714 		stream = (socket->monitor_stream->stream->side == MOS_SIDE_CLI) ?
715 			socket->monitor_stream->stream :
716 			socket->monitor_stream->stream->pair_stream;
717 
718 		mgmt = 0;
719 		SOCKQ_FOREACH_START(walk, &stream->msocks) {
720 			if (walk->monitor_stream->client_mon == 1) {
721 				mgmt = 1;
722 				break;
723 			}
724 		} SOCKQ_FOREACH_END;
725 		/* if all streams have mgmt off, then tag the stream for destruction */
726 		if (mgmt == 0) {
727 			stream = (socket->monitor_stream->stream->side == MOS_SIDE_CLI) ?
728 				socket->monitor_stream->stream :
729 				socket->monitor_stream->stream->pair_stream;
730 			stream->status_mgmt = 0;
731 		}
732 	}
733 
734 	if (side == MOS_SIDE_SVR) {
735 		/* see if the associated stream requires monitoring any more */
736 		stream = (socket->monitor_stream->stream->side == MOS_SIDE_SVR) ?
737 			socket->monitor_stream->stream :
738 			socket->monitor_stream->stream->pair_stream;
739 		mgmt = 0;
740 		SOCKQ_FOREACH_START(walk, &stream->msocks) {
741 			if (walk->monitor_stream->server_mon == 1) {
742 				mgmt = 1;
743 				break;
744 			}
745 		} SOCKQ_FOREACH_END;
746 		/* if all streams have mgmt off, then tag the stream for destruction */
747 		if (mgmt == 0) {
748 			stream = (socket->monitor_stream->stream->side == MOS_SIDE_SVR) ?
749 				socket->monitor_stream->stream :
750 				socket->monitor_stream->stream->pair_stream;
751 			stream->status_mgmt = 0;
752 		}
753 	}
754 
755 	return 0;
756 }
757 /*----------------------------------------------------------------------------*/
758 /**
759  * send a RST packet to the TCP stream (uni-directional)
760  */
761 static inline void
762 SendRSTPacketStandalone(mtcp_manager_t mtcp, struct tcp_stream *stream) {
763 	SendTCPPacketStandalone(mtcp,
764 				stream->saddr, stream->sport, stream->daddr, stream->dport,
765 				stream->snd_nxt, stream->rcv_nxt, 0, TCP_FLAG_RST | TCP_FLAG_ACK,
766 				NULL, 0, mtcp->cur_ts, 0, 0, -1);
767 }
768 /*----------------------------------------------------------------------------*/
769 /**
770  * Reset the connection (send RST packets to both sides)
771  */
772 int
773 mtcp_reset_conn(mctx_t mctx, int sock)
774 {
775 	mtcp_manager_t mtcp;
776 	socket_map_t socket;
777 
778 	mtcp = GetMTCPManager(mctx);
779 	if (!mtcp) {
780 		errno = EACCES;
781 		return -1;
782 	}
783 
784 	socket = &mtcp->msmap[sock];
785 
786 	/* passive monitoring socket is not connected to any stream */
787 	if (socket->socktype == MOS_SOCK_MONITOR_STREAM) {
788 		errno = EINVAL;
789 		return -1;
790 	}
791 
792 	/* send RST packets to the both sides */
793 	SendRSTPacketStandalone(mtcp, socket->monitor_stream->stream);
794 	SendRSTPacketStandalone(mtcp, socket->monitor_stream->stream->pair_stream);
795 
796 	return 0;
797 }
798 /*----------------------------------------------------------------------------*/
799 uint32_t
800 mtcp_cb_get_ts(mctx_t mctx)
801 {
802 	mtcp_manager_t mtcp;
803 
804 	mtcp = GetMTCPManager(mctx);
805 	if (!mtcp) {
806 		TRACE_DBG("Can't access MTCP manager!\n");
807 		errno = EACCES;
808 		return 0;
809 	}
810 
811 	/* check if the calling thread is in MOS context */
812 	if (mtcp->ctx->thread != pthread_self()) {
813 		errno = EPERM;
814 		return 0;
815 	}
816 
817 	return TS_TO_USEC(mtcp->cur_ts);
818 }
819 /*----------------------------------------------------------------------------*/
820 /* Macros related to getpeername */
821 #define TILL_SVRADDR		offsetof(struct sockaddr_in, sin_zero)
822 #define TILL_SVRPORT		offsetof(struct sockaddr_in, sin_addr)
823 #define TILL_SVRFAMILY		offsetof(struct sockaddr_in, sin_port)
824 #define TILL_CLIADDR		sizeof(struct sockaddr) + TILL_SVRADDR
825 #define TILL_CLIPORT		sizeof(struct sockaddr) + TILL_SVRPORT
826 #define TILL_CLIFAMILY		sizeof(struct sockaddr) + TILL_SVRFAMILY
827 
828 int
829 mtcp_getpeername(mctx_t mctx, int sockfd, struct sockaddr *saddr,
830 				 socklen_t *addrlen, int side)
831 {
832 	mtcp_manager_t mtcp;
833 	socket_map_t socket;
834 	struct tcp_stream *stream;
835 	struct sockaddr_in *sin;
836 	int rc;
837 
838 	mtcp = GetMTCPManager(mctx);
839 	if (!mtcp) {
840 		TRACE_DBG("Can't access MTCP manager!\n");
841 		errno = EACCES;
842 		return -1;
843 	}
844 
845 	/* check if sockfd is within limits */
846 	if (sockfd < 0 || sockfd >= g_config.mos->max_concurrency) {
847 		TRACE_API("Socket id %d out of range.\n", sockfd);
848 		errno = EBADF;
849 		return -1;
850 	}
851 
852 	/* check if the calling thread is in MOS context */
853 	if (mtcp->ctx->thread != pthread_self()) {
854 		errno = EPERM;
855 		return -1;
856 	}
857 
858 	socket = &mtcp->msmap[sockfd];
859 	sin = (struct sockaddr_in *)saddr;
860 	rc = 0;
861 
862 	/* retrieve both streams */
863 	stream = socket->monitor_stream->stream;
864 
865 	if (side != stream->side)
866 		stream = stream->pair_stream;
867 
868 	if (stream == NULL) {
869 		errno = ENOTCONN;
870 		return -1;
871 	}
872 
873 	/* reset to 2 * sizeof(struct sockaddr) if addrlen is too big */
874 	if (*addrlen > 2 * sizeof(struct sockaddr))
875 		*addrlen = 2 * sizeof(struct sockaddr);
876 
877 	/* according per manpage, address can be truncated */
878 	switch (*addrlen) {
879 	case (2 * sizeof(struct sockaddr)):
880 	case TILL_CLIADDR:
881 		sin[1].sin_addr.s_addr = stream->side == MOS_SIDE_SVR ?
882 								 stream->daddr : stream->saddr;
883 	case TILL_CLIPORT:
884 		sin[1].sin_port = stream->side == MOS_SIDE_SVR ?
885 						  stream->dport : stream->sport;
886 	case TILL_CLIFAMILY:
887 		sin[1].sin_family = AF_INET;
888 	case (sizeof(struct sockaddr)):
889 	case TILL_SVRADDR:
890 		sin->sin_addr.s_addr = stream->side == MOS_SIDE_SVR ?
891 							   stream->saddr : stream->daddr;
892 	case TILL_SVRPORT:
893 		sin->sin_port = stream->side == MOS_SIDE_SVR ?
894 						stream->sport : stream->dport;
895 	case TILL_SVRFAMILY:
896 		sin->sin_family = AF_INET;
897 		break;
898 	default:
899 		rc = -1;
900 		*addrlen = 0xFFFF;
901 		errno = EINVAL;
902 	}
903 
904 	return rc;
905 }
906 /*----------------------------------------------------------------------------*/
907 int
908 mtcp_setlastpkt(mctx_t mctx, int sock, int side, off_t offset,
909 		byte *data, uint16_t datalen, int option)
910 {
911 	mtcp_manager_t mtcp;
912 	struct pkt_ctx *cur_pkt_ctx;
913 	struct ethhdr *ethh;
914 	struct iphdr *iph;
915 	struct tcphdr *tcph;
916 	unsigned char *payload;
917 
918 #if 0
919 	socket_map_t socket;
920 	struct tcp_stream *cur_stream;
921 #endif
922 
923 	/* checking if mtcp is valid */
924 	mtcp = GetMTCPManager(mctx);
925 	if (!mtcp) {
926 		errno = EACCES;
927 		TRACE_ERROR("Invalid mtcp!\n");
928 		return -1;
929 	}
930 
931 	/* check if the calling thread is in MOS context */
932 	if (mtcp->ctx->thread != pthread_self()) {
933 		errno = EPERM;
934 		TRACE_ERROR("Invalid thread id!\n");
935 		return -1;
936 	}
937 
938 #if 0
939 	/* check if the socket is monitor stream */
940 	socket = &mtcp->msmap[sock];
941 	if (socket->socktype == MOS_SOCK_MONITOR_STREAM_ACTIVE) {
942 		if (side != MOS_SIDE_CLI && side != MOS_SIDE_SVR) {
943 			TRACE_ERROR("Invalid side requested!\n");
944 			exit(EXIT_FAILURE);
945 			return -1;
946 		}
947 
948 		struct tcp_stream *mstrm = socket->monitor_stream->stream;
949 		cur_stream = (side == mstrm->side) ? mstrm : mstrm->pair_stream;
950 
951 		if (!cur_stream->allow_pkt_modification)
952 			return -1;
953 	} else if (socket->socktype != MOS_SOCK_MONITOR_RAW) {
954 		TRACE_ERROR("Invalid socket type!\n");
955 		exit(EXIT_FAILURE);
956 		return -1;
957 	}
958 #endif
959 
960 	/* see if cur_pkt_ctx is valid */
961 	cur_pkt_ctx = mtcp->pctx;
962 	if (cur_pkt_ctx == NULL) {
963 		TRACE_ERROR("pctx is NULL!\n");
964 		errno = ENODATA;
965 		return -1;
966 	}
967 
968 	/* check if offset is valid */
969 	if (offset < 0) {
970 		TRACE_ERROR("Invalid offset position!\n");
971 		errno = EINVAL;
972 		return -1;
973 	}
974 
975 	if (__builtin_popcount(option & (MOS_DROP | MOS_CHOMP |
976 					 MOS_INSERT | MOS_OVERWRITE)) != 1) {
977 		TRACE_ERROR("mtcp_setlastpkt() function only allows one of "
978 			    "(MOS_DROP | MOS_CHOMP | MOS_INSERT | MOS_OVERWRITE) "
979 			    "to be set at a time.\n");
980 		errno = EAGAIN;
981 		return -1;
982 	}
983 
984 	/* drop pkt has the highest priority */
985 	if (option & MOS_DROP) {
986 		mtcp->pctx->forward = 0;
987 		return 0;
988 	} else if (option & MOS_ETH_HDR) {
989 		/* validity test */
990 		if ((ethh=cur_pkt_ctx->p.ethh) == NULL ||
991 		    offset + datalen > sizeof(struct ethhdr)) {
992 			TRACE_ERROR("Ethernet setting has gone out of bounds "
993 				    "(offset: %ld, datalen: %d)\n",
994 				    offset, datalen);
995 			errno = EINVAL;
996 			return -1;
997 		}
998 		if (option & MOS_CHOMP) {
999 			TRACE_ERROR("Illegal call. "
1000 				    "Ethernet header can't be chopped down!\n");
1001 			errno = EACCES;
1002 			return -1;
1003 		} else if (option & MOS_INSERT) {
1004 			TRACE_ERROR("Illegal call. "
1005 				    "Ethernet header can't be extended!\n");
1006 			errno = EACCES;
1007 			return -1;
1008 		} else /* if (option & MOS_OVERWRITE) */ {
1009 			memcpy((uint8_t *)ethh + offset, data, datalen);
1010 		}
1011 		/* iph, tcph, and payload do not need to change */
1012 	} else if (option & MOS_IP_HDR) {
1013 		/* validity test */
1014 		if (cur_pkt_ctx->p.ethh == NULL ||
1015 		    cur_pkt_ctx->p.ethh->h_proto != ntohs(ETH_P_IP) ||
1016 		    (iph=(struct iphdr *)(cur_pkt_ctx->p.ethh + 1)) == NULL) {
1017 			TRACE_ERROR("ethh or iph are out of bounds\n");
1018 			errno = EACCES;
1019 			return -1;
1020 		}
1021 		if (option & MOS_OVERWRITE) {
1022 			if (offset + datalen > (iph->ihl<<2)) {
1023 				TRACE_ERROR("IP setting has gone out of bounds "
1024 					    "(offset: %ld, datalen: %d)\n",
1025 					    offset, datalen);
1026 				errno = EINVAL;
1027 				return -1;
1028 			}
1029 			memcpy((uint8_t *)iph + offset, data, datalen);
1030 		}
1031 		if (option & MOS_CHOMP) {
1032 			memmove((uint8_t *)iph + offset,
1033 				(uint8_t *)iph + offset + datalen,
1034 				cur_pkt_ctx->p.ip_len - offset - datalen);
1035 
1036 			/* iph does not need to change */
1037 			if (iph->protocol == IPPROTO_TCP) {
1038 				cur_pkt_ctx->p.tcph = (struct tcphdr *)((uint8_t *)iph + (iph->ihl<<2));
1039 				cur_pkt_ctx->p.payload = (uint8_t *)cur_pkt_ctx->p.tcph +
1040 					(cur_pkt_ctx->p.tcph->doff<<2);
1041 			} else {
1042 				/* reset tcph if iph does not have tcp proto */
1043 				cur_pkt_ctx->p.tcph = NULL;
1044 			}
1045 			/* update iph total length */
1046 			cur_pkt_ctx->p.ip_len = ntohs(iph->tot_len);
1047 			/* update eth frame length */
1048 			cur_pkt_ctx->p.eth_len = cur_pkt_ctx->p.ip_len + sizeof(struct ethhdr);
1049 		} else if (option & MOS_INSERT) {
1050 			memmove((uint8_t *)iph + offset + datalen,
1051 				(uint8_t *)iph + offset + 1,
1052 				cur_pkt_ctx->p.ip_len - offset);
1053 			memcpy((uint8_t *)iph + offset,
1054 			       data, datalen);
1055 
1056 			/* iph does not need to change */
1057 			if (iph->protocol == IPPROTO_TCP) {
1058 				cur_pkt_ctx->p.tcph = (struct tcphdr *)((uint8_t *)iph + (iph->ihl<<2));
1059 				cur_pkt_ctx->p.payload = (uint8_t *)cur_pkt_ctx->p.tcph +
1060 					(cur_pkt_ctx->p.tcph->doff<<2);
1061 			} else {
1062 				/* reset tcph if iph does not have tcp proto */
1063 				cur_pkt_ctx->p.tcph = NULL;
1064 			}
1065 			/* update iph total length */
1066 			cur_pkt_ctx->p.ip_len = ntohs(iph->tot_len);
1067 			/* update eth frame length */
1068 			cur_pkt_ctx->p.eth_len = cur_pkt_ctx->p.ip_len + sizeof(struct ethhdr);
1069 		}
1070 		/* can't update payloadlen because we don't know tcph->doff */
1071 	} else if (option & MOS_TCP_HDR) {
1072 		/* validity test */
1073 		iph = (struct iphdr *)(cur_pkt_ctx->p.ethh + 1);
1074 		if (iph == NULL ||
1075 		    iph->protocol != IPPROTO_TCP ||
1076 		    (tcph=(struct tcphdr *)((uint8_t *)iph + (iph->ihl<<2))) == NULL) {
1077 			TRACE_ERROR("TCP setting has gone out of bounds "
1078 				    "(offset: %ld, datalen: %d)\n",
1079 				    offset, datalen);
1080 			errno = EINVAL;
1081 			return -1;
1082 		}
1083 		if (option & MOS_OVERWRITE) {
1084 			if (offset + datalen > (tcph->doff<<2)) {
1085 				TRACE_ERROR("TCP setting has gone out of bounds "
1086 					    "(offset: %ld, datalen: %d)\n",
1087 					    offset, datalen);
1088 				errno = EINVAL;
1089 				return -1;
1090 			}
1091 			memcpy((uint8_t *)tcph + offset, data, datalen);
1092 			/* update tcp seq # */
1093 			cur_pkt_ctx->p.seq = ntohl(tcph->seq);
1094 			/* update tcp ack_seq # */
1095 			cur_pkt_ctx->p.ack_seq = ntohl(tcph->ack_seq);
1096 			/* update tcp window */
1097 			cur_pkt_ctx->p.window = ntohs(tcph->window);
1098 
1099 			/* 150422 dhkim TODO: seq and offset are two different form of same
1100 			 * variable. We also need to update the offset. */
1101 		}
1102 		if (option & MOS_CHOMP) {
1103 			memmove((uint8_t *)tcph + offset,
1104 				(uint8_t *)tcph + offset + datalen,
1105 				cur_pkt_ctx->p.payloadlen + (tcph->doff<<2)
1106 				- offset - datalen);
1107 			/* update payload ptr */
1108 			cur_pkt_ctx->p.payload = (uint8_t *)tcph + (tcph->doff<<2);
1109 		} else if (option & MOS_INSERT) {
1110 			memmove((uint8_t *)tcph + offset + datalen,
1111 				(uint8_t *)tcph + offset + 1,
1112 				cur_pkt_ctx->p.payloadlen + (tcph->doff<<2)
1113 				- offset);
1114 			memcpy((uint8_t *)tcph + offset, data, datalen);
1115 			/* update payload ptr */
1116 			cur_pkt_ctx->p.payload = (uint8_t *)tcph + (tcph->doff<<2);
1117 		}
1118 	} else if (option & MOS_TCP_PAYLOAD) {
1119 		iph = (struct iphdr *)(cur_pkt_ctx->p.ethh + 1);
1120 		tcph = (struct tcphdr *)((uint8_t *)iph + (iph->ihl<<2));
1121 		payload = (uint8_t *)tcph + (tcph->doff<<2);
1122 		if (option & MOS_OVERWRITE) {
1123 			if (offset + datalen > ntohs(iph->tot_len) -
1124 			    (iph->ihl<<2) - (tcph->doff<<2)) {
1125 				TRACE_ERROR("Payload setting has gone out of bounds "
1126 					    "(offset: %ld, datalen: %d)\n",
1127 					    offset, datalen);
1128 				errno = EINVAL;
1129 				return -1;
1130 			}
1131 			memcpy(payload + offset, data, datalen);
1132 		}
1133 		if (option & MOS_CHOMP) {
1134 			memmove(payload + offset,
1135 				payload + offset + datalen,
1136 				(cur_pkt_ctx->p.payloadlen -
1137 				 offset - datalen));
1138 			/* update payload length */
1139 			cur_pkt_ctx->p.payloadlen = cur_pkt_ctx->p.ip_len -
1140 				(tcph->doff<<2) - (iph->ihl<<2);
1141 		} else if (option & MOS_INSERT) {
1142 			memmove(payload + offset + datalen,
1143 				payload + offset + 1,
1144 				cur_pkt_ctx->p.payloadlen - offset);
1145 			memcpy(payload + offset, data, datalen);
1146 			cur_pkt_ctx->p.payloadlen = cur_pkt_ctx->p.ip_len -
1147 				(tcph->doff<<2) - (iph->ihl<<2);
1148 		}
1149 	} else {
1150 		TRACE_ERROR("Invalid option!\n");
1151 		errno = EINVAL;
1152 		return -1;
1153 	}
1154 
1155 	/* update ip checksum */
1156 	if (option & MOS_UPDATE_IP_CHKSUM) {
1157 		iph = (struct iphdr *)(cur_pkt_ctx->p.ethh + 1);
1158 		iph->check = 0;
1159 		iph->check = ip_fast_csum(iph, iph->ihl);
1160 	}
1161 
1162 	/* update tcp checksum */
1163 	if (option & MOS_UPDATE_TCP_CHKSUM) {
1164 		iph = (struct iphdr *)(cur_pkt_ctx->p.ethh + 1);
1165 		tcph = (struct tcphdr *)((uint8_t *)iph + (iph->ihl<<2));
1166 		tcph->check = 0;
1167 		tcph->check = TCPCalcChecksum((uint16_t *)tcph,
1168 					      ntohs(iph->tot_len) - (iph->ihl<<2),
1169 					      iph->saddr, iph->daddr);
1170 	}
1171 	return 0;
1172 }
1173 /*----------------------------------------------------------------------------*/
1174 #if 0
1175 inline int
1176 mtcp_cb_updatecurpkt(mctx_t mctx, off_t offset, unsigned char *data,
1177 		     uint16_t datalen, int option)
1178 {
1179 	return mtcp_setlastpkt(mctx, sock, side, offset, data, datalen, option);
1180 }
1181 #endif
1182 /*----------------------------------------------------------------------------*/
1183 /**
1184  * THIS IS A DEPRECETED FUNCTION...
1185  */
1186 int
1187 mtcp_cb_dropcurpkt(mctx_t mctx)
1188 {
1189 	mtcp_manager_t mtcp;
1190 
1191 	/* checking if mtcp is valid */
1192 	mtcp = GetMTCPManager(mctx);
1193 	if (!mtcp) {
1194 		TRACE_ERROR("Invalid mtcp!\n");
1195 		errno = EACCES;
1196 		return -1;
1197 	}
1198 
1199 	/* check if the calling thread is in MOS context */
1200 	if (mtcp->ctx->thread != pthread_self()) {
1201 		TRACE_ERROR("Invalid thread id!\n");
1202 		errno = EPERM;
1203 		return -1;
1204 	}
1205 
1206 	/* see if cur_pkt_ctx is valid */
1207 	if (mtcp->pctx == NULL) {
1208 		TRACE_ERROR("pctx is NULL!\n");
1209 		errno = ENODATA;
1210 		return -1;
1211 	}
1212 
1213 	mtcp->pctx->forward = 0;
1214 
1215 	return 0;
1216 }
1217 /*----------------------------------------------------------------------------*/
1218 int
1219 mtcp_set_debug_string(mtcp_manager_t mtcp, const char *fmt, ...)
1220 {
1221 #ifdef ENABLE_DEBUG_EVENT
1222 	va_list args;
1223 	int i;
1224 
1225 	assert(mtcp);
1226 
1227 	if (fmt == NULL) {
1228 		mtcp->dbg_buf[0] = '\0';
1229 		return 0;
1230 	}
1231 
1232 	va_start(args, fmt);
1233 	i = vsnprintf(mtcp->dbg_buf, DBG_BUF_LEN - 1, fmt, args);
1234 	va_end(args);
1235 
1236 	return i;
1237 #else
1238 	return -1;
1239 #endif /* ENABLE_DEBUG_EVENT */
1240 }
1241 /*----------------------------------------------------------------------------*/
1242 int
1243 mtcp_get_debug_string(mctx_t mctx, char *buf, int len)
1244 {
1245 #ifdef ENABLE_DEBUG_EVENT
1246 	mtcp_manager_t mtcp;
1247 	int copylen;
1248 
1249 	if (len < 0)
1250 		return -1;
1251 	else if (len == 0)
1252 		return 0;
1253 
1254 	if (!(mtcp = GetMTCPManager(mctx)))
1255 		return -1;
1256 
1257 	copylen = MIN(strlen(mtcp->dbg_buf), len);
1258 	strncpy(buf, mtcp->dbg_buf, copylen);
1259 
1260 	return copylen;
1261 #else
1262 	return -1;
1263 #endif /* ENABLE_DEBUG_EVENT */
1264 }
1265 /*----------------------------------------------------------------------------*/
1266