本文转自http://eslxf.blog.51cto.com/918801/204275
1.4.2 pcap_open_live函数
函数首先创建pcap_t结构体,设置捕获数据包的长度,设置网卡为混杂模式,设置读取超时时间,最后激活该已打开的捕捉实例。
函数的重要代码如下:
pcap_t *pcap_open_live(const char *source, int snaplen,
int promisc, int to_ms, char *errbuf)
{
pcap_t *p;
int status;
/*创建pcap_t结构体*/
p = pcap_create(source, errbuf);
if (p == NULL)
return (NULL);
/*设置捕获数据包的长度*/
status = pcap_set_snaplen(p, snaplen);
if (status < 0)
goto fail;
/*设置混杂模式*/
status = pcap_set_promisc(p, promisc);
if (status < 0)
goto fail;
/*设置读取超时时间*/
status = pcap_set_timeout(p, to_ms);
if (status < 0)
goto fail;
/*如果使用pcap_open_live()函数,就设置为1*/
p->oldstyle = 1;
/*激活该已打开的捕捉实例p*/
status = pcap_activate(p);
if (status < 0)
goto fail;
return (p);
fail:
//出错处理
…
}
1.4.2.1 pcap_create函数
函数首先检查参数device是否为unicode字符串,如果是则转换为ASCII字符串,
然后设置p->activate_op函数指针指向pcap_activate_win32函数。
函数的重要代码如下:
pcap_t *pcap_create(const char *device, char *ebuf)
{
pcap_t *p;
/*检查device是否为unicode字符串,如果是转换为ASCII字符串 */
if (strlen(device) == 1)
{
//可能是unicode字符串
//转换为ASCII字符串,
//并把转换结果传递给pcap_create_common()函数
size_t length;
char* deviceAscii;
length = wcslen((wchar_t*)device);
deviceAscii = (char*)malloc(length + 1);
…
snprintf(deviceAscii, length + 1, "%ws", (wchar_t*)device);
p = pcap_create_common(deviceAscii, ebuf);
free(deviceAscii);
}
else
{
p = pcap_create_common(device, ebuf);
}
…
/*设置p->activate_op为pcap_activate_win32*/
p->activate_op = pcap_activate_win32;
…
return (p);
}
1.4.2.2 pcap_create_common函数
函数pcap_create_common()创建一个pcap_t结构体,并对结构体中的一些字段进行初始化,如果成功将返回指向pcap_t结构体内存的指针。参数source是所要打开源的名称,参数ebuf存储函数的错误信息。
函数的重要代码如下:
pcap_t *pcap_create_common(const char *source, char *ebuf)
{
pcap_t *p;
/*分配pcap_t的内存空间*/
p = malloc(sizeof(*p));
if (p == NULL) {
//分配失败,函数退出
}
memset(p, 0, sizeof(*p));
/* 给p->opt.source复制源字符串*/
p->opt.source = strdup(source);
if (p->opt.source == NULL) {
//失败,函数退出
}
/*
*默认为"不能设置rfmon模式"。
*如果被平台支持,可以设置该操作句柄,
*使用所设置的例程检测设备是否支持。
*/
p->can_set_rfmon_op = pcap_cant_set_rfmon;
/*
*一些操作只有在pcap_t是激活状态下才能执行
*把这些操作句柄设为“不支持”的句柄,直到pcap_t被激活
*/
p->read_op = (read_op_t)pcap_not_initialized;
p->inject_op = (inject_op_t)pcap_not_initialized;
p->setfilter_op = (setfilter_op_t)pcap_not_initialized;
p->setdirection_op = (setdirection_op_t)pcap_not_initialized;
p->set_datalink_op = (set_datalink_op_t)pcap_not_initialized;
p->getnonblock_op = (getnonblock_op_t)pcap_not_initialized;
p->setnonblock_op = (setnonblock_op_t)pcap_not_initialized;
p->stats_op = (stats_op_t)pcap_not_initialized;
#ifdef WIN32
p->setbuff_op = (setbuff_op_t)pcap_not_initialized;
p->setmode_op = (setmode_op_t)pcap_not_initialized;
p->setmintocopy_op = (setmintocopy_op_t)pcap_not_initialized;
#endif
p->cleanup_op = pcap_cleanup_live_common;
/* 把一些只设为默认的*/
pcap_set_timeout(p, 0);
pcap_set_snaplen(p, 65535);
p->opt.promisc = 0;
p->opt.buffer_size = 0;
return (p);
}
函数首先分配一个pcap_t结构体的内存空间,并对其清零。
然后给p->opt.source复制源字符串,然后设置p->can_set_rfmon_op操作句柄,使用所设置的例程pcap_cant_set_rfmon检测设备是否支持rfmon模式。
接着把一些只有在pcap_t是激活状态下才能执行的操作的句柄,设置为“不支持”的句柄pcap_not_initialized()。
把p->cleanup_op清除操作设置为pcap_cleanup_live_common()函数,使得与pcap_open_live()函数对应的pcap_close()函数调用,调用该函数正确释放各种资源。
最后把读取超时时间设为0,设置捕获数据包的长度为65535个字节,混杂模式p->opt.promisc设置为0,把缓冲区大小p->opt.buffer_size设为0。
其中函数pcap_cant_set_rfmon()的实现如下
static int pcap_cant_set_rfmon(pcap_t *p _U_)
{
return (0);
}
可见系统不支持rfmon模式。
函数pcap_not_initialized()的实现如下:
int pcap_not_initialized(pcap_t *pcap)
{
/*意味着“不初始化”*/
return PCAP_ERROR_NOT_ACTIVATED;
}