static int retrieve_client_ips() { int count = 0, len, i; char *split, *p, tmp_ip[32], *q; uint32_t ip; p = clt_settings.raw_clt_ips; while (true) { split = strchr(p, ','); if (split != NULL) { *split = '\0'; } len = strlen(p); if (len == 0) { tc_log_info(LOG_WARN, 0, "ip is empty"); break; } if (p[len - 1] == '*') { strncpy(tmp_ip, p, len -1); q = tmp_ip + len - 1; for (i = 1; i < 255; i++) { sprintf(q, "%d", i); ip = inet_addr(tmp_ip); clt_settings.valid_ips[count++] = ip; if (count == M_CLIENT_IP_NUM) { tc_log_info(LOG_WARN, 0, "reach the limit for clt ips"); break; } } } else { ip = inet_addr(p); clt_settings.valid_ips[count++] = ip; if (count == M_CLIENT_IP_NUM) { tc_log_info(LOG_WARN, 0, "reach the limit for clt ips"); break; } } if (split != NULL) { *split = ','; } if (count == M_CLIENT_IP_NUM) { tc_log_info(LOG_WARN, 0, "reach the limit for clt_tf_ip"); break; } if (split == NULL) { break; } else { p = split + 1; } } clt_settings.valid_ip_num = count; return 1; }
/* * main entry point */ int main(int argc, char **argv) { int ret, is_continue = 1; settings_init(); #if (TC_SIGACTION) if (set_signal_handler(signals) == -1) { return -1; } #else signal(SIGINT, tcp_copy_over); signal(SIGPIPE, tcp_copy_over); signal(SIGHUP, tcp_copy_over); signal(SIGTERM, tcp_copy_over); #endif tc_time_init(); if (read_args(argc, argv) == -1) { return -1; } if (tc_log_init(clt_settings.log_path) == -1) { return -1; } clt_settings.pool = tc_create_pool(TC_DEFAULT_POOL_SIZE, 0, 0); if (clt_settings.pool == NULL) { return -1; } /* output debug info */ output_for_debug(); /* set details for running */ if (set_details() == -1) { return -1; } #if (TC_DIGEST) tc_init_digests(); if (!tc_init_sha1()) { return -1; } #endif tc_event_timer_init(); ret = tc_event_loop_init(&event_loop, MAX_FD_NUM); if (ret == TC_EVENT_ERROR) { tc_log_info(LOG_ERR, 0, "event loop init failed"); is_continue = 0; } if (is_continue) { ret = tcp_copy_init(&event_loop); if (ret == TC_ERR) { is_continue = 0; } } if (is_continue) { /* run now */ tc_event_proc_cycle(&event_loop); } tcp_copy_release_resources(); return 0; }
static int tc_pcap_open(pcap_t **pd, char *device, int snap_len, int buf_size) { int status; char ebuf[PCAP_ERRBUF_SIZE]; *ebuf = '\0'; *pd = pcap_create(device, ebuf); if (*pd == NULL) { tc_log_info(LOG_ERR, 0, "pcap create error:%s", ebuf); return TC_ERR; } status = pcap_set_snaplen(*pd, snap_len); if (status != 0) { tc_log_info(LOG_ERR, 0, "pcap_set_snaplen error:%s", pcap_statustostr(status)); return TC_ERR; } status = pcap_set_promisc(*pd, 0); if (status != 0) { tc_log_info(LOG_ERR, 0, "pcap_set_promisc error:%s", pcap_statustostr(status)); return TC_ERR; } status = pcap_set_timeout(*pd, 10); if (status != 0) { tc_log_info(LOG_ERR, 0, "pcap_set_timeout error:%s", pcap_statustostr(status)); return TC_ERR; } status = pcap_set_buffer_size(*pd, buf_size); if (status != 0) { tc_log_info(LOG_ERR, 0, "pcap_set_buffer_size error:%s", pcap_statustostr(status)); return TC_ERR; } tc_log_info(LOG_NOTICE, 0, "pcap_set_buffer_size:%d", buf_size); #if (HAVE_SET_IMMEDIATE_MODE) status = pcap_set_immediate_mode(*pd, 1); if (status != 0) { tc_log_info(LOG_ERR, 0, "pcap_set_immediate_mode error:%s", pcap_statustostr(status)); return TC_ERR; } #endif status = pcap_activate(*pd); if (status < 0) { tc_log_info(LOG_ERR, 0, "pcap_activate error:%s", pcap_statustostr(status)); return TC_ERR; } else if (status > 0) { tc_log_info(LOG_WARN, 0, "pcap activate warn:%s", pcap_statustostr(status)); } return TC_OK; }
int tc_filter(frame_list_t *ptr_, char *options) { vframe_list_t *ptr = (vframe_list_t *)ptr_; if(ptr->tag & TC_FILTER_GET_CONFIG) { optstr_filter_desc (options, MOD_NAME, MOD_CAP, MOD_VERSION, "Thomas Oestreich", "VRYE", "1"); optstr_param (options, "mode", "Choose the test pattern (0-4 interlaced, 5 colorfull)", "%d", "0", "0", "5"); } //---------------------------------- // // filter init // //---------------------------------- if(ptr->tag & TC_FILTER_INIT) { if((vob = tc_get_vob())==NULL) return(-1); // filter init ok. if(verbose) tc_log_info(MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP); if(verbose) tc_log_info(MOD_NAME, "options=%s", options); if (options) { if (is_optstr(options)) { optstr_get(options, "mode", "%d", &mode); } else sscanf(options, "%d", &mode); } if(mode <0) { tc_log_error(MOD_NAME, "Invalid mode"); return(-1); } return(0); } //---------------------------------- // // filter close // //---------------------------------- if(ptr->tag & TC_FILTER_CLOSE) { return(0); } //---------------------------------- // // filter frame routine // //---------------------------------- // tag variable indicates, if we are called before // transcodes internal video/audo frame processing routines // or after and determines video/audio context if(ptr->tag & TC_PRE_M_PROCESS && ptr->tag & TC_VIDEO && !(ptr->attributes & TC_FRAME_IS_SKIPPED)) { if(vob->im_v_codec==CODEC_RGB) { generate_rgb_frame(ptr->video_buf, ptr->v_width, ptr->v_height); } else { generate_yuv_frame(ptr->video_buf, ptr->v_width, ptr->v_height); } } return(0); }
static int dispose_packet(char *recv_buf, int recv_len, int *p_valid_flag) { int replica_num, i, last, packet_num, max_payload, index, payload_len; char *packet, tmp_buf[RECV_BUF_SIZE]; bool packet_valid = false; uint16_t id, size_ip, size_tcp, tot_len, cont_len, pack_len = 0, head_len; uint32_t seq; struct tcphdr *tcp_header; struct iphdr *ip_header; packet = recv_buf; if (is_packet_needed((const char *)packet)) { replica_num = clt_settings.replica_num; packet_num = 1; ip_header = (struct iphdr*)packet; if (localhost == ip_header->saddr) { if (0 != clt_settings.lo_tf_ip) { ip_header->saddr = clt_settings.lo_tf_ip; } } /* * If packet length larger than MTU, then we split it. * This is to solve the ip fragmentation problem */ if (recv_len > clt_settings.mtu) { /* Calculate number of packets */ size_ip = ip_header->ihl << 2; tot_len = ntohs(ip_header -> tot_len); if (tot_len != recv_len) { tc_log_info(LOG_WARN, 0, "packet len:%u, recv len:%u", tot_len, recv_len); return FAILURE; } tcp_header = (struct tcphdr*)((char *)ip_header + size_ip); size_tcp = tcp_header->doff << 2; cont_len = tot_len - size_tcp - size_ip; head_len = size_ip + size_tcp; max_payload = clt_settings.mtu - head_len; packet_num = (cont_len + max_payload - 1)/max_payload; seq = ntohl(tcp_header->seq); last = packet_num - 1; id = ip_header->id; #if (TCPCOPY_DEBUG) tc_log_trace(LOG_NOTICE, 0, CLIENT_FLAG, ip_header, tcp_header); #endif tc_log_debug1(LOG_DEBUG, 0, "recv:%d, more than MTU", recv_len); index = head_len; for (i = 0 ; i < packet_num; i++) { tcp_header->seq = htonl(seq + i * max_payload); if (i != last) { pack_len = clt_settings.mtu; } else { pack_len += (cont_len - packet_num * max_payload); } payload_len = pack_len - head_len; ip_header->tot_len = htons(pack_len); ip_header->id = id++; /* Copy header here */ memcpy(tmp_buf, recv_buf, head_len); /* Copy payload here */ memcpy(tmp_buf + head_len, recv_buf + index, payload_len); index = index + payload_len; if (replica_num > 1) { packet_valid = process_packet(true, tmp_buf, pack_len); replicate_packs(tmp_buf, pack_len, replica_num); } else { packet_valid = process_packet(false, tmp_buf, pack_len); } } } else { if (replica_num > 1) { packet_valid = process_packet(true, packet, recv_len); replicate_packs(packet, recv_len, replica_num); } else { packet_valid = process_packet(false, packet, recv_len); } } } if (packet_valid) { *p_valid_flag = 1; } else { *p_valid_flag = 0; } return SUCCESS; }
static int set_details() { int rand_port; unsigned int seed; struct timeval tp; /* generate a random port number for avoiding port conflicts */ gettimeofday(&tp, NULL); seed = tp.tv_usec; rand_port = (int) ((rand_r(&seed)/(RAND_MAX + 1.0))*512); clt_settings.rand_port_shifted = rand_port; /* set the ip port pair mapping according to settings */ if (retrieve_target_addresses(clt_settings.raw_transfer, &clt_settings.transfer) == -1) { return -1; } if (clt_settings.percentage < 0 && clt_settings.percentage >99) { clt_settings.percentage = 0; } #if (TCPCOPY_OFFLINE) if (clt_settings.pcap_file == NULL) { tc_log_info(LOG_ERR, 0, "it must have -i argument for offline"); fprintf(stderr, "no -i argument\n"); return -1; } #endif #if (TCPCOPY_PCAP) if (clt_settings.raw_device != NULL) { tc_log_info(LOG_NOTICE, 0, "device:%s", clt_settings.raw_device); if (strcmp(clt_settings.raw_device, DEFAULT_DEVICE) == 0) { clt_settings.raw_device = NULL; } else { retrieve_devices(); } } #endif #if (TCPCOPY_MYSQL_ADVANCED) if (clt_settings.user_pwd != NULL) { if (retrieve_mysql_user_pwd_info(clt_settings.user_pwd) == -1) { return -1; } } else { tc_log_info(LOG_ERR, 0, "it must have -u argument"); fprintf(stderr, "no -u argument\n"); return -1; } #endif #if (TCPCOPY_DR) /* retrieve real server ip addresses */ if (clt_settings.raw_rs_ip_list != NULL) { tc_log_info(LOG_NOTICE, 0, "s parameter:%s", clt_settings.raw_rs_ip_list); retrieve_real_servers(); } else { tc_log_info(LOG_WARN, 0, "no real server ip addresses"); return -1; } #endif /* daemonize */ if (clt_settings.do_daemonize) { if (sigignore(SIGHUP) == -1) { tc_log_info(LOG_ERR, errno, "Failed to ignore SIGHUP"); } if (daemonize() == -1) { fprintf(stderr, "failed to daemon() in order to daemonize\n"); return -1; } } #if (TCPCOPY_OFFLINE) if (tc_time_set_timer(TIMER_INTERVAL) == TC_ERROR) { #else if (tc_time_set_timer(100) == TC_ERROR) { #endif tc_log_info(LOG_ERR, 0, "set timer error"); return -1; } return 0; } /* set default values for TCPCopy client */ static void settings_init() { /* init values */ clt_settings.mtu = DEFAULT_MTU; clt_settings.mss = DEFAULT_MSS; clt_settings.max_rss = MAX_MEMORY_SIZE; clt_settings.srv_port = SERVER_PORT; clt_settings.percentage = 0; clt_settings.session_timeout = DEFAULT_SESSION_TIMEOUT; tc_raw_socket_out = TC_INVALID_SOCKET; set_signal_handler(); }
/* initiate for tcpcopy server */ int interception_init(tc_event_loop_t *event_loop, char *ip, uint16_t port) { int fd; #if (INTERCEPT_THREAD) pthread_t thread; #endif tc_event_t *ev; router_init(srv_settings.hash_size); pid = getpid(); /* init the listening socket */ if ((fd = tc_socket_init()) == TC_INVALID_SOCKET) { return TC_ERROR; } else { if (tc_socket_listen(fd, ip, port) == TC_ERROR) { return TC_ERROR; } tc_log_info(LOG_NOTICE, 0, "msg listen socket:%d", fd); ev = tc_event_create(fd, tc_msg_event_accept, NULL); if (ev == NULL) { return TC_ERROR; } if (tc_event_add(event_loop, ev, TC_EVENT_READ) == TC_EVENT_ERROR) { return TC_ERROR; } } /* init the netlink socket */ if ((fd = tc_nl_socket_init()) == TC_INVALID_SOCKET) { return TC_ERROR; } else { tc_log_info(LOG_NOTICE, 0, "firewall socket:%d", fd); ev = tc_event_create(fd, tc_nl_event_process, NULL); if (ev == NULL) { return TC_ERROR; } if (tc_event_add(event_loop, ev, TC_EVENT_READ) == TC_EVENT_ERROR) { return TC_ERROR; } } #if (INTERCEPT_THREAD) pthread_mutex_init(&mutex, NULL); pthread_cond_init(&full, NULL); pthread_cond_init(&empty, NULL); pthread_create(&thread, NULL, interception_process_msg, NULL); pthread_mutex_init(&nl_mutex, NULL); pthread_cond_init(&nl_full, NULL); pthread_cond_init(&nl_empty, NULL); pthread_create(&thread, NULL, interception_dispose_nl_verdict, NULL); #endif return TC_OK; }
/* * main function: check interlace state */ static void check_interlace (myfilter_t *myf, int id) { double pixDiff, pixShiftChangedT, pixShiftChangedB; double pixLastT, pixLastB, pixLast; int isChangedT = IS_FALSE, isChangedB = IS_FALSE; int isProg = IS_UNKNOWN; int isShift = IS_UNKNOWN, isTop = IS_UNKNOWN; int *counter = &myf->unknownFrames; /* Determine frame parmeters */ pixDiff = pic_compare (myf->lumInT, myf->lumInB, myf->width, myf->height-2, 0); pixShiftChangedT = pic_compare (myf->lumInT, myf->lumPrevB, myf->width, myf->height-2, 0); pixShiftChangedB = pic_compare (myf->lumInB, myf->lumPrevT, myf->width, myf->height-2, 0); pixLastT = pic_compare (myf->lumIn, myf->lumPrev, myf->width, myf->height/2, myf->width); pixLastB = pic_compare (myf->lumIn + myf->width, myf->lumPrev + myf->width, myf->width, myf->height/2, myf->width); pixLast = (pixLastT + pixLastB) / 2; /* Check for changed fields */ if (pixLastT > myf->changedIfMore) isChangedT = IS_TRUE; if (pixLastB > myf->changedIfMore) isChangedB = IS_TRUE; /* Major field detection */ if (pixShiftChangedT * myf->interlaceDiff < pixShiftChangedB) isTop = IS_TRUE; if (pixShiftChangedB * myf->interlaceDiff < pixShiftChangedT) isTop = IS_FALSE; /* Check for progessive frame */ if (pixDiff * myf->unknownDiff > pixShiftChangedT || pixDiff * myf->unknownDiff > pixShiftChangedB) isProg = IS_FALSE; if (pixDiff * myf->progressiveDiff < pixShiftChangedT && pixDiff * myf->progressiveDiff < pixShiftChangedB && pixDiff < pixLast * myf->progressiveChange) isProg = IS_TRUE; /* Check for shifted progressive frame */ /* not completely equivalent to check.prog.frame. (pixLast) */ /* TODO: this triggers too often for regular interlaced material */ if (pixShiftChangedT * myf->progressiveDiff < pixDiff && pixShiftChangedT * myf->progressiveDiff < pixShiftChangedB && pixShiftChangedT < myf->progressiveChange * pixLast) isShift = IS_TRUE; if (pixShiftChangedB * myf->progressiveDiff < pixDiff && pixShiftChangedB * myf->progressiveDiff < pixShiftChangedT && pixShiftChangedT < myf->progressiveChange * pixLast) isShift = IS_TRUE; /* Detect telecine */ /* telecined material will create a sequence like this (TopfieldFirst): * 0t1b (0)1t1b (1)2t2b (2)3t3b (3)3t4b (4)4t5b (0)5t5b ... * and vice versa for BottomfieldFirst. * We start looking for an progressive frame (1t1b) with one field * equal to the last frame and continue checking the frames for * adhering to the pattern. * We only count frames as valid telecine frames, if the pattern has been * detected twice in a row (telecineState > 10). * Undecidable frames (isProg == UNKNOWN && isTop == UNKNOWN) and * frames without changes (isChangedT != TRUE && isChangedB != TRUE) * are only accepted, if telecineState > 10. * Only happens for NTSC (29.97fps). * If a test fails, it reduces the current telecineState by 20. * Max. telecineState is 100. */ /* TODO: currently no field insertion/deletion is detected, * requires resync right now */ if ((myf->fps > 29.9 && myf->fps < 30.1) || myf->forceTelecineDetect) { if ((isChangedT == IS_TRUE || isChangedB == IS_TRUE) && (isProg != IS_UNKNOWN || isTop != IS_UNKNOWN || myf->telecineState > 10)){ switch (myf->telecineState % 5) { case 0: /* if (isProg == IS_FALSE) myf->telecineState -= 20; */ /* prog. detmination may fail */ switch (isTop) { case IS_TRUE: if (isChangedB == IS_TRUE) myf->telecineState -= 20; break; case IS_FALSE: if (isChangedT == IS_TRUE) myf->telecineState -= 20; break; } break; case 1: case 2: if (isProg == IS_FALSE) myf->telecineState -= 20; break; case 3: if (isProg == IS_TRUE) myf->telecineState -= 20; switch (isTop) { case IS_TRUE: if (isChangedT == IS_TRUE) myf->telecineState -= 20; break; case IS_FALSE: if (isChangedB == IS_TRUE) myf->telecineState -= 20; break; } break; case 4: if (isProg == IS_TRUE) myf->telecineState -= 20; break; } if (myf->telecineState < 0) myf->telecineState = 0; if (myf->telecineState == 0) { /* Frame has another chance to be case 0 */ /* if (isProg == IS_FALSE) myf->telecineState = -1; */ /* prog. detmination may fail */ switch (isTop) { case IS_TRUE: if (isChangedB == IS_TRUE) myf->telecineState = -1; break; case IS_FALSE: if (isChangedT == IS_TRUE) myf->telecineState = -1; break; } } myf->telecineState++; } else if (myf->telecineState > 10) myf->telecineState++; else myf->telecineState = 0; if (myf->telecineState > 100) myf->telecineState -= 10; } /* Detect inconstistencies */ if (isProg == IS_FALSE && isTop == IS_UNKNOWN) isProg = IS_UNKNOWN; if (isProg != IS_FALSE && isTop != IS_UNKNOWN) { isTop = IS_UNKNOWN; isProg = IS_UNKNOWN; } if (isChangedT == IS_FALSE || isChangedB == IS_FALSE) { isProg = IS_UNKNOWN; isTop = IS_UNKNOWN; isShift = IS_UNKNOWN; } /* verbose output */ if (myf->verbose) { char verboseBuffer[64]; char *outType = 0, *outField = " "; memset (verboseBuffer, ' ', 63); if (pixDiff * myf->unknownDiff < pixShiftChangedT) memcpy (&verboseBuffer[0], "pt", 2); if (pixDiff * myf->progressiveDiff < pixShiftChangedT) memcpy (&verboseBuffer[0], "Pt", 2); if (pixDiff * myf->unknownDiff < pixShiftChangedB) memcpy (&verboseBuffer[2], "pb", 2); if (pixDiff * myf->progressiveDiff < pixShiftChangedB) memcpy (&verboseBuffer[2], "Pb", 2); if (pixDiff < myf->progressiveChange*pixLast) verboseBuffer[5] = 'c'; if (pixShiftChangedT * myf->interlaceDiff < pixShiftChangedB) verboseBuffer[7] = 't'; if (pixShiftChangedB * myf->interlaceDiff < pixShiftChangedT) verboseBuffer[7] = 'b'; if (isChangedT == IS_FALSE) memcpy (&verboseBuffer[9], "st", 2); if (isChangedB == IS_FALSE) memcpy (&verboseBuffer[11], "sb", 2); verboseBuffer[13] = 0; if (myf->verbose > 1) { tc_log_info (MOD_NAME, "frame %d: pixDiff %.3f " "pixShiftChanged %.3fT/%.3fB pixLast %.3fT/%.3fB telecineState %d", id, pixDiff, pixShiftChangedT, pixShiftChangedB, pixLastT, pixLastB, myf->telecineState); } switch (isProg) { case IS_UNKNOWN: outType = "unknown "; break; case IS_FALSE: outType = "interlaced "; break; case IS_TRUE: outType = "progressive"; break; } if (isChangedT == IS_FALSE && isChangedB == IS_FALSE) outType = "low change "; if (isShift == IS_TRUE) outType = "shifted p "; if (myf->telecineState > 10) outType = "telecined "; switch (isTop) { case IS_FALSE: outField = "B"; break; case IS_TRUE: outField = "T"; break; } tc_log_info (MOD_NAME, "frame %d: %s %s [%s]", id, outType, outField, verboseBuffer); } /* Count types */ switch (isProg) { case IS_UNKNOWN: counter = &myf->unknownFrames; break; case IS_FALSE: counter = &myf->interlacedFrames; break; case IS_TRUE: counter = &myf->progressiveFrames; break; } if (isChangedT == IS_FALSE && isChangedB == IS_FALSE) counter = &myf->unknownFrames; if (isShift == IS_TRUE) counter = &myf->fieldShiftFrames; if (myf->telecineState > 10) counter = &myf->telecineFrames; switch (isTop) { case IS_FALSE: myf->bottomFirstFrames++; break; case IS_TRUE: myf->topFirstFrames++; break; } assert (counter); (*counter)++; myf->numFrames++; }
/* * transcode API */ int tc_filter(frame_list_t *ptr_, char *options) { vframe_list_t *ptr = (vframe_list_t *)ptr_; vob_t *vob = NULL; myfilter_t *myf = myf_global; /* * filter init */ if (ptr->tag & TC_FILTER_INIT) { if (! (vob = tc_get_vob ())) return -1; if (! (myf = myf_global = tc_zalloc (sizeof (myfilter_t)))) { return -1; } if (! (myf->tcvhandle = tcv_init())) { tc_log_error(MOD_NAME, "tcv_init() failed"); free(myf); myf = myf_global = NULL; return -1; } if (verbose) /* global verbose */ tc_log_info(MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP); /* default values */ myf->interlaceDiff = 1.1; myf->unknownDiff = 1.5; myf->progressiveDiff = 8; myf->progressiveChange = 0.2; myf->changedIfMore = 10; myf->forceTelecineDetect = 0; myf->verbose = 0; myf->outDiff = 0; /* video parameters */ switch (vob->im_v_codec) { case TC_CODEC_YUY2: case TC_CODEC_YUV420P: case TC_CODEC_YUV422P: case TC_CODEC_RGB24: break; default: tc_log_error(MOD_NAME, "Unsupported codec - need one of RGB24 YUV420P YUY2 YUV422P"); return -1; } myf->codec = vob->im_v_codec; myf->width = vob->im_v_width; myf->height = vob->im_v_height; myf->fps = vob->fps; myf->size = myf->width * myf->height; if (options) { optstr_get (options, "interlacediff", "%lf", &myf->interlaceDiff); optstr_get (options, "unknowndiff", "%lf", &myf->unknownDiff); optstr_get (options, "progressivediff", "%lf", &myf->progressiveDiff); optstr_get (options, "progressivechange", "%lf", &myf->progressiveChange); optstr_get (options, "changedifmore", "%lf", &myf->changedIfMore); optstr_get (options, "forcetelecinedetect", "%d", &myf->forceTelecineDetect); optstr_get (options, "verbose", "%d", &myf->verbose); optstr_get (options, "outdiff", "%d", &myf->outDiff); if (optstr_lookup (options, "help") != NULL) { tc_log_info (MOD_NAME, "(%s) help\n" "* Overview:\n" " 'fieldanalysis' scans video for interlacing artifacts and\n" " detects progressive / interlaced / telecined video.\n" " It also determines the major field for interlaced video.\n" "* Verbose Output: [PtPb c t stsb]\n" " Pt, Pb: progressivediff succeeded, per field.\n" " pt, pb: unknowndiff succeeded, progressivediff failed.\n" " c: progressivechange succeeded.\n" " t: topFieldFirst / b: bottomFieldFirst detected.\n" " st, sb: changedifmore failed (fields are similar to last frame).\n" , MOD_CAP); } } /* frame memory */ if (! (myf->lumIn = calloc (1, myf->size)) || ! (myf->lumPrev = calloc (1, myf->size)) || ! (myf->lumInT = calloc (1, myf->size)) || ! (myf->lumInB = calloc (1, myf->size)) || ! (myf->lumPrevT = calloc (1, myf->size)) || ! (myf->lumPrevB = calloc (1, myf->size))) { tc_log_error(MOD_NAME, "calloc() failed"); return -1; } if (verbose) { /* global verbose */ tc_log_info(MOD_NAME, "interlacediff %.2f, unknowndiff %.2f, progressivediff %.2f", myf->interlaceDiff, myf->unknownDiff, myf->progressiveDiff); tc_log_info(MOD_NAME, "progressivechange %.2f, changedifmore %.2f", myf->progressiveChange, myf->changedIfMore); tc_log_info(MOD_NAME, "forcetelecinedetect %s, verbose %d, outdiff %d", myf->forceTelecineDetect ? "True":"False", myf->verbose, myf->outDiff); } return 0; } /* * filter close */ if (ptr->tag & TC_FILTER_CLOSE) { int total = myf->numFrames - myf->unknownFrames; int totalfields = myf->topFirstFrames + myf->bottomFirstFrames; /* Cleanup */ free (myf->lumIn); free (myf->lumPrev); free (myf->lumInT); free (myf->lumInB); free (myf->lumPrevT); free (myf->lumPrevB); myf->lumIn = myf->lumPrev = myf->lumInT = myf->lumInB = myf->lumPrevT = myf->lumPrevB = NULL; /* Output results */ if (totalfields < 1) totalfields = 1; tc_log_info(MOD_NAME, "RESULTS: Frames: %d (100%%) Unknown: %d (%.3g%%)", myf->numFrames, myf->unknownFrames, 100.0 * myf->unknownFrames / (double)myf->numFrames); tc_log_info(MOD_NAME, "RESULTS: Progressive: %d (%.3g%%) Interlaced: %d (%.3g%%)", myf->progressiveFrames, 100.0 * myf->progressiveFrames / (double)myf->numFrames, myf->interlacedFrames, 100.0 * myf->interlacedFrames / (double)myf->numFrames); tc_log_info(MOD_NAME, "RESULTS: FieldShift: %d (%.3g%%) Telecined: %d (%.3g%%)", myf->fieldShiftFrames, 100.0 * myf->fieldShiftFrames / (double)myf->numFrames, myf->telecineFrames, 100.0 * myf->telecineFrames / (double)myf->numFrames); tc_log_info(MOD_NAME, "RESULTS: MajorField: TopFirst %d (%.3g%%) BottomFirst %d (%.3g%%)", myf->topFirstFrames, 100.0 * myf->topFirstFrames / (double)totalfields, myf->bottomFirstFrames, 100.0 * myf->bottomFirstFrames / (double)totalfields); if (total < 50) tc_log_warn (MOD_NAME, "less than 50 frames analyzed correctly, no conclusion."); else if (myf->unknownFrames * 10 > myf->numFrames * 9) tc_log_warn (MOD_NAME, "less than 10%% frames analyzed correctly, no conclusion."); else if (myf->progressiveFrames * 8 > total * 7) tc_log_info (MOD_NAME, "CONCLUSION: progressive video."); else if (myf->topFirstFrames * 8 > myf->bottomFirstFrames && myf->bottomFirstFrames * 8 > myf->topFirstFrames) tc_log_info (MOD_NAME, "major field unsure, no conclusion. Use deinterlacer for processing."); else if (myf->telecineFrames * 4 > total * 3) tc_log_info (MOD_NAME, "CONCLUSION: telecined video, %s field first.", myf->topFirstFrames > myf->bottomFirstFrames ? "top" : "bottom"); else if (myf->fieldShiftFrames * 4 > total * 3) tc_log_info (MOD_NAME, "CONCLUSION: field shifted progressive video, %s field first.", myf->topFirstFrames > myf->bottomFirstFrames ? "top" : "bottom"); else if (myf->interlacedFrames > myf->fieldShiftFrames && (myf->interlacedFrames+myf->fieldShiftFrames) * 8 > total * 7) tc_log_info (MOD_NAME, "CONCLUSION: interlaced video, %s field first.", myf->topFirstFrames > myf->bottomFirstFrames ? "top" : "bottom"); else tc_log_info (MOD_NAME, "mixed video, no conclusion. Use deinterlacer for processing."); tcv_free(myf->tcvhandle); myf->tcvhandle = 0; return 0; } /* * filter description */ if (ptr->tag & TC_FILTER_GET_CONFIG) { char buf[255]; optstr_filter_desc (options, MOD_NAME, MOD_CAP, MOD_VERSION, MOD_AUTHOR, "VRY4E", "2"); tc_snprintf (buf, sizeof(buf), "%g", myf->interlaceDiff); optstr_param (options, "interlacediff", "Minimum temporal inter-field difference for detecting interlaced video", "%f", buf, "1.0", "inf"); tc_snprintf (buf, sizeof(buf), "%g", myf->unknownDiff); optstr_param (options, "unknowndiff", "Maximum inter-frame change vs. detail differences for neglecting interlaced video", "%f", buf, "1.0", "inf"); tc_snprintf (buf, sizeof(buf), "%g", myf->progressiveDiff); optstr_param (options, "progressivediff", "Minimum inter-frame change vs. detail differences for detecting progressive video" ,"%f", buf, "unknowndiff", "inf"); tc_snprintf (buf, sizeof(buf), "%g", myf->progressiveChange); optstr_param (options, "progressivechange", "Minimum temporal change needed for detecting progressive video" ,"%f", buf, "0", "inf"); tc_snprintf (buf, sizeof(buf), "%g", myf->changedIfMore); optstr_param (options, "changedifmore", "Minimum temporal change for detecting truly changed frames" ,"%f", buf, "0", "65025"); tc_snprintf (buf, sizeof(buf), "%d", myf->forceTelecineDetect); optstr_param (options, "forcetelecinedetect", "Detect telecine even on non-NTSC (29.97fps) video", "%d", buf, "0", "1"); tc_snprintf (buf, sizeof(buf), "%d", myf->verbose); optstr_param (options, "verbose", "Output analysis for every frame", "%d", buf, "0", "2"); tc_snprintf (buf, sizeof(buf), "%d", myf->outDiff); optstr_param (options, "outdiff", "Output internal debug frames as luminance of YUV video (see source)", "%d", buf, "0", "11"); } /* * filter frame routine */ /* need to process frames in-order */ if ((ptr->tag & TC_PRE_S_PROCESS) && (ptr->tag & TC_VIDEO)) { uint8_t *tmp; int i, j; assert (ptr->free == 0 || ptr->free == 1); assert (ptr->video_buf_Y[!ptr->free] == ptr->video_buf); /* Convert / Copy to luminance only */ switch (myf->codec) { case TC_CODEC_RGB24: tcv_convert(myf->tcvhandle, ptr->video_buf, myf->lumIn, myf->width, myf->height, IMG_RGB_DEFAULT, IMG_Y8); break; case TC_CODEC_YUY2: tcv_convert(myf->tcvhandle, ptr->video_buf, myf->lumIn, myf->width, myf->height, IMG_YUY2, IMG_Y8); break; case TC_CODEC_YUV420P: tcv_convert(myf->tcvhandle, ptr->video_buf, myf->lumIn, myf->width, myf->height, IMG_YUV_DEFAULT, IMG_Y8); break; case TC_CODEC_YUV422P: tcv_convert(myf->tcvhandle, ptr->video_buf, myf->lumIn, myf->width, myf->height, IMG_YUV422P, IMG_Y8); break; default: assert (0); } /* Bob Top field */ bob_field (myf->lumIn, myf->lumInT, myf->width, myf->height/2-1); /* Bob Bottom field */ ac_memcpy (myf->lumInB, myf->lumIn + myf->width, myf->width); bob_field (myf->lumIn + myf->width, myf->lumInB + myf->width, myf->width, myf->height/2-1); /* last copied line is ignored, buffer is large enough */ if (myf->numFrames == 0) myf->numFrames++; else if (! (ptr->tag & TC_FRAME_IS_SKIPPED)) { /* check_it */ check_interlace (myf, ptr->id); } /* only works with YUV data correctly */ switch (myf->outDiff) { case 1: /* lumIn */ ac_memcpy (ptr->video_buf, myf->lumIn, myf->size); break; case 2: /* field shift */ for (i = 0 ; i < myf->height-2; i += 2) for (j = 0; j < myf->width; j++) { ptr->video_buf [myf->width*i+j] = myf->lumIn [myf->width*i+j]; ptr->video_buf [myf->width*(i+1)+j] = myf->lumPrev [myf->width*(i+1)+j]; } break; case 3: /* lumInT */ ac_memcpy (ptr->video_buf, myf->lumInT, myf->size); break; case 4: /* lumInB */ ac_memcpy (ptr->video_buf, myf->lumInB, myf->size); break; case 5: /* lumPrevT */ ac_memcpy (ptr->video_buf, myf->lumPrevT, myf->size); break; case 6: /* lumPrevB */ ac_memcpy (ptr->video_buf, myf->lumPrevB, myf->size); break; case 7: /* pixDiff */ pic_diff (myf->lumInT, myf->lumInB, ptr->video_buf, myf->size,4); break; case 8: /* pixShiftChangedT */ pic_diff (myf->lumInT, myf->lumPrevB, ptr->video_buf, myf->size,4); break; case 9: /* pixShiftChangedB */ pic_diff (myf->lumInB, myf->lumPrevT, ptr->video_buf, myf->size,4); break; case 10: /* pixLastT */ pic_diff (myf->lumInT, myf->lumPrevT, ptr->video_buf, myf->size,4); break; case 11: /* pixLastB */ pic_diff (myf->lumInB, myf->lumPrevB, ptr->video_buf, myf->size,4); break; } /* The current frame gets the next previous frame :-P */ tmp = myf->lumPrev; myf->lumPrev = myf->lumIn; myf->lumIn = tmp; tmp = myf->lumPrevT; myf->lumPrevT = myf->lumInT; myf->lumInT = tmp; tmp = myf->lumPrevB; myf->lumPrevB = myf->lumInB; myf->lumInB = tmp; } return 0; }
static int encoder_acquire_vframe(TCEncoderBuffer *buf, vob_t *vob) { int got_frame = TC_TRUE; do { buf->vptr = vframe_retrieve(); if (!buf->vptr) { if (verbose >= TC_THREADS) tc_log_msg(__FILE__, "frame retrieve interrupted!"); return -1; /* can't acquire video frame */ } got_frame = TC_TRUE; buf->frame_id = buf->vptr->id + tc_get_frames_skipped_cloned(); if (verbose & TC_STATS) { tc_log_info(__FILE__, "got frame %p (id=%i)", buf->vptr, buf->frame_id); } /* * now we do the post processing ... this way, if just a video frame is * skipped, we'll know. * * we have to check to make sure that before we do any processing * that this frame isn't out of range (if it is, and one is using * the "-t" split option, we'll see this frame again. */ apply_video_filters(buf->vptr, vob); if (buf->vptr->attributes & TC_FRAME_IS_SKIPPED) { if (buf->vptr != NULL && (buf->vptr->attributes & TC_FRAME_WAS_CLONED) ) { /* XXX do we want to track skipped cloned flags? */ tc_update_frames_cloned(1); } if (buf->vptr != NULL && (buf->vptr->attributes & TC_FRAME_IS_CLONED) ) { /* XXX what to do when a frame is cloned and skipped? */ /* * I'd like to say they cancel, but perhaps they will end * up also skipping the clone? or perhaps they'll keep, * but modify the clone? Best to do the whole drill :/ */ if (verbose & TC_DEBUG) { tc_log_info (__FILE__, "(%i) V pointer done. " "Skipped and Cloned: (%i)", buf->vptr->id, (buf->vptr->attributes)); } /* update flags */ buf->vptr->attributes &= ~TC_FRAME_IS_CLONED; buf->vptr->attributes |= TC_FRAME_WAS_CLONED; /* * this has to be done here, * frame_threads.c won't see the frame again */ } if (buf->vptr != NULL && !(buf->vptr->attributes & TC_FRAME_IS_CLONED) ) { vframe_remove(buf->vptr); /* reset pointer for next retrieve */ buf->vptr = NULL; } // tc_update_frames_skipped(1); got_frame = TC_FALSE; } } while (!got_frame); return 0; }
static int connect_to_server(tc_event_loop_t *event_loop) { int i, j, fd; uint32_t target_ip; uint16_t target_port; connections_t *connections; /* * add connections to the real servers for sending router info * and receiving response packet */ for (i = 0; i < clt_settings.real_servers.num; i++) { target_ip = clt_settings.real_servers.ips[i]; target_port = clt_settings.real_servers.ports[i]; if (target_port == 0) { target_port = clt_settings.srv_port; } if (clt_settings.real_servers.active[i] != 0) { continue; } connections = &(clt_settings.real_servers.connections[i]); for (j = 0; j < connections->num; j++) { fd = connections->fds[j]; if (fd > 0) { tc_log_info(LOG_NOTICE, 0, "it close socket:%d", fd); tc_socket_close(fd); tc_event_del(clt_settings.ev[fd]->loop, clt_settings.ev[fd], TC_EVENT_READ); tc_event_destroy(clt_settings.ev[fd]); connections->fds[j] = -1; } } clt_settings.real_servers.connections[i].num = 0; clt_settings.real_servers.connections[i].remained_num = 0; for (j = 0; j < clt_settings.par_connections; j++) { fd = tc_message_init(event_loop, target_ip, target_port); if (fd == TC_INVALID_SOCKET) { return TC_ERROR; } if (!send_version(fd)) { return TC_ERROR; } if (j == 0) { clt_settings.real_servers.active_num++; clt_settings.real_servers.active[i] = 1; } clt_settings.real_servers.connections[i].fds[j] = fd; clt_settings.real_servers.connections[i].num++; clt_settings.real_servers.connections[i].remained_num++; } tc_log_info(LOG_NOTICE, 0, "add dr tunnels for exchanging info:%u:%u", target_ip, target_port); } return TC_OK; }
int tc_filter(frame_list_t *ptr_, char *options) { aframe_list_t *ptr = (aframe_list_t *)ptr_; int n; double sum; short *s; vob_t *vob=NULL; if(ptr->tag & TC_FILTER_GET_CONFIG) { optstr_filter_desc (options, MOD_NAME, MOD_CAP, MOD_VERSION, "Thomas Oestreich", "AE", "1"); optstr_param (options, "level", "The audio must be under this level to be skipped", "%d", "10", "0", "255"); optstr_param (options, "range", "Number of samples over level will be keyframes", "%d", "25", "0", "255"); return 0; } //---------------------------------- // // filter init // //---------------------------------- if(ptr->tag & TC_FILTER_INIT) { if((vob = tc_get_vob())==NULL) return(-1); // filter init ok. if(verbose) tc_log_info(MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP); if(verbose) tc_log_info(MOD_NAME, "options=%s", options); if(options!=NULL) { if (!is_optstr(options)) { n=sscanf(options,"%d:%d", &level, &range); } else { optstr_get (options, "level", "%d", &level); optstr_get (options, "range", "%d", &range); } } range_ctr=range; return(0); } //---------------------------------- // // filter close // //---------------------------------- if(ptr->tag & TC_FILTER_CLOSE) { return(0); } //---------------------------------- // // filter frame routine // //---------------------------------- if(verbose & TC_STATS) tc_log_info(MOD_NAME, "%s/%s %s %s", vob->mod_path, MOD_NAME, MOD_VERSION, MOD_CAP); // tag variable indicates, if we are called before // transcodes internal video/audo frame processing routines // or after and determines video/audio context if(ptr->tag & TC_PRE_S_PROCESS && ptr->tag & TC_AUDIO && !(ptr->attributes & TC_FRAME_IS_SKIPPED)) { total += (uint64_t) ptr->audio_size; s=(short *) ptr->audio_buf; sum=0; for(n=0; n<ptr->audio_size>>1; ++n) { sum+=(double) ((int)(*s) * (int)(*s)); s++; } if(ptr->audio_size>0) sum = sqrt(sum)/(ptr->audio_size>>1); sum *= 1000; if(verbose & TC_DEBUG) tc_log_info(MOD_NAME, "frame=%d sum=%f", ptr->id, sum); if(sum<level) { if(range_ctr == range) { ptr->attributes |= TC_FRAME_IS_SKIPPED; skip_mode=1; } else ++range_ctr; } else { if(skip_mode) ptr->attributes |= TC_FRAME_IS_KEYFRAME; skip_mode = 0; range_ctr = 0; } }
static int prepare_for_renew_session(tc_sess_t *s, tc_iph_t *ip, tc_tcph_t *tcp) { uint16_t size_ip; uint32_t tot_clen, base_seq; tc_iph_t *fir_ip, *t_ip; tc_tcph_t *fir_tcp, *t_tcp; p_link_node ln; unsigned char *p; mysql_table_item_t *item; tc_mysql_session *mysql_sess; if (!ctx.fir_auth_pack) { tc_log_info(LOG_WARN, 0, "no first auth pack here"); return TC_ERR; } mysql_sess = s->data; if (mysql_sess == NULL) { tc_log_info(LOG_WARN, 0, "mysql session structure is not allocated"); return TC_ERR; } else if (mysql_sess->fir_auth_added) { tc_log_info(LOG_NOTICE, 0, "dup visit prepare_for_renew_session"); return TC_OK; } s->sm.need_rep_greet = 1; fir_ip = ctx.fir_auth_pack; fir_ip->saddr = ip->saddr; size_ip = fir_ip->ihl << 2; fir_tcp = (tc_tcph_t *) ((char *) fir_ip + size_ip); fir_tcp->source = tcp->source; tot_clen = ctx.fir_auth_cont_len; item = hash_find(ctx.table, s->hash_key); if (item) { tot_clen += item->tot_cont_len; } tc_log_debug2(LOG_INFO, 0, "total len subtracted:%u,p:%u", tot_clen, ntohs(s->src_port)); tcp->seq = htonl(ntohl(tcp->seq) - tot_clen); fir_tcp->seq = htonl(ntohl(tcp->seq) + 1); tc_save_pack(s, s->slide_win_packs, fir_ip, fir_tcp); mysql_sess->fir_auth_added = 1; base_seq = ntohl(fir_tcp->seq) + ctx.fir_auth_cont_len; if (item) { ln = link_list_first(item->list); while (ln) { p = (unsigned char *) ln->data; t_ip = (tc_iph_t *) (p + ETHERNET_HDR_LEN); t_tcp = (tc_tcph_t *) ((char *) t_ip + size_ip); t_tcp->seq = htonl(base_seq); tc_save_pack(s, s->slide_win_packs, t_ip, t_tcp); base_seq += TCP_PAYLOAD_LENGTH(t_ip, t_tcp); ln = link_list_get_next(item->list, ln); } } mysql_sess->old_ps_cleaned = 0; return TC_OK; }
static int faac_configure(TCModuleInstance *self, const char *options, vob_t *vob) { PrivateData *pd; int samplerate = vob->mp3frequency ? vob->mp3frequency : vob->a_rate; int ret; unsigned long dummy; faacEncConfiguration conf; TC_MODULE_SELF_CHECK(self, "configure"); pd = self->userdata; /* Save bytes per sample */ pd->bps = (vob->dm_chan * vob->dm_bits) / 8; /* Create FAAC handle (freeing any old one that might be left over) */ if (pd->handle) faacEncClose(pd->handle); pd->handle = faacEncOpen(samplerate, vob->dm_chan, &pd->framesize, &dummy); if (!pd->handle) { tc_log_error(MOD_NAME, "FAAC initialization failed"); return TC_ERROR; } /* Set up our default audio parameters */ /* why can't just use a pointer here? -- FR */ /* Because the function returns a pointer to an internal buffer --AC */ conf = *faacEncGetCurrentConfiguration(pd->handle); conf.mpegVersion = MPEG4; conf.aacObjectType = MAIN; conf.allowMidside = 1; conf.useLfe = 0; conf.useTns = 1; conf.bitRate = vob->mp3bitrate / vob->dm_chan; conf.bandWidth = 0; // automatic configuration conf.quantqual = 100; // FIXME: quality should be a per-module setting conf.outputFormat = 1; if (vob->dm_bits != 16) { tc_log_error(MOD_NAME, "Only 16-bit samples supported"); return TC_ERROR; } conf.inputFormat = FAAC_INPUT_16BIT; conf.shortctl = SHORTCTL_NORMAL; ret = optstr_get(options, "quality", "%li", &conf.quantqual); if (ret >= 0) { if (verbose >= TC_INFO) { tc_log_info(MOD_NAME, "using quality=%li", conf.quantqual); } } if (!faacEncSetConfiguration(pd->handle, &conf)) { tc_log_error(MOD_NAME, "Failed to set FAAC configuration"); faacEncClose(pd->handle); pd->handle = 0; return TC_ERROR; } /* Allocate local audio buffer */ if (pd->audiobuf) free(pd->audiobuf); pd->audiobuf = tc_malloc(pd->framesize * pd->bps); if (!pd->audiobuf) { tc_log_error(MOD_NAME, "Unable to allocate audio buffer"); faacEncClose(pd->handle); pd->handle = 0; return TC_ERROR; } return TC_OK; }
static int set_details() { clt_settings.session_keepalive_timeout = clt_settings.session_timeout; tc_log_info(LOG_NOTICE, 0, "keepalive timeout:%d", clt_settings.session_keepalive_timeout); if (clt_settings.users <= 0) { tc_log_info(LOG_ERR, 0, "please set the -u parameter"); return -1; } if (clt_settings.raw_clt_ips == NULL) { tc_log_info(LOG_ERR, 0, "please set the -c parameter"); return -1; } retrieve_client_ips(); /* set the ip port pair mapping according to settings */ if (retrieve_target_addresses(clt_settings.raw_transfer, &clt_settings.transfer) == -1) { return -1; } if (clt_settings.par_connections <= 0) { clt_settings.par_connections = 1; } else if (clt_settings.par_connections > MAX_CONNECTION_NUM) { clt_settings.par_connections = MAX_CONNECTION_NUM; } tc_log_info(LOG_NOTICE, 0, "parallel connections per target:%d", clt_settings.par_connections); if (clt_settings.raw_pcap_files == NULL) { tc_log_info(LOG_ERR, 0, "it must have -f argument for gryphon"); fprintf(stderr, "no -f argument\n"); return -1; } retrieve_pcap_files(); if (clt_settings.throughput_factor < 1) { clt_settings.throughput_factor = 1; } tc_log_info(LOG_NOTICE, 0, "throughput factor: %d,interval:%llu ms", clt_settings.throughput_factor, clt_settings.interval); if (clt_settings.interval > 0) { clt_settings.interval = clt_settings.interval * 1000; } #if (GRYPHON_PCAP_SEND) if (clt_settings.output_if_name != NULL) { tc_log_info(LOG_NOTICE, 0, "output device:%s", clt_settings.output_if_name); } else { tc_log_info(LOG_ERR, 0, "output device is null"); return -1; } #endif /* retrieve real server ip addresses */ if (clt_settings.raw_rs_list != NULL) { tc_log_info(LOG_NOTICE, 0, "s parameter:%s", clt_settings.raw_rs_list); retrieve_real_servers(); } else { tc_log_info(LOG_WARN, 0, "no real server ip addresses"); return -1; } /* daemonize */ if (clt_settings.do_daemonize) { if (sigignore(SIGHUP) == -1) { tc_log_info(LOG_ERR, errno, "Failed to ignore SIGHUP"); } if (daemonize() == -1) { fprintf(stderr, "failed to daemonize() in order to daemonize\n"); return -1; } } return 0; }
void router_update(int old, int main_router_fd, tc_ip_header_t *ip_header) { #if (!TCPCOPY_SINGLE) int fd; uint32_t key; #endif uint32_t size_ip, size_tcp, tot_len; msg_server_t msg; tc_tcp_header_t *tcp_header; #if (TCPCOPY_MYSQL_ADVANCED) uint32_t cont_len; unsigned char *payload, *p; #endif #if (TCPCOPY_SINGLE) if (main_router_fd == 0) { return; } #endif if (ip_header->protocol != IPPROTO_TCP) { tc_log_info(LOG_INFO, 0, "this is not a tcp packet"); return; } size_ip = ip_header->ihl << 2; tcp_header = (tc_tcp_header_t *) ((char *) ip_header + size_ip); size_tcp = tcp_header->doff << 2; tot_len = ntohs(ip_header->tot_len); memset(&msg, 0, sizeof(struct msg_server_s)); memcpy((void *) &(msg.ip_header), ip_header, sizeof(tc_ip_header_t)); memcpy((void *) &(msg.tcp_header), tcp_header, size_tcp); #if (TCPCOPY_MYSQL_ADVANCED) cont_len = tot_len - size_ip - size_tcp; if (cont_len > 0) { payload = (unsigned char *) ((char *) tcp_header + size_tcp); if (cont_len <= MAX_PAYLOAD_LEN) { p = ((unsigned char *) &(msg.tcp_header)) + size_tcp; memcpy((void *) p, payload, cont_len); } } #endif #if (!TCPCOPY_SINGLE) key = get_route_key(old, ip_header->daddr, tcp_header->dest, ip_header->saddr, tcp_header->source); fd = router_get(key); if (fd <= 0) { if (tcp_header->syn || tcp_header->rst) { if (tcp_header->rst) { tc_log_info(LOG_NOTICE, 0, "reset from tcp"); } tc_log_debug0(LOG_DEBUG, 0, "fd is null"); delay_table_add(key, &msg); return ; } else { tc_log_info(LOG_NOTICE, 0, "fd is null after session is created"); tc_log_trace(LOG_NOTICE, 0, BACKEND_FLAG, ip_header, tcp_header); return; } } #endif tc_log_debug_trace(LOG_NOTICE, 0, BACKEND_FLAG, ip_header, tcp_header); #if (INTERCEPT_COMBINED) #if (!TCPCOPY_SINGLE) buffer_and_send(main_router_fd, (int) (long) fd, &msg); #else buffer_and_send(main_router_fd, main_router_fd, &msg); #endif #else #if (!TCPCOPY_SINGLE) tc_socket_send((int) (long) fd, (char *) &msg, MSG_SERVER_SIZE); #else tc_socket_send(main_router_fd, (char *) &msg, MSG_SERVER_SIZE); #endif #endif }
/* * main entry point */ int main(int argc, char **argv) { int ret, is_continue = 1; settings_init(); #if (GRYPHON_SIGACTION) if (set_signal_handler(signals) == -1) { return -1; } #else signal(SIGALRM, tc_time_sig_alarm); signal(SIGINT, gryphon_over); signal(SIGPIPE, gryphon_over); signal(SIGHUP, gryphon_over); signal(SIGTERM, gryphon_over); #endif tc_time_init(); if (read_args(argc, argv) == -1) { return -1; } if (clt_settings.log_path == NULL) { clt_settings.log_path = "error_gryphon.log"; } if (tc_log_init(clt_settings.log_path) == -1) { return -1; } /* output debug info */ output_for_debug(argc, argv); /* set details for running */ if (set_details() == -1) { return -1; } if (set_timer() == -1) { return -1; } ret = tc_event_loop_init(&event_loop, MAX_FD_NUM); if (ret == TC_EVENT_ERROR) { tc_log_info(LOG_ERR, 0, "event loop init failed"); is_continue = 0; } if (is_continue) { ret = tc_build_session_table(65536); if (ret == TC_ERROR) { is_continue = 0; } else { ret = gryphon_init(&event_loop); if (ret == TC_ERROR) { is_continue = 0; } else { if (!tc_build_users(clt_settings.client_mode, clt_settings.users, clt_settings.valid_ips, clt_settings.valid_ip_num)) { is_continue = 0; } } } } if (is_continue) { if (set_timer() == -1) { is_continue = 0; } } if (is_continue) { /* run now */ tc_event_process_cycle(&event_loop); } gryphon_release_resources(); return 0; }
static int dispose_packet(unsigned char *frame, int frame_len, int ip_recv_len, int *p_valid_flag) { int replica_num, i, last, packet_num, max_payload, index, payload_len; char *p, buf[ETHERNET_HDR_LEN + IP_RECV_BUF_SIZE]; bool packet_valid = false; uint16_t id, size_ip, size_tcp, tot_len, cont_len, pack_len = 0, head_len; uint32_t seq; unsigned char *packet; tc_ip_header_t *ip_header; tc_tcp_header_t *tcp_header; packet = frame + ETHERNET_HDR_LEN; if (is_packet_needed(packet)) { replica_num = clt_settings.replica_num; ip_header = (tc_ip_header_t *) packet; if (clt_settings.clt_tf_ip != 0) { ip_header->saddr = clt_settings.clt_tf_ip; } /* * If the packet length is larger than MTU, we split it. */ if (ip_recv_len > clt_settings.mtu) { /* calculate number of packets */ size_ip = ip_header->ihl << 2; tot_len = ntohs(ip_header -> tot_len); if (tot_len != ip_recv_len) { tc_log_info(LOG_WARN, 0, "packet len:%u, recv len:%u", tot_len, ip_recv_len); return TC_ERROR; } tcp_header = (tc_tcp_header_t *) ((char *) ip_header + size_ip); size_tcp = tcp_header->doff << 2; cont_len = tot_len - size_tcp - size_ip; head_len = size_ip + size_tcp; max_payload = clt_settings.mtu - head_len; packet_num = (cont_len + max_payload - 1)/max_payload; seq = ntohl(tcp_header->seq); last = packet_num - 1; id = ip_header->id; #if (TCPCOPY_DEBUG) tc_log_trace(LOG_NOTICE, 0, CLIENT_FLAG, ip_header, tcp_header); #endif tc_log_debug1(LOG_DEBUG, 0, "recv:%d, more than MTU", ip_recv_len); index = head_len; for (i = 0 ; i < packet_num; i++) { tcp_header->seq = htonl(seq + i * max_payload); if (i != last) { pack_len = clt_settings.mtu; } else { pack_len += (cont_len - packet_num * max_payload); } payload_len = pack_len - head_len; ip_header->tot_len = htons(pack_len); ip_header->id = id++; p = buf + ETHERNET_HDR_LEN; /* copy header here */ memcpy(p, (char *) packet, head_len); p += head_len; /* copy payload here */ memcpy(p, (char *) (packet + index), payload_len); index = index + payload_len; if (replica_num > 1) { packet_valid = process_packet(true, (unsigned char *) buf, ETHERNET_HDR_LEN + pack_len); replicate_packs((unsigned char *) buf, ETHERNET_HDR_LEN + pack_len, replica_num); } else { packet_valid = process_packet(false, (unsigned char *) buf, ETHERNET_HDR_LEN + pack_len); } } } else { if (replica_num > 1) { packet_valid = process_packet(true, frame, frame_len); replicate_packs(frame, frame_len, replica_num); } else { packet_valid = process_packet(false, frame, frame_len); } } } if (p_valid_flag) { *p_valid_flag = (packet_valid == true ? 1 : 0); } return TC_OK; }
static void put_resp_header_to_pool(tc_ip_header_t *ip_header) { int *p_len, cur_w_pos, diff, next_w_pos; char *p_content; uint16_t size_ip, save_len, record_len; #if (TCPCOPY_MYSQL_ADVANCED) uint16_t size_tcp, cont_len, tot_len; unsigned char *payload; #endif uint64_t next_w_cnt; tc_tcp_header_t *tcp_header; if (ip_header->protocol != IPPROTO_TCP) { tc_log_info(LOG_WARN, 0, "this is not a tcp packet"); return; } save_len = RESP_MAX_USEFUL_SIZE; size_ip = ip_header->ihl << 2; tcp_header = (tc_tcp_header_t *) ((char *)ip_header + size_ip); #if (TCPCOPY_MYSQL_ADVANCED) size_tcp = tcp_header->doff << 2; tot_len = ntohs(ip_header->tot_len); cont_len = tot_len - size_ip - size_tcp; if (cont_len > 0 && cont_len <= MAX_PAYLOAD_LEN) { save_len += cont_len; } #endif record_len = save_len; pthread_mutex_lock(&mutex); next_w_cnt = write_counter + save_len + sizeof(int); next_w_pos = next_w_cnt & POOL_MASK; if (next_w_pos > POOL_MAX_ADDR) { next_w_cnt = (next_w_cnt / POOL_SIZE + 1) << POOL_SHIFT; record_len += (POOL_SIZE - next_w_pos); } diff = next_w_cnt - read_counter; for (;;) { if (diff > POOL_SIZE) { tc_log_info(LOG_WARN, 0, "pool is full"); pthread_cond_wait(&empty, &mutex); } else { break; } diff = next_w_cnt - read_counter; } cur_w_pos = write_counter & POOL_MASK; p_len = (int *) (pool + cur_w_pos); p_content = (char *) ((unsigned char *) p_len + sizeof(int)); write_counter = next_w_cnt; *p_len = record_len; ip_header->ihl = (sizeof(tc_ip_header_t)) >> 2; memcpy(p_content, ip_header, sizeof(tc_ip_header_t)); p_content = p_content + sizeof(tc_ip_header_t); memcpy(p_content, tcp_header, sizeof(tc_tcp_header_t)); #if (TCPCOPY_MYSQL_ADVANCED) if (cont_len > 0 && cont_len <= MAX_PAYLOAD_LEN) { p_content = p_content + sizeof(tc_tcp_header_t); payload = (unsigned char*) ((char*) tcp_header + size_tcp); memcpy(p_content, payload, cont_len); } #endif pthread_cond_signal(&full); pthread_mutex_unlock(&mutex); }
static void send_packets_from_pcap(int first) { int l2_len, ip_pack_len, p_valid_flag = 0; bool stop; pcap_t *pcap; unsigned char *pkt_data, *frame, *ip_data; struct pcap_pkthdr pkt_hdr; pcap = clt_settings.pcap; if (pcap == NULL) { return; } gettimeofday(&cur_time, NULL); stop = check_read_stop(); while (!stop) { pkt_data = (u_char *) pcap_next(pcap, &pkt_hdr); if (pkt_data != NULL) { if (pkt_hdr.caplen < pkt_hdr.len) { tc_log_info(LOG_WARN, 0, "truncated packets,drop"); } else { ip_data = get_ip_data(clt_settings.pcap, pkt_data, pkt_hdr.len, &l2_len); if (l2_len < ETHERNET_HDR_LEN) { tc_log_info(LOG_WARN, 0, "l2 len is %d", l2_len); continue; } last_pack_time = pkt_hdr.ts; if (ip_data != NULL) { clt_settings.pcap_time = last_pack_time.tv_sec * 1000 + last_pack_time.tv_usec / 1000; ip_pack_len = pkt_hdr.len - l2_len; tc_log_debug2(LOG_DEBUG, 0, "frame len:%d, ip len:%d", pkt_hdr.len, ip_pack_len); frame = ip_data - ETHERNET_HDR_LEN; dispose_packet(frame, ip_pack_len + ETHERNET_HDR_LEN, ip_pack_len, &p_valid_flag); if (p_valid_flag) { tc_log_debug0(LOG_DEBUG, 0, "valid flag for packet"); if (first) { first_pack_time = pkt_hdr.ts; first = 0; } else { adj_v_pack_diff = timeval_diff(&last_v_pack_time, &last_pack_time); } /* set last valid packet time in pcap file */ last_v_pack_time = last_pack_time; stop = check_read_stop(); } else { tc_log_debug0(LOG_DEBUG, 0, "invalid flag"); } } } } else { tc_log_info(LOG_WARN, 0, "stop, null from pcap_next"); stop = true; read_pcap_over = true; read_pcap_over_time = tc_time(); } } }
static int parse_options(char *options, int *pre, double *infps, double *outfps) { char *p, *pbase, *q, *r; size_t len; vob_t *vob; int default_pre, i; /* defaults from -f and --export_fps */ vob = tc_get_vob(); if (!vob) return -1; *infps = vob->fps; *outfps = vob->ex_fps; default_pre = 1; if (!options || !*options) return 0; if (!strcmp(options, "help")) { tc_log_info(MOD_NAME, "(%s) help\n" "This filter converts the video frame rate, by repeating or dropping frames.\n" "options: <input fps>:<output fps>\n" "example: -J fps=25:29.97 will convert from PAL to NTSC\n" "In addition to the frame rate options, you may also specify pre or post.\n" "If no rate options are given, defaults or -f/--export_fps/--export_frc will\n" "be used.\n" "If no pre or post options are given, decreasing rates will preprocess and\n" "increasing rates will postprocess.\n" , MOD_CAP); return -1; } len = strlen(options); p = pbase = malloc(len + 1); ac_memcpy(p, options, len); p[len] = '\0'; i = 0; do { q = memchr(p, ':', len); if (q) *q++ = '\0'; if (!strcmp(p, "pre")) { *pre = 1; default_pre = 0; } else if (!strncmp(p, "pre=", 4) && *(p + 4)) { *pre = strtol(p + 4, &r, 0); if (r == p) return -1; default_pre = 0; } else if (!strcmp(p, "post")) { *pre = 0; default_pre = 0; } else if (!strncmp(p, "post=", 5) && *(p + 5)) { *pre = !strtol(p + 4, &r, 0); if (r == p) return -1; default_pre = 0; } else { if (i == 0) { *infps = strtod(p, &r); if (r == p) return -1; } else if (i == 1) { *outfps = strtod(p, &r); if (r == p) return -1; } else return -1; i++; } } while (q && (p = q)); free(pbase); if (default_pre) { if (*infps > *outfps) *pre = 1; else if (*infps < *outfps) *pre = 0; } return 0; }
static int resp_dispose(tc_ip_header_t *ip_header) { int i, passed; uint16_t port, size_ip, size_tcp, tot_len; uint32_t ip_addr; ip_port_pair_t *pair; tc_tcp_header_t *tcp_header; if (ip_header->protocol != IPPROTO_TCP) { return TC_OK; } tot_resp_packs++; size_ip = ip_header->ihl << 2; if (size_ip < 20) { tc_log_info(LOG_WARN, 0, "Invalid IP header length: %d", size_ip); return TC_OK; } tot_len = ntohs(ip_header->tot_len); tcp_header = (tc_tcp_header_t *) ((char *) ip_header + size_ip); size_tcp = tcp_header->doff << 2; if (size_tcp < 20) { tc_log_info(LOG_WARN, 0, "Invalid TCP header len: %d bytes,pack len:%d", size_tcp, tot_len); return TC_OK; } #if (TCPCOPY_PCAP) if (srv_settings.user_filter != NULL) { passed = 1; } else { passed = 0; } #else passed = 0; #endif ip_addr = ip_header->saddr; port = tcp_header->source; if (!passed) { /* filter the packets we do care about */ for (i = 0; i < srv_settings.targets.num; i++) { pair = srv_settings.targets.mappings[i]; if (ip_addr == pair->ip && port == pair->port) { passed = 1; break; } else if (0 == pair->ip && port == pair->port) { passed = 1; break; } } if (passed == 0) { return TC_OK; } } tot_copy_resp_packs++; router_update(srv_settings.old, ip_header); return TC_OK; }
static int set_details() { #if (INTERCEPT_ADVANCED && TCPCOPY_PCAP) int len; #endif #if (!INTERCEPT_ADVANCED) /* retrieve ip address */ if (srv_settings.raw_ip_list != NULL) { tc_log_info(LOG_NOTICE, 0, "-x parameter:%s", srv_settings.raw_ip_list); retrieve_ip_addr(); } #endif #if (INTERCEPT_ADVANCED) if (srv_settings.raw_targets != NULL) { tc_log_info(LOG_NOTICE, 0, "-o parameter:%s", srv_settings.raw_targets); retrieve_target_addresses(srv_settings.raw_targets, &(srv_settings.targets)); } else { #if (!TCPCOPY_PCAP) tc_log_info(LOG_WARN, 0, "no raw targets for advanced mode"); return -1; #else tc_log_info(LOG_NOTICE, 0, "no raw targets for advanced mode"); #endif } #if (TCPCOPY_PCAP) if (srv_settings.raw_device != NULL) { tc_log_info(LOG_NOTICE, 0, "device:%s", srv_settings.raw_device); if (strcmp(srv_settings.raw_device, DEFAULT_DEVICE) == 0) { srv_settings.raw_device = NULL; } else { retrieve_devices(srv_settings.raw_device, &(srv_settings.devices)); } } if (srv_settings.user_filter != NULL) { tc_log_info(LOG_NOTICE, 0, "user filter:%s", srv_settings.user_filter); len = strlen(srv_settings.user_filter); if (len >= MAX_FILTER_LENGH) { tc_log_info(LOG_ERR, 0, "user filter is too long"); return -1; } memcpy(srv_settings.filter, srv_settings.user_filter, len); } else { extract_filter(); } #endif #endif #if (INTERCEPT_NFQUEUE) if (srv_settings.max_queue_len <= 1024) { srv_settings.max_queue_len = -1; } #endif /* daemonize */ if (srv_settings.do_daemonize) { if (sigignore(SIGHUP) == -1) { tc_log_info(LOG_ERR, errno, "failed to ignore SIGHUP"); } if (daemonize() == -1) { fprintf(stderr, "failed to daemonize() in order to daemonize\n"); return -1; } } return 0; }
/* sniff response packets in the second test machine */ static int sniff_init(tc_event_loop_t *event_loop) { #if (TCPCOPY_PCAP) int i = 0; bool work = false; char ebuf[PCAP_ERRBUF_SIZE]; devices_t *devices; pcap_if_t *alldevs, *d; #else int fd; tc_event_t *ev; #endif #if (TCPCOPY_PCAP) devices = &(srv_settings.devices); if (srv_settings.raw_device == NULL) { if (pcap_findalldevs(&alldevs, ebuf) == -1) { tc_log_info(LOG_ERR, 0, "error in pcap_findalldevs:%s", ebuf); return TC_ERROR; } for (d = alldevs; d; d = d->next) { if (strcmp(d->name, DEFAULT_DEVICE) == 0) { continue; } if (i >= MAX_DEVICE_NUM) { pcap_freealldevs(alldevs); tc_log_info(LOG_ERR, 0, "It has too many devices"); return TC_ERROR; } strcpy(devices->device[i++].name, d->name); } devices->device_num = i; pcap_freealldevs(alldevs); } for (i = 0; i < devices->device_num; i++) { if (tc_device_set(event_loop, &(devices->device[i])) == TC_ERROR) { tc_log_info(LOG_WARN, 0, "device could not work:%s", devices->device[i].name); } else { work = true; } } if (!work) { tc_log_info(LOG_ERR, 0, "no device available for snooping packets"); return TC_ERROR; } #else if ((fd = tc_raw_socket_in_init(COPY_FROM_LINK_LAYER)) == TC_INVALID_SOCKET) { return TC_ERROR; } tc_socket_set_nonblocking(fd); ev = tc_event_create(fd, tc_process_resp_packet, NULL); if (ev == NULL) { return TC_ERROR; } if (tc_event_add(event_loop, ev, TC_EVENT_READ) == TC_EVENT_ERROR) { tc_log_info(LOG_ERR, 0, "add socket(%d) to event loop failed.", fd); return TC_ERROR; } #endif return TC_OK; }
/* Initiate tcpcopy client */ int tcp_copy_init(tc_event_loop_t *event_loop) { int i; #if (TCPCOPY_OFFLINE) char *pcap_file, ebuf[PCAP_ERRBUF_SIZE]; #endif uint16_t online_port, target_port; uint32_t target_ip; tc_event_t *raw_socket_event; ip_port_pair_mapping_t *pair, **mappings; /* keep it temporarily */ select_server_set_callback(dispose_event); /* Register a timer to check resource every minute */ tc_event_timer_add(event_loop, 60000, check_resource_usage); /* Init session table*/ init_for_sessions(); localhost = inet_addr("127.0.0.1"); /* Init output raw socket info */ send_init(); /* Add connections to the tested server for exchanging info */ mappings = clt_settings.transfer.mappings; for (i = 0; i < clt_settings.transfer.num; i++) { pair = mappings[i]; online_port = pair->online_port; target_ip = pair->target_ip; target_port = pair->target_port; if (address_add_msg_conn(event_loop, online_port, target_ip, clt_settings.srv_port)) { return FAILURE; } tc_log_info(LOG_NOTICE, 0, "add a tunnel for exchanging info:%u", ntohs(target_port)); } #if (!TCPCOPY_OFFLINE) /* Init input raw socket info */ raw_sock = init_input_raw_socket(); #endif if (raw_sock != -1) { /* Add the input raw socket to select */ raw_socket_event = tc_event_create(raw_sock, dispose_event_wrapper, NULL); if (raw_socket_event == NULL) { return FAILURE; } if (tc_event_add(event_loop, raw_socket_event, TC_EVENT_READ) == TC_EVENT_ERROR) { tc_log_info(LOG_ERR, 0, "add raw socket(%d) to event loop failed.", raw_socket_event->fd); return FAILURE; } /* Init output raw socket info */ send_init(); /* Add connections to the tested server for exchanging info */ mappings = clt_settings.transfer.mappings; for (i = 0; i < clt_settings.transfer.num; i++) { pair = mappings[i]; online_port = pair->online_port; target_ip = pair->target_ip; target_port = pair->target_port; if (address_add_msg_conn(event_loop, online_port, target_ip, clt_settings.srv_port) == -1) { return FAILURE; } tc_log_info(LOG_NOTICE, 0, "add a tunnel for exchanging info:%u", ntohs(target_port)); } return SUCCESS; } else { #if (TCPCOPY_OFFLINE) select_offline_set_callback(send_packets_from_pcap); pcap_file = clt_settings.pcap_file; if (pcap_file != NULL) { if ((pcap = pcap_open_offline(pcap_file, ebuf)) == NULL) { tc_log_info(LOG_ERR, 0, "open %s" , ebuf); fprintf(stderr, "open %s\n", ebuf); return FAILURE; } else { gettimeofday(&base_time, NULL); tc_log_info(LOG_NOTICE, 0, "open pcap success:%s", pcap_file); tc_log_info(LOG_NOTICE, 0, "send the first packets here"); send_packets_from_pcap(1); } } else { return FAILURE; } #else return FAILURE; #endif } return SUCCESS; }
static int tc_msg_event_process(tc_event_t *rev) { int fd, version; msg_client_t msg; tunnel_basic_t *tunnel; fd = rev->fd; tunnel = srv_settings.tunnel; if (tunnel[fd].first_in) { if (tc_socket_recv(fd, (char *) &msg, MSG_CLIENT_MIN_SIZE) == TC_ERROR) { tc_intercept_release_tunnel(fd, rev); return TC_ERROR; } tunnel[fd].first_in = 0; version = ntohs(msg.type); if (msg.client_ip != 0 || msg.client_port != 0) { tunnel[fd].clt_msg_size = MSG_CLIENT_MIN_SIZE; srv_settings.old = 1; tc_log_info(LOG_WARN, 0, "client too old for intercept"); } else { if (version != INTERNAL_VERSION) { tc_log_info(LOG_WARN, 0, "not compatible,tcpcopy:%d,intercept:%d", msg.type, INTERNAL_VERSION); } tunnel[fd].clt_msg_size = MSG_CLIENT_SIZE; if (tc_socket_recv(fd, ((char *) &msg + MSG_CLIENT_MIN_SIZE), MSG_CLIENT_SIZE - MSG_CLIENT_MIN_SIZE) == TC_ERROR) { tc_intercept_release_tunnel(fd, rev); return TC_ERROR; } return TC_OK; } } else { if (tc_socket_recv(fd, (char *) &msg, tunnel[fd].clt_msg_size) == TC_ERROR) { tc_intercept_release_tunnel(fd, rev); return TC_ERROR; } } msg.client_ip = msg.client_ip; msg.client_port = msg.client_port; msg.type = ntohs(msg.type); msg.target_ip = msg.target_ip; msg.target_port = msg.target_port; switch (msg.type) { case CLIENT_ADD: #if (!TCPCOPY_SINGLE) tot_router_items++; tc_log_debug1(LOG_DEBUG, 0, "add client router:%u", ntohs(msg.client_port)); router_add(srv_settings.old, msg.client_ip, msg.client_port, msg.target_ip, msg.target_port, rev->fd); #endif break; case CLIENT_DEL: tc_log_debug1(LOG_DEBUG, 0, "del client router:%u", ntohs(msg.client_port)); break; default: tc_log_info(LOG_WARN, 0, "unknown msg type:%u", msg.type); } return TC_OK; }
static void output_for_debug() { /* print out version info */ tc_log_info(LOG_NOTICE, 0, "tcpcopy version:%s", VERSION); tc_log_info(LOG_NOTICE, 0, "tcpcopy internal version:%d", INTERNAL_VERSION); /* print out target info */ tc_log_info(LOG_NOTICE, 0, "target:%s", clt_settings.raw_tf); /* print out working mode info */ #if (TC_OFFLINE) tc_log_info(LOG_NOTICE, 0, "TC_OFFLINE mode"); #endif #if (TC_PCAP) tc_log_info(LOG_NOTICE, 0, "TC_PCAP mode"); #endif #if (TC_SINGLE) tc_log_info(LOG_NOTICE, 0, "TC_SINGLE mode"); #endif #if (TC_UDP) tc_log_info(LOG_NOTICE, 0, "TC_UDP mode"); #endif #if (TC_COMBINED) tc_log_info(LOG_NOTICE, 0, "TC_COMBINED mode"); #endif #if (TC_PCAP_SND) tc_log_info(LOG_NOTICE, 0, "TC_PCAP_SND mode"); #endif #if (TC_MILLION_SUPPORT) tc_log_info(LOG_NOTICE, 0, "TC_MILLION_SUPPORT mode"); #endif #if (TC_PLUGIN) tc_log_info(LOG_NOTICE, 0, "TC_PLUGIN mode"); #endif #if (TC_PAYLOAD) tc_log_info(LOG_NOTICE, 0, "TC_PAYLOAD is true"); #endif #if (TC_HAVE_EPOLL) tc_log_info(LOG_NOTICE, 0, "epoll mode"); #endif #if (TC_HAVE_PF_RING) tc_log_info(LOG_NOTICE, 0, "TC_HAVE_PF_RING is true"); #endif #if (TC_DETECT_MEMORY) tc_log_info(LOG_NOTICE, 0, "TC_DETECT_MEMORY is true"); #endif }
int tc_nfq_socket_init(struct nfq_handle **h, struct nfq_q_handle **qh, nfq_callback *cb, int max_queue_len) { int fd; tc_log_info(LOG_NOTICE, 0, "opening library handle"); *h = nfq_open(); if (!(*h)) { tc_log_info(LOG_ERR, errno, "error during nfq_open()"); return TC_INVALID_SOCK; } tc_log_info(LOG_NOTICE, 0, "unbinding existing nf_queue handler for AF_INET (if any)"); if (nfq_unbind_pf((*h), AF_INET) < 0) { tc_log_info(LOG_ERR, errno, "error during nfq_unbind_pf()"); return TC_INVALID_SOCK; } tc_log_info(LOG_NOTICE, 0, "binding nfnetlink_queue as nf_queue handler for AF_INET"); if (nfq_bind_pf((*h), AF_INET) < 0) { tc_log_info(LOG_ERR, errno, "error during nfq_bind_pf()"); return TC_INVALID_SOCK; } tc_log_info(LOG_NOTICE, 0, "binding this socket to queue"); *qh = nfq_create_queue((*h), 0, cb, NULL); if (!(*qh)) { tc_log_info(LOG_ERR, errno, "error during nfq_create_queue()"); return TC_INVALID_SOCK; } tc_log_info(LOG_NOTICE, 0, "setting copy_packet mode"); if (nfq_set_mode((*qh), NFQNL_COPY_PACKET, REP_MAX_USEFUL_SIZE) < 0) { tc_log_info(LOG_ERR, errno, "can't set packet_copy mode"); return TC_INVALID_SOCK; } if (max_queue_len > 0) { if (nfq_set_queue_maxlen((*qh), (uint32_t) max_queue_len) < 0) { tc_log_info(LOG_ERR, errno, "can't set queue max length:%d", max_queue_len); tc_log_info(LOG_WARN, 0, "unable to set queue maxlen"); tc_log_info(LOG_WARN, 0, "your kernel probably doesn't support it"); } } fd = nfq_fd(*h); nfnl_rcvbufsiz(nfq_nfnlh(*h), 16777216); return fd; }