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