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 #ifdef NEWRB 289 tcprb_t *rcvbuf = cur_stream->rcvvar->rcvbuf; 290 loff_t *poff = &sock->monitor_stream->peek_offset[cur_stream->side]; 291 292 rc = tcprb_ppeek(rcvbuf, (uint8_t *)buf, len, *poff); 293 if (rc < 0) { 294 errno = ENODATA; 295 return -1; 296 } 297 298 *poff += rc; 299 UNUSED(copylen); 300 301 return rc; 302 #else 303 struct tcp_ring_buffer *rcvbuf; 304 uint32_t *monitor_read_head_offset_ptr; 305 uint8_t *overlap_ptr; 306 /* assign monitor-related ptrs */ 307 rcvbuf = cur_stream->rcvvar->rcvbuf; 308 monitor_read_head_offset_ptr = &sock->monitor_stream->monitor_read.head_offset[cur_stream->side]; 309 overlap_ptr = &sock->monitor_stream->monitor_read.overlap[cur_stream->side]; 310 311 /* 312 * if the head ptr is way back than monitor offset... 313 * then head ptr has looped around.. use m_tail_offset as 314 * reference 315 */ 316 if (rcvbuf->head_offset + rcvbuf->merged_len < 317 *monitor_read_head_offset_ptr) 318 copylen = MIN(rcvbuf->monitor_read_tail_offset - 319 *monitor_read_head_offset_ptr, 320 len); 321 /* 322 * if the head ptr is ahead of monitor offset... 323 * then read till head + merged length 324 */ 325 else 326 copylen = MIN(rcvbuf->head_offset + 327 rcvbuf->merged_len - 328 *monitor_read_head_offset_ptr, 329 len); 330 memcpy(buf, rcvbuf->data + *monitor_read_head_offset_ptr, copylen); 331 *monitor_read_head_offset_ptr += copylen; 332 rc = copylen; 333 if (*overlap_ptr) { 334 *overlap_ptr = 0; 335 rc = -1; 336 } 337 #endif 338 } else { 339 TRACE_DBG("Stream hasn't yet been initialized!\n"); 340 rc = 0; 341 } 342 343 return rc; 344 } 345 /*----------------------------------------------------------------------------*/ 346 /** 347 * Copies from the frags.. returns no. of bytes copied to buf 348 */ 349 static inline int 350 ExtractPayloadFromFrags(struct tcp_ring_buffer *rcvbuf, char *buf, 351 size_t count, off_t seq_num) 352 { 353 int cpbytesleft; 354 struct fragment_ctx *it; 355 356 it = rcvbuf->fctx; 357 cpbytesleft = count; 358 /* go through each frag */ 359 while (it) { 360 /* first check whether sequent number matches */ 361 if (TCP_SEQ_BETWEEN(seq_num, it->seq, it->seq + it->len)) { 362 /* copy buf starting from seq# seq_num */ 363 /* copy the MIN of seq-range and bytes to be copied */ 364 memcpy(buf + count - cpbytesleft, 365 rcvbuf->head + seq_num - rcvbuf->head_seq, 366 MIN(it->len - (seq_num - it->seq), cpbytesleft)); 367 /* update target seq num */ 368 seq_num += it->len - (seq_num - it->seq); 369 /* update cpbytes left */ 370 cpbytesleft -= it->len - (seq_num - it->seq); 371 if (cpbytesleft == 0) 372 break; 373 } 374 it = it->next; 375 } 376 377 count -= cpbytesleft; 378 379 /* return number of bytes copied */ 380 return count; 381 } 382 /*----------------------------------------------------------------------------*/ 383 /* Please see in-code comments for description */ 384 ssize_t 385 #ifdef NEWPPEEK 386 mtcp_ppeek(mctx_t mctx, int msock, int side, 387 char *buf, size_t count, uint64_t off) 388 #else 389 mtcp_ppeek(mctx_t mctx, int msock, int side, 390 char *buf, size_t count, off_t seq_num) 391 #endif 392 { 393 mtcp_manager_t mtcp; 394 struct tcp_stream *cur_stream; 395 int rc; 396 socket_map_t sock; 397 398 mtcp = GetMTCPManager(mctx); 399 if (!mtcp) { 400 errno = EACCES; 401 goto ppeek_error; 402 } 403 404 /* check if the calling thread is in MOS context */ 405 if (mtcp->ctx->thread != pthread_self()) { 406 errno = EPERM; 407 goto ppeek_error; 408 } 409 410 /* check if the socket is monitor stream */ 411 sock = &mtcp->msmap[msock]; 412 if (sock->socktype != MOS_SOCK_MONITOR_STREAM_ACTIVE) { 413 TRACE_DBG("Invalid socket type!\n"); 414 errno = ESOCKTNOSUPPORT; 415 goto ppeek_error; 416 } 417 418 if (side != MOS_SIDE_CLI && side != MOS_SIDE_SVR) { 419 TRACE_ERROR("Invalid side requested!\n"); 420 exit(EXIT_FAILURE); 421 return -1; 422 } 423 424 struct tcp_stream *mstrm = sock->monitor_stream->stream; 425 cur_stream = (side == mstrm->side) ? mstrm : mstrm->pair_stream; 426 427 if (!cur_stream || !cur_stream->buffer_mgmt) { 428 TRACE_DBG("Stream is either NULL or ring buffer is not managed!!\n"); 429 errno = EACCES; 430 goto ppeek_error; 431 } 432 433 rc = 0; 434 /* Check if the read was not just due to syn-ack recv */ 435 if (cur_stream->rcvvar != NULL && 436 cur_stream->rcvvar->rcvbuf != NULL) { 437 #ifdef NEWRB 438 tcprb_t *rcvbuf = cur_stream->rcvvar->rcvbuf; 439 #ifndef NEWPPEEK 440 loff_t off = seq2loff(rcvbuf, seq_num, cur_stream->rcvvar->irs + 1); 441 #endif 442 return tcprb_ppeek(rcvbuf, (uint8_t *)buf, count, off); 443 #else 444 struct tcp_ring_buffer *rcvbuf = cur_stream->rcvvar->rcvbuf; 445 446 /* Next calculate the lowest sequence number in ring buffer */ 447 off_t lwst_seq_num = 0; 448 if (rcvbuf->monitor_read_tail_offset == 0) { 449 lwst_seq_num = rcvbuf->head_seq - rcvbuf->head_offset; 450 } 451 else { 452 lwst_seq_num = rcvbuf->head_seq - 453 (rcvbuf->head_offset + 454 rcvbuf->monitor_read_tail_offset - 455 rcvbuf->tail_offset); 456 } 457 /* 458 * if the requested payload is within the frags then 459 * copy the payload from frags (if possible) 460 */ 461 if (TCP_SEQ_BETWEEN(seq_num, rcvbuf->head_seq + rcvbuf->merged_len, 462 rcvbuf->head_seq + rcvbuf->last_len)) { 463 /* if no bytes copied... then return error */ 464 if ((rc=ExtractPayloadFromFrags(rcvbuf, buf, count, seq_num)) == 0) { 465 errno = EAGAIN; 466 goto ppeek_error; 467 } else { 468 /* set count to the number of bytes actually copied */ 469 count = rc; 470 /* function was a success.. record it! */ 471 //rc = 0; 472 } 473 } else if (TCP_SEQ_BETWEEN(seq_num, lwst_seq_num, rcvbuf->head_seq + rcvbuf->merged_len)) { 474 /* 475 * else if the requested payload is on or before 476 * the received data 477 */ 478 479 /* first go back to the starting offset */ 480 int cpbytesleft; 481 off_t start; 482 int distance; 483 484 if (lwst_seq_num > seq_num) { 485 errno = EAGAIN; 486 goto ppeek_error; 487 } else 488 lwst_seq_num = seq_num; 489 490 start = 0; 491 distance = rcvbuf->head_seq - lwst_seq_num; 492 cpbytesleft = count; 493 494 /* if the distance is longer than the head_offset (needs a wrap-around) */ 495 if (distance > rcvbuf->head_offset) { 496 /* first calculate the start offset */ 497 start = rcvbuf->monitor_read_tail_offset - (distance - rcvbuf->head_offset); 498 /* get the bytes copy value for 1st part */ 499 cpbytesleft = count - MIN(rcvbuf->monitor_read_tail_offset - start, count); 500 /* do the memcpy */ 501 memcpy(buf, rcvbuf->data + start, 502 MIN(rcvbuf->monitor_read_tail_offset - start, count)); 503 if (cpbytesleft == 0) { 504 rc = 0; 505 } else { 506 /* do the 2nd memcpy */ 507 memcpy(buf + rcvbuf->monitor_read_tail_offset - start, 508 rcvbuf->data, 509 MIN(distance - (rcvbuf->monitor_read_tail_offset - start), 510 cpbytesleft)); 511 cpbytesleft = cpbytesleft - 512 MIN(distance - (rcvbuf->monitor_read_tail_offset - start), 513 cpbytesleft); 514 count = count - cpbytesleft; 515 } 516 } else { /* if the distance is shorter */ 517 start = rcvbuf->head_offset - distance; 518 count = MIN(distance, count); 519 memcpy(buf, rcvbuf->data + start, MIN(distance, count)); 520 } 521 rc = count; 522 } else { 523 errno = ERANGE; 524 goto ppeek_error; 525 } 526 #endif 527 } else { 528 errno = EPERM; 529 goto ppeek_error; 530 } 531 532 return rc; 533 534 ppeek_error: 535 return -1; 536 } 537 /*----------------------------------------------------------------------------*/ 538 #ifdef MTCP_CB_GETCURPKT_CREATE_COPY 539 static __thread unsigned char local_frame[ETHERNET_FRAME_LEN]; 540 inline struct pkt_info * 541 ClonePacketCtx(struct pkt_info *to, unsigned char *frame, struct pkt_ctx *from) 542 { 543 /* only memcpy till the last field before ethh */ 544 /* memcpy(to, from, PCTX_COPY_LEN); */ 545 memcpy(to, &(from->p), PKT_INFO_LEN); 546 /* memcpy the entire ethernet frame */ 547 assert(from); 548 assert(from->p.eth_len > 0); 549 assert(from->p.eth_len <= ETHERNET_FRAME_LEN); 550 memcpy(frame, from->p.ethh, from->p.eth_len); 551 /* set iph */ 552 to->ethh = (struct ethhdr *)frame; 553 /* set iph */ 554 to->iph = from->p.iph ? 555 (struct iphdr *)((uint8_t *)(frame + ETHERNET_HEADER_LEN)) : NULL; 556 /* set tcph */ 557 to->tcph = from->p.tcph ? 558 (struct tcphdr *)(((uint8_t *)(to->iph)) + (to->iph->ihl<<2)) : NULL; 559 /* set payload */ 560 to->payload = from->p.tcph ? 561 ((uint8_t *)(to->tcph) + (to->tcph->doff<<2)) : NULL; 562 return to; 563 } 564 /*----------------------------------------------------------------------------*/ 565 int 566 mtcp_getlastpkt(mctx_t mctx, int sock, int side, struct pkt_info *pkt) 567 { 568 mtcp_manager_t mtcp; 569 socket_map_t socket; 570 struct tcp_stream *cur_stream; 571 struct pkt_ctx *cur_pkt_ctx; 572 573 mtcp = GetMTCPManager(mctx); 574 if (!mtcp) { 575 errno = EACCES; 576 return -1; 577 } 578 579 /* check if the calling thread is in MOS context */ 580 if (mtcp->ctx->thread != pthread_self()) { 581 errno = EPERM; 582 return -1; 583 } 584 585 /* check if the socket is monitor stream */ 586 socket = &mtcp->msmap[sock]; 587 588 if (socket->socktype == MOS_SOCK_MONITOR_STREAM_ACTIVE) { 589 if (side != MOS_SIDE_CLI && side != MOS_SIDE_SVR) { 590 TRACE_ERROR("Invalid side requested!\n"); 591 exit(EXIT_FAILURE); 592 return -1; 593 } 594 595 struct tcp_stream *mstrm = socket->monitor_stream->stream; 596 cur_stream = (side == mstrm->side) ? mstrm : mstrm->pair_stream; 597 598 cur_pkt_ctx = &cur_stream->last_pctx; 599 if (!cur_pkt_ctx->p.ethh) { 600 errno = ENODATA; 601 return -1; 602 } 603 } else if (socket->socktype == MOS_SOCK_MONITOR_RAW) { 604 cur_pkt_ctx = mtcp->pctx; 605 } else if (socket->socktype == MOS_SOCK_MONITOR_STREAM) { 606 /* 607 * if it is a monitor socket, then this means that 608 * this is a request for an orphan tcp packet 609 */ 610 cur_pkt_ctx = mtcp->pctx; 611 } else { 612 TRACE_DBG("Invalid socket type!\n"); 613 errno = EBADF; 614 return -1; 615 } 616 617 ClonePacketCtx(pkt, local_frame, cur_pkt_ctx); 618 return 0; 619 } 620 #else 621 /*----------------------------------------------------------------------------*/ 622 int 623 mtcp_getlastpkt(mctx_t mctx, int sock, int side, struct pkt_ctx **pctx) 624 { 625 mtcp_manager_t mtcp; 626 627 mtcp = GetMTCPManager(mctx); 628 if (!mtcp) { 629 errno = EACCES; 630 return -1; 631 } 632 633 /* check if the calling thread is in MOS context */ 634 if (mtcp->ctx->thread != pthread_self()) { 635 errno = EPERM; 636 return -1; 637 } 638 /* just pass direct pointer */ 639 *pctx = mtcp->pctx; 640 641 return 0; 642 } 643 #endif 644 /*----------------------------------------------------------------------------*/ 645 /** Disable events from the monitor stream socket 646 * @param [in] mtcp: mtcp_manager 647 * @param [in] sock: socket 648 * 649 * returns 0 on success, -1 on failure 650 * 651 * This is used for flow management based monitoring sockets 652 */ 653 int 654 RemoveMonitorEvents(mtcp_manager_t mtcp, socket_map_t socket, int side) 655 { 656 struct mon_stream *mstream; 657 struct mon_listener *mlistener; 658 659 if (mtcp == NULL) { 660 TRACE_DBG("mtcp is not defined!!!\n"); 661 errno = EACCES; 662 return -1; 663 } 664 665 switch (socket->socktype) { 666 case MOS_SOCK_MONITOR_STREAM_ACTIVE: 667 mstream = socket->monitor_stream; 668 if (mstream == NULL) { 669 TRACE_ERROR("Mon Stream does not exist!\n"); 670 /* exit(-1); */ 671 errno = ENODATA; 672 return -1; 673 } 674 675 if (side == MOS_SIDE_SVR) mstream->server_mon = 0; 676 else if (side == MOS_SIDE_CLI) mstream->client_mon = 0; 677 678 if (mstream->server_mon == 0 && mstream->client_mon == 0) { 679 #ifdef NEWEV 680 /* 681 * if stree_dontcare is NULL, then we know that all 682 * events have already been disabled 683 */ 684 if (mstream->stree_pre_rcv != NULL) { 685 stree_dec_ref(mtcp->ev_store, mstream->stree_dontcare); 686 stree_dec_ref(mtcp->ev_store, mstream->stree_pre_rcv); 687 stree_dec_ref(mtcp->ev_store, mstream->stree_post_snd); 688 689 mstream->stree_dontcare = NULL; 690 mstream->stree_pre_rcv = NULL; 691 mstream->stree_post_snd = NULL; 692 } 693 #else 694 /* no error checking over here.. 695 * but its okay.. this code is 696 * deprecated 697 */ 698 CleanupEvP(&mstream->dontcare_evp); 699 CleanupEvP(&mstream->pre_tcp_evp); 700 CleanupEvP(&mstream->post_tcp_evp); 701 #endif 702 } 703 break; 704 case MOS_SOCK_MONITOR_STREAM: 705 mlistener = socket->monitor_listener; 706 if (mlistener == NULL) { 707 TRACE_ERROR("Mon listener does not exist!\n"); 708 errno = ENODATA; 709 return -1; 710 } 711 712 if (side == MOS_SIDE_SVR) mlistener->server_mon = 0; 713 else if (side == MOS_SIDE_CLI) mlistener->client_mon = 0; 714 715 if (mlistener->server_mon == 0 && mlistener->client_mon == 0) { 716 #ifdef NEWEV 717 /* 718 * if stree_dontcare is NULL, then we know that all 719 * events have already been disabled 720 */ 721 if (mlistener->stree_pre_rcv != NULL) { 722 stree_dec_ref(mtcp->ev_store, mlistener->stree_dontcare); 723 stree_dec_ref(mtcp->ev_store, mlistener->stree_pre_rcv); 724 stree_dec_ref(mtcp->ev_store, mlistener->stree_post_snd); 725 726 mlistener->stree_dontcare = NULL; 727 mlistener->stree_pre_rcv = NULL; 728 mlistener->stree_post_snd = NULL; 729 } 730 #else 731 /* no error checking over here.. 732 * but its okay.. this code is 733 * deprecated 734 */ 735 CleanupEvB(mtcp, &mlistener->dontcare_evb); 736 CleanupEvB(mtcp, &mlistener->pre_tcp_evb); 737 CleanupEvB(mtcp, &mlistener->post_tcp_evb); 738 #endif 739 } 740 break; 741 default: 742 TRACE_ERROR("Invalid socket type!\n"); 743 } 744 745 return 0; 746 } 747 /*----------------------------------------------------------------------------*/ 748 /** 749 * Disable monitoring based on side variable. 750 */ 751 int 752 mtcp_cb_stop(mctx_t mctx, int sock, int side) 753 { 754 mtcp_manager_t mtcp; 755 socket_map_t socket; 756 struct tcp_stream *stream; 757 struct socket_map *walk; 758 uint8_t mgmt; 759 760 mtcp = GetMTCPManager(mctx); 761 if (!mtcp) { 762 errno = EACCES; 763 return -1; 764 } 765 766 socket = &mtcp->msmap[sock]; 767 768 /* works for both monitor listener and stream sockets */ 769 RemoveMonitorEvents(mtcp, socket, side); 770 771 /* passive monitoring socket is not connected to any stream */ 772 if (socket->socktype == MOS_SOCK_MONITOR_STREAM) 773 return 0; 774 775 if (side == MOS_SIDE_CLI) { 776 /* see if the associated stream requires monitoring any more */ 777 stream = (socket->monitor_stream->stream->side == MOS_SIDE_CLI) ? 778 socket->monitor_stream->stream : 779 socket->monitor_stream->stream->pair_stream; 780 781 mgmt = 0; 782 SOCKQ_FOREACH_START(walk, &stream->msocks) { 783 if (walk->monitor_stream->client_mon == 1) { 784 mgmt = 1; 785 break; 786 } 787 } SOCKQ_FOREACH_END; 788 /* if all streams have mgmt off, then tag the stream for destruction */ 789 if (mgmt == 0) { 790 stream = (socket->monitor_stream->stream->side == MOS_SIDE_CLI) ? 791 socket->monitor_stream->stream : 792 socket->monitor_stream->stream->pair_stream; 793 stream->status_mgmt = 0; 794 } 795 } 796 797 if (side == MOS_SIDE_SVR) { 798 /* see if the associated stream requires monitoring any more */ 799 stream = (socket->monitor_stream->stream->side == MOS_SIDE_SVR) ? 800 socket->monitor_stream->stream : 801 socket->monitor_stream->stream->pair_stream; 802 mgmt = 0; 803 SOCKQ_FOREACH_START(walk, &stream->msocks) { 804 if (walk->monitor_stream->server_mon == 1) { 805 mgmt = 1; 806 break; 807 } 808 } SOCKQ_FOREACH_END; 809 /* if all streams have mgmt off, then tag the stream for destruction */ 810 if (mgmt == 0) { 811 stream = (socket->monitor_stream->stream->side == MOS_SIDE_SVR) ? 812 socket->monitor_stream->stream : 813 socket->monitor_stream->stream->pair_stream; 814 stream->status_mgmt = 0; 815 } 816 } 817 818 return 0; 819 } 820 /*----------------------------------------------------------------------------*/ 821 /** 822 * send a RST packet to the TCP stream (uni-directional) 823 */ 824 static inline void 825 SendRSTPacketStandalone(mtcp_manager_t mtcp, struct tcp_stream *stream) { 826 SendTCPPacketStandalone(mtcp, 827 stream->saddr, stream->sport, stream->daddr, stream->dport, 828 stream->snd_nxt, stream->rcv_nxt, 0, TCP_FLAG_RST | TCP_FLAG_ACK, 829 NULL, 0, mtcp->cur_ts, 0); 830 } 831 /*----------------------------------------------------------------------------*/ 832 /** 833 * Reset the connection (send RST packets to both sides) 834 */ 835 int 836 mtcp_reset_conn(mctx_t mctx, int sock) 837 { 838 mtcp_manager_t mtcp; 839 socket_map_t socket; 840 841 mtcp = GetMTCPManager(mctx); 842 if (!mtcp) { 843 errno = EACCES; 844 return -1; 845 } 846 847 socket = &mtcp->msmap[sock]; 848 849 /* passive monitoring socket is not connected to any stream */ 850 if (socket->socktype == MOS_SOCK_MONITOR_STREAM) { 851 errno = EINVAL; 852 return -1; 853 } 854 855 /* send RST packets to the both sides */ 856 SendRSTPacketStandalone(mtcp, socket->monitor_stream->stream); 857 SendRSTPacketStandalone(mtcp, socket->monitor_stream->stream->pair_stream); 858 859 return 0; 860 } 861 /*----------------------------------------------------------------------------*/ 862 uint32_t 863 mtcp_cb_get_ts(mctx_t mctx) 864 { 865 mtcp_manager_t mtcp; 866 867 mtcp = GetMTCPManager(mctx); 868 if (!mtcp) { 869 TRACE_DBG("Can't access MTCP manager!\n"); 870 errno = EACCES; 871 return 0; 872 } 873 874 /* check if the calling thread is in MOS context */ 875 if (mtcp->ctx->thread != pthread_self()) { 876 errno = EPERM; 877 return 0; 878 } 879 880 return TS_TO_USEC(mtcp->cur_ts); 881 } 882 /*----------------------------------------------------------------------------*/ 883 /* Macros related to getpeername */ 884 #define TILL_SVRADDR offsetof(struct sockaddr_in, sin_zero) 885 #define TILL_SVRPORT offsetof(struct sockaddr_in, sin_addr) 886 #define TILL_SVRFAMILY offsetof(struct sockaddr_in, sin_port) 887 #define TILL_CLIADDR sizeof(struct sockaddr) + TILL_SVRADDR 888 #define TILL_CLIPORT sizeof(struct sockaddr) + TILL_SVRPORT 889 #define TILL_CLIFAMILY sizeof(struct sockaddr) + TILL_SVRFAMILY 890 891 int 892 mtcp_getpeername(mctx_t mctx, int sockfd, struct sockaddr *saddr, 893 socklen_t *addrlen, int side) 894 { 895 mtcp_manager_t mtcp; 896 socket_map_t socket; 897 struct tcp_stream *stream; 898 struct sockaddr_in *sin; 899 int rc; 900 901 mtcp = GetMTCPManager(mctx); 902 if (!mtcp) { 903 TRACE_DBG("Can't access MTCP manager!\n"); 904 errno = EACCES; 905 return -1; 906 } 907 908 /* check if the calling thread is in MOS context */ 909 if (mtcp->ctx->thread != pthread_self()) { 910 errno = EPERM; 911 return -1; 912 } 913 914 socket = &mtcp->msmap[sockfd]; 915 sin = (struct sockaddr_in *)saddr; 916 rc = 0; 917 918 /* retrieve both streams */ 919 stream = socket->monitor_stream->stream; 920 921 if (side != stream->side) 922 stream = stream->pair_stream; 923 924 if (stream == NULL) 925 return -1; 926 927 /* reset to 2 * sizeof(struct sockaddr) if addrlen is too big */ 928 if (*addrlen > 2 * sizeof(struct sockaddr)) 929 *addrlen = 2 * sizeof(struct sockaddr); 930 931 /* according per manpage, address can be truncated */ 932 switch (*addrlen) { 933 case (2 * sizeof(struct sockaddr)): 934 case TILL_CLIADDR: 935 sin[1].sin_addr.s_addr = stream->side == MOS_SIDE_SVR ? 936 stream->daddr : stream->saddr; 937 case TILL_CLIPORT: 938 sin[1].sin_port = stream->side == MOS_SIDE_SVR ? 939 stream->dport : stream->sport; 940 case TILL_CLIFAMILY: 941 sin[1].sin_family = AF_INET; 942 case (sizeof(struct sockaddr)): 943 case TILL_SVRADDR: 944 sin->sin_addr.s_addr = stream->side == MOS_SIDE_SVR ? 945 stream->saddr : stream->daddr; 946 case TILL_SVRPORT: 947 sin->sin_port = stream->side == MOS_SIDE_SVR ? 948 stream->sport : stream->dport; 949 case TILL_SVRFAMILY: 950 sin->sin_family = AF_INET; 951 break; 952 default: 953 rc = -1; 954 *addrlen = 0xFFFF; 955 } 956 957 return rc; 958 } 959 /*----------------------------------------------------------------------------*/ 960 int 961 mtcp_setlastpkt(mctx_t mctx, int sock, int side, off_t offset, 962 byte *data, uint16_t datalen, int option) 963 { 964 mtcp_manager_t mtcp; 965 struct pkt_ctx *cur_pkt_ctx; 966 struct ethhdr *ethh; 967 struct iphdr *iph; 968 struct tcphdr *tcph; 969 unsigned char *payload; 970 971 #if 0 972 socket_map_t socket; 973 struct tcp_stream *cur_stream; 974 #endif 975 976 /* checking if mtcp is valid */ 977 mtcp = GetMTCPManager(mctx); 978 if (!mtcp) { 979 errno = EACCES; 980 TRACE_ERROR("Invalid mtcp!\n"); 981 return -1; 982 } 983 984 /* check if the calling thread is in MOS context */ 985 if (mtcp->ctx->thread != pthread_self()) { 986 errno = EPERM; 987 TRACE_ERROR("Invalid thread id!\n"); 988 return -1; 989 } 990 991 #if 0 992 /* check if the socket is monitor stream */ 993 socket = &mtcp->msmap[sock]; 994 if (socket->socktype == MOS_SOCK_MONITOR_STREAM_ACTIVE) { 995 if (side != MOS_SIDE_CLI && side != MOS_SIDE_SVR) { 996 TRACE_ERROR("Invalid side requested!\n"); 997 exit(EXIT_FAILURE); 998 return -1; 999 } 1000 1001 struct tcp_stream *mstrm = socket->monitor_stream->stream; 1002 cur_stream = (side == mstrm->side) ? mstrm : mstrm->pair_stream; 1003 1004 if (!cur_stream->allow_pkt_modification) 1005 return -1; 1006 } else if (socket->socktype != MOS_SOCK_MONITOR_RAW) { 1007 TRACE_ERROR("Invalid socket type!\n"); 1008 exit(EXIT_FAILURE); 1009 return -1; 1010 } 1011 #endif 1012 1013 /* see if cur_pkt_ctx is valid */ 1014 cur_pkt_ctx = mtcp->pctx; 1015 if (cur_pkt_ctx == NULL) { 1016 TRACE_ERROR("pctx is NULL!\n"); 1017 errno = ENODATA; 1018 return -1; 1019 } 1020 1021 /* check if offset is valid */ 1022 if (offset < 0) { 1023 TRACE_ERROR("Invalid offset position!\n"); 1024 errno = EINVAL; 1025 return -1; 1026 } 1027 1028 if (__builtin_popcount(option & (MOS_DROP | MOS_CHOMP | 1029 MOS_INSERT | MOS_OVERWRITE)) != 1) { 1030 TRACE_ERROR("mtcp_setlastpkt() function only allows one of " 1031 "(MOS_DROP | MOS_CHOMP | MOS_INSERT | MOS_OVERWRITE) " 1032 "to be set at a time.\n"); 1033 errno = EAGAIN; 1034 return -1; 1035 } 1036 1037 /* drop pkt has the highest priority */ 1038 if (option & MOS_DROP) { 1039 mtcp->pctx->forward = 0; 1040 return 0; 1041 } else if (option & MOS_ETH_HDR) { 1042 /* validity test */ 1043 if ((ethh=cur_pkt_ctx->p.ethh) == NULL || 1044 offset + datalen > sizeof(struct ethhdr)) { 1045 TRACE_ERROR("Ethernet setting has gone out of bounds " 1046 "(offset: %ld, datalen: %d)\n", 1047 offset, datalen); 1048 errno = EINVAL; 1049 return -1; 1050 } 1051 if (option & MOS_CHOMP) { 1052 TRACE_ERROR("Illegal call. " 1053 "Ethernet header can't be chopped down!\n"); 1054 errno = EACCES; 1055 return -1; 1056 } else if (option & MOS_INSERT) { 1057 TRACE_ERROR("Illegal call. " 1058 "Ethernet header can't be extended!\n"); 1059 errno = EACCES; 1060 return -1; 1061 } else /* if (option & MOS_OVERWRITE) */ { 1062 memcpy((uint8_t *)ethh + offset, data, datalen); 1063 } 1064 /* iph, tcph, and payload do not need to change */ 1065 } else if (option & MOS_IP_HDR) { 1066 /* validity test */ 1067 if (cur_pkt_ctx->p.ethh == NULL || 1068 cur_pkt_ctx->p.ethh->h_proto != ntohs(ETH_P_IP) || 1069 (iph=(struct iphdr *)(cur_pkt_ctx->p.ethh + 1)) == NULL) { 1070 TRACE_ERROR("ethh or iph are out of bounds\n"); 1071 errno = EACCES; 1072 return -1; 1073 } 1074 if (option & MOS_OVERWRITE) { 1075 if (offset + datalen > (iph->ihl<<2)) { 1076 TRACE_ERROR("IP setting has gone out of bounds " 1077 "(offset: %ld, datalen: %d)\n", 1078 offset, datalen); 1079 errno = EINVAL; 1080 return -1; 1081 } 1082 memcpy((uint8_t *)iph + offset, data, datalen); 1083 } 1084 if (option & MOS_CHOMP) { 1085 memmove((uint8_t *)iph + offset, 1086 (uint8_t *)iph + offset + datalen, 1087 cur_pkt_ctx->p.ip_len - offset - datalen); 1088 1089 /* iph does not need to change */ 1090 if (iph->protocol == IPPROTO_TCP) { 1091 cur_pkt_ctx->p.tcph = (struct tcphdr *)((uint8_t *)iph + (iph->ihl<<2)); 1092 cur_pkt_ctx->p.payload = (uint8_t *)cur_pkt_ctx->p.tcph + 1093 (cur_pkt_ctx->p.tcph->doff<<2); 1094 } else { 1095 /* reset tcph if iph does not have tcp proto */ 1096 cur_pkt_ctx->p.tcph = NULL; 1097 } 1098 /* update iph total length */ 1099 cur_pkt_ctx->p.ip_len = ntohs(iph->tot_len); 1100 /* update eth frame length */ 1101 cur_pkt_ctx->p.eth_len = cur_pkt_ctx->p.ip_len + sizeof(struct ethhdr); 1102 } else if (option & MOS_INSERT) { 1103 memmove((uint8_t *)iph + offset + datalen, 1104 (uint8_t *)iph + offset + 1, 1105 cur_pkt_ctx->p.ip_len - offset); 1106 memcpy((uint8_t *)iph + offset, 1107 data, datalen); 1108 1109 /* iph does not need to change */ 1110 if (iph->protocol == IPPROTO_TCP) { 1111 cur_pkt_ctx->p.tcph = (struct tcphdr *)((uint8_t *)iph + (iph->ihl<<2)); 1112 cur_pkt_ctx->p.payload = (uint8_t *)cur_pkt_ctx->p.tcph + 1113 (cur_pkt_ctx->p.tcph->doff<<2); 1114 } else { 1115 /* reset tcph if iph does not have tcp proto */ 1116 cur_pkt_ctx->p.tcph = NULL; 1117 } 1118 /* update iph total length */ 1119 cur_pkt_ctx->p.ip_len = ntohs(iph->tot_len); 1120 /* update eth frame length */ 1121 cur_pkt_ctx->p.eth_len = cur_pkt_ctx->p.ip_len + sizeof(struct ethhdr); 1122 } 1123 /* can't update payloadlen because we don't know tcph->doff */ 1124 } else if (option & MOS_TCP_HDR) { 1125 /* validity test */ 1126 iph = (struct iphdr *)(cur_pkt_ctx->p.ethh + 1); 1127 if (iph == NULL || 1128 iph->protocol != IPPROTO_TCP || 1129 (tcph=(struct tcphdr *)((uint8_t *)iph + (iph->ihl<<2))) == NULL) { 1130 TRACE_ERROR("TCP setting has gone out of bounds " 1131 "(offset: %ld, datalen: %d)\n", 1132 offset, datalen); 1133 errno = EINVAL; 1134 return -1; 1135 } 1136 if (option & MOS_OVERWRITE) { 1137 if (offset + datalen > (tcph->doff<<2)) { 1138 TRACE_ERROR("TCP setting has gone out of bounds " 1139 "(offset: %ld, datalen: %d)\n", 1140 offset, datalen); 1141 errno = EINVAL; 1142 return -1; 1143 } 1144 memcpy((uint8_t *)tcph + offset, data, datalen); 1145 /* update tcp seq # */ 1146 cur_pkt_ctx->p.seq = ntohl(tcph->seq); 1147 /* update tcp ack_seq # */ 1148 cur_pkt_ctx->p.ack_seq = ntohl(tcph->ack_seq); 1149 /* update tcp window */ 1150 cur_pkt_ctx->p.window = ntohs(tcph->window); 1151 1152 /* 150422 dhkim TODO: seq and offset are two different form of same 1153 * variable. We also need to update the offset. */ 1154 } 1155 if (option & MOS_CHOMP) { 1156 memmove((uint8_t *)tcph + offset, 1157 (uint8_t *)tcph + offset + datalen, 1158 cur_pkt_ctx->p.payloadlen + (tcph->doff<<2) 1159 - offset - datalen); 1160 /* update payload ptr */ 1161 cur_pkt_ctx->p.payload = (uint8_t *)tcph + (tcph->doff<<2); 1162 } else if (option & MOS_INSERT) { 1163 memmove((uint8_t *)tcph + offset + datalen, 1164 (uint8_t *)tcph + offset + 1, 1165 cur_pkt_ctx->p.payloadlen + (tcph->doff<<2) 1166 - offset); 1167 memcpy((uint8_t *)tcph + offset, data, datalen); 1168 /* update payload ptr */ 1169 cur_pkt_ctx->p.payload = (uint8_t *)tcph + (tcph->doff<<2); 1170 } 1171 } else if (option & MOS_TCP_PAYLOAD) { 1172 iph = (struct iphdr *)(cur_pkt_ctx->p.ethh + 1); 1173 tcph = (struct tcphdr *)((uint8_t *)iph + (iph->ihl<<2)); 1174 payload = (uint8_t *)tcph + (tcph->doff<<2); 1175 if (option & MOS_OVERWRITE) { 1176 if (offset + datalen > ntohs(iph->tot_len) - 1177 (iph->ihl<<2) - (tcph->doff<<2)) { 1178 TRACE_ERROR("Payload setting has gone out of bounds " 1179 "(offset: %ld, datalen: %d)\n", 1180 offset, datalen); 1181 errno = EINVAL; 1182 return -1; 1183 } 1184 memcpy(payload + offset, data, datalen); 1185 } 1186 if (option & MOS_CHOMP) { 1187 memmove(payload + offset, 1188 payload + offset + datalen, 1189 (cur_pkt_ctx->p.payloadlen - 1190 offset - datalen)); 1191 /* update payload length */ 1192 cur_pkt_ctx->p.payloadlen = cur_pkt_ctx->p.ip_len - 1193 (tcph->doff<<2) - (iph->ihl<<2); 1194 } else if (option & MOS_INSERT) { 1195 memmove(payload + offset + datalen, 1196 payload + offset + 1, 1197 cur_pkt_ctx->p.payloadlen - offset); 1198 memcpy(payload + offset, data, datalen); 1199 cur_pkt_ctx->p.payloadlen = cur_pkt_ctx->p.ip_len - 1200 (tcph->doff<<2) - (iph->ihl<<2); 1201 } 1202 } else { 1203 TRACE_ERROR("Invalid option!\n"); 1204 errno = EINVAL; 1205 return -1; 1206 } 1207 1208 /* update ip checksum */ 1209 if (option & MOS_UPDATE_IP_CHKSUM) { 1210 iph = (struct iphdr *)(cur_pkt_ctx->p.ethh + 1); 1211 iph->check = 0; 1212 iph->check = ip_fast_csum(iph, iph->ihl); 1213 } 1214 1215 /* update tcp checksum */ 1216 if (option & MOS_UPDATE_TCP_CHKSUM) { 1217 iph = (struct iphdr *)(cur_pkt_ctx->p.ethh + 1); 1218 tcph = (struct tcphdr *)((uint8_t *)iph + (iph->ihl<<2)); 1219 tcph->check = 0; 1220 tcph->check = TCPCalcChecksum((uint16_t *)tcph, 1221 ntohs(iph->tot_len) - (iph->ihl<<2), 1222 iph->saddr, iph->daddr); 1223 } 1224 return 0; 1225 } 1226 /*----------------------------------------------------------------------------*/ 1227 #if 0 1228 inline int 1229 mtcp_cb_updatecurpkt(mctx_t mctx, off_t offset, unsigned char *data, 1230 uint16_t datalen, int option) 1231 { 1232 return mtcp_setlastpkt(mctx, sock, side, offset, data, datalen, option); 1233 } 1234 #endif 1235 /*----------------------------------------------------------------------------*/ 1236 /** 1237 * THIS IS A DEPRECETED FUNCTION... 1238 */ 1239 int 1240 mtcp_cb_dropcurpkt(mctx_t mctx) 1241 { 1242 mtcp_manager_t mtcp; 1243 1244 /* checking if mtcp is valid */ 1245 mtcp = GetMTCPManager(mctx); 1246 if (!mtcp) { 1247 TRACE_ERROR("Invalid mtcp!\n"); 1248 errno = EACCES; 1249 return -1; 1250 } 1251 1252 /* check if the calling thread is in MOS context */ 1253 if (mtcp->ctx->thread != pthread_self()) { 1254 TRACE_ERROR("Invalid thread id!\n"); 1255 errno = EPERM; 1256 return -1; 1257 } 1258 1259 /* see if cur_pkt_ctx is valid */ 1260 if (mtcp->pctx == NULL) { 1261 TRACE_ERROR("pctx is NULL!\n"); 1262 errno = ENODATA; 1263 return -1; 1264 } 1265 1266 mtcp->pctx->forward = 0; 1267 1268 return 0; 1269 } 1270 /*----------------------------------------------------------------------------*/ 1271 int 1272 mtcp_set_debug_string(mtcp_manager_t mtcp, const char *fmt, ...) 1273 { 1274 #ifdef ENABLE_DEBUG_EVENT 1275 va_list args; 1276 int i; 1277 1278 assert(mtcp); 1279 1280 if (fmt == NULL) { 1281 mtcp->dbg_buf[0] = '\0'; 1282 return 0; 1283 } 1284 1285 va_start(args, fmt); 1286 i = vsnprintf(mtcp->dbg_buf, DBG_BUF_LEN - 1, fmt, args); 1287 va_end(args); 1288 1289 return i; 1290 #else 1291 return -1; 1292 #endif /* ENABLE_DEBUG_EVENT */ 1293 } 1294 /*----------------------------------------------------------------------------*/ 1295 int 1296 mtcp_get_debug_string(mctx_t mctx, char *buf, int len) 1297 { 1298 #ifdef ENABLE_DEBUG_EVENT 1299 mtcp_manager_t mtcp; 1300 int copylen; 1301 1302 if (len < 0) 1303 return -1; 1304 else if (len == 0) 1305 return 0; 1306 1307 if (!(mtcp = GetMTCPManager(mctx))) 1308 return -1; 1309 1310 copylen = MIN(strlen(mtcp->dbg_buf), len); 1311 strncpy(buf, mtcp->dbg_buf, copylen); 1312 1313 return copylen; 1314 #else 1315 return -1; 1316 #endif /* ENABLE_DEBUG_EVENT */ 1317 } 1318 /*----------------------------------------------------------------------------*/ 1319