libnids中多线程

来源:互联网 发布:淘宝链接短网址转换 编辑:程序博客网 时间:2024/06/05 04:47

可以通过设置全局变量nids_params.multiproc不为0来在libnids中使用多线程捕获数据包。libnids使用的是glib库的gthread-2.0线程函数(该函数库某些函数已经过时,例如线程创建函数;过时的api:https://developer.gnome.org/glib/stable/glib-Deprecated-Thread-APIs.html;新版thread接口:https://developer.gnome.org/glib/stable/glib-Threads.html)。

在libnids1.24源文件libnids.c中nids_run会调用pcap_loop函数进行循环捕获数据包的操作;pcap_loop函数的回调函数nids_pcap_heandler在设置了全局变量multiproc时,会将捕获的数据包片段插入到异步捕获队列中(这里的异步队列是glib的接口,用于在不同线程之间通信,https://developer.gnome.org/glib/stable/glib-Asynchronous-Queues.html)

int nids_run(){    if (!desc) {strcpy(nids_errbuf, "Libnids not initialized");return 0;    }    START_CAP_QUEUE_PROCESS_THREAD(); /* threading... */    pcap_loop(desc, -1, (pcap_handler) nids_pcap_handler, 0); //循环捕获数据包    /* FIXME: will this code ever be called? Don't think so - mcree */    STOP_CAP_QUEUE_PROCESS_THREAD();     nids_exit();    return 0;}
nids_pcap_handler部分代码:

 #ifdef HAVE_LIBGTHREAD_2_0     if(nids_params.multiproc) {  //如果系统有thread_2_0函数库并设置了使用多线程        /*          * Insert received fragment into the async capture queue.         * We hope that the overhead of memcpy          * will be saturated by the benefits of SMP - mcree         */        qitem=malloc(sizeof(struct cap_queue_item));        if (qitem && (qitem->data=malloc(hdr->caplen - nids_linkoffset))) {          qitem->caplen=hdr->caplen - nids_linkoffset;          memcpy(qitem->data,data_aligned,qitem->caplen);          g_async_queue_lock(cap_queue);  //为异步队列加锁          /* ensure queue does not overflow,如果队列长度大于全局变量queue_limit的限制就说明overflow了*/          if(g_async_queue_length_unlocked(cap_queue) > nids_params.queue_limit) {    /* queue limit reached: drop packet - should we notify user via syslog? */    free(qitem->data); //丢弃数据包数据    free(qitem);  //销毁数据包    } else {    /* insert packet to queue */    g_async_queue_push_unlocked(cap_queue,qitem);          }          g_async_queue_unlock(cap_queue); //解锁异步队列}     } else { /* user requested simple passthru - no threading */        call_ip_frag_procs(data_aligned,hdr->caplen - nids_linkoffset);     } #else     call_ip_frag_procs(data_aligned,hdr->caplen - nids_linkoffset); #endif}


可以看出nids_run函数中是通过宏START_CAP_QUEUE_PROCESS_THREAD()来创建新线程的,通过STOP_CAP_QUEUE_PROCESS_THREAD()来销毁线程的。

如下是宏 START_CAP_QUEUE_PROCESS_THREAD()和STOP_CAP_QUEUE_PROCESS_THREAD()的定义:

//g_thread_create_full从version 2.32开始被废弃了 and should not be used in newly-written code.//https://developer.gnome.org/glib/stable/glib-Deprecated-Thread-APIs.html#g-thread-create-full#define START_CAP_QUEUE_PROCESS_THREAD() \    if(nids_params.multiproc) { /* threading... */ \ if(!(g_thread_create_full((GThreadFunc)cap_queue_process_thread,NULL,0,FALSE,TRUE,G_THREAD_PRIORITY_LOW,&gerror))) { \    strcpy(nids_errbuf, "thread: "); \    strncat(nids_errbuf, gerror->message, sizeof(nids_errbuf) - 8); \    return 0; \ }; \    }#define STOP_CAP_QUEUE_PROCESS_THREAD() \    if(nids_params.multiproc) { /* stop the capture process thread */ \ g_async_queue_push(cap_queue,&EOF_item); \    }
g_thread_create_full创建新线程,其中第一个参数cap_queue_process_thread是要在新创建的线程里执行的函数,它的定义如下:
/* thread entry point  * pops capture queue items and feeds them to * the ip fragment processors - mcree */static void cap_queue_process_thread(){     struct cap_queue_item *qitem;          while(1) { /* loop "forever" */  qitem=g_async_queue_pop(cap_queue);  if (qitem==&EOF_item) break; /* EOF item received: we should exit */  call_ip_frag_procs(qitem->data,qitem->caplen);  free(qitem->data);  free(qitem);     }     g_thread_exit(NULL);}
该函数从异步队列中不断取出pcap_loop捕获的数据包,交给call_ip_frag_procs函数进行处理。上面nids_pcap_handler函数的部分代码中可以看出,如果没有设置使用多线程,那么直接在nids_pcap_handler函数中就使用call_ip_frag_procs函数处理数据包了。接下来处理过程参考http://blog.csdn.net/u013074465/article/details/45555837

0 0