C 套接字关闭(sd)呼叫(发送arp请求后)被卡住(挂起)
发送arp请求后,下面的C 套接字关闭(sd)呼叫(发送arp请求后)被卡住(挂起),c,linux,network-programming,C,Linux,Network Programming,发送arp请求后,下面的create_和
create_和
函数有时会挂起在close(sd)
调用中。这是因为创建了带有htons(ETH\u P\u ALL)
的套接字吗?我认为发送免费的ARP请求应该是htons(ETH\u P\u ARP)
如果我们将套接字协议类型改为ETH_p_ARP
而不是ETH_p_ALL
,会有任何副作用吗
create_and_send_arp(string port, IpAddress& addr)
{
const char *interface;
int frame_length, sd, bytes;
arp_hdr arphdr;
UINT32 address = addr.addr.ipv4.s_addr;
uint8_t src_ip[4], src_mac[6], dst_mac[6], ether_frame[IP_MAXPACKET];
struct sockaddr_ll device;
struct ifreq ifr;
// Interface to send packet through.
interface = port.c_str();
memcpy (src_ip, &address, 4 * sizeof (uint8_t));
// Submit request for a socket descriptor to look up interface.
if ((sd = socket (AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
perror ("socket() failed to get socket descriptor for using ioctl()");
return;
}
// Use ioctl() to look up interface name and get its MAC address.
memset (&ifr, 0, sizeof (ifr));
snprintf (ifr.ifr_name, sizeof (ifr.ifr_name), "%s", interface);
if (ioctl (sd, SIOCGIFHWADDR, &ifr) < 0) {
perror ("ioctl() failed to get source MAC address");
close (sd);
return;
}
close (sd);
// Copy source MAC address.
memcpy (src_mac, ifr.ifr_hwaddr.sa_data, 6 * sizeof (uint8_t));
// Find interface index from interface name and store index in
// struct sockaddr_ll device, which will be used as an argument of sendto().
if ((device.sll_ifindex = if_nametoindex (interface)) == 0) {
perror ("if_nametoindex() failed to obtain interface index");
return;
}
// Set destination MAC address: broadcast address
memset (dst_mac, 0xff, 6 * sizeof (uint8_t));
memcpy (&arphdr.sender_ip, src_ip, 4 * sizeof (uint8_t));
memcpy (&arphdr.target_ip, src_ip, 4 * sizeof (uint8_t));
// Fill out sockaddr_ll.
device.sll_family = AF_PACKET;
memcpy (device.sll_addr, src_mac, 6 * sizeof (uint8_t));
device.sll_halen = htons (6);
// ARP header
// Hardware type (16 bits): 1 for ethernet
arphdr.htype = htons (1);
// Protocol type (16 bits): 2048 for IP
arphdr.ptype = htons (ETH_P_IP);
// Hardware address length (8 bits): 6 bytes for MAC address
arphdr.hlen = 6;
// Protocol address length (8 bits): 4 bytes for IPv4 address
arphdr.plen = 4;
// OpCode: 1 for ARP request
arphdr.opcode = htons (ARPOP_REQUEST);
// Sender hardware address (48 bits): MAC address
memcpy (&arphdr.sender_mac, src_mac, 6 * sizeof (uint8_t));
// Target hardware address (48 bits): zero
memset (&arphdr.target_mac, 0, 6 * sizeof (uint8_t));
// Fill out ethernet frame header.
// Ethernet frame length = ethernet header (MAC + MAC + ethernet type) + ethernet data (ARP header)
frame_length = 6 + 6 + 2 + ARP_HDRLEN;
// Destination and Source MAC addresses
memcpy (ether_frame, dst_mac, 6 * sizeof (uint8_t));
memcpy (ether_frame + 6, src_mac, 6 * sizeof (uint8_t));
// Next is ethernet type code (ETH_P_ARP for ARP).
ether_frame[12] = ETH_P_ARP / 256;
ether_frame[13] = ETH_P_ARP % 256;
// ARP header
memcpy (ether_frame + ETH_HDRLEN, &arphdr, ARP_HDRLEN * sizeof (uint8_t));
if ((sd = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ARP))) < 0) {
perror ("socket() failed");
return;
}
// Send ethernet frame to socket.
if ((bytes = sendto (sd, ether_frame, frame_length, 0, (struct sockaddr *) &device, sizeof (device))) <= 0) {
perror ("sendto() failed");
close (sd);
return;
}
// Close socket descriptor.
close (sd); // this gets stuck and hangs
return;
}
部分回溯表明您的程序是多线程的,而且似乎还表明您有两个线程同时运行
close()
(不一定对应于同一源代码行)。多线程为间歇性故障提供了各种机会,因此合理的诊断步骤是尝试在单线程程序中重现问题。我们正在启动一个计时器(使用libevent),在计时器到期回调函数中,我们调用此ARP请求发送方法。因此,libevent可能会在内部为每个计时器事件创建线程,并从该线程调用回调函数。最终调用create_和send_arp方法。发布的问题是关于运行时的问题。因此,请发表一篇文章,以便我们重现问题并帮助您调试。似乎OP可以在他们的程序中对htons(ETH_P_ARP)进行较小的编辑。并在将问题发布到StackOverflow上之前对其进行测试(IMO:应该这样做)。部分回溯表明您的程序是多线程的,此外,它似乎还表明有两个线程同时运行close()
(不一定对应于同一个源代码行)。多线程为间歇性故障提供了各种机会,因此合理的诊断步骤是尝试在单线程程序中重现问题。我们正在启动一个计时器(使用libevent),在计时器到期回调函数中,我们调用此ARP请求发送方法。因此,libevent可能会在内部为每个计时器事件创建线程,并从该线程调用回调函数。最终调用create_和send_arp方法。发布的问题是关于运行时的问题。因此,请发布一篇文章,以便我们重现问题并帮助您调试。似乎OP可以在他们的程序中对htons(ETH_P_ARP)进行轻微编辑。并在将问题发布到stackoverflow之前对其进行测试(IMO:应该这样做)
[New LWP 29815]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
#0 0x00007f33984cf750 in __close_nocancel () from /lib64/libpthread.so.0
#0 0x00007f33984cf750 in __close_nocancel () from /lib64/libpthread.so.0