1
0
mirror of https://github.com/mfontanini/libtins synced 2026-01-23 02:35:57 +01:00

Fixed bug on PacketSender::send_recv which didn't work under OSX and FreeBSD.

This commit is contained in:
Matias Fontanini
2014-02-06 15:10:23 -03:00
parent ea927caa4b
commit fbef2e765d
2 changed files with 42 additions and 8 deletions

View File

@@ -325,6 +325,10 @@ namespace Tins {
SocketTypeMap _types;
uint32_t _timeout, _timeout_usec;
NetworkInterface default_iface;
// In BSD we need to store the buffer size, retrieved using BIOCGBLEN
#if defined(BSD) || defined(__FreeBSD_kernel__)
int buffer_size;
#endif
};
}

View File

@@ -162,6 +162,12 @@ void PacketSender::open_l2_socket(const NetworkInterface& iface) {
::close(sock);
throw socket_open_error(make_error_string());
}
// Use immediate mode
if(ioctl(sock, BIOCIMMEDIATE, &buffer_size) < 0)
throw socket_open_error(make_error_string());
// Get the buffer size
if(ioctl(sock, BIOCGBLEN, &buffer_size) < 0)
throw socket_open_error(make_error_string());
_ether_socket[iface.id()] = sock;
#else
if (_ether_socket == INVALID_RAW_SOCKET) {
@@ -320,7 +326,15 @@ PDU *PacketSender::recv_match_loop(const std::vector<int>& sockets, PDU &pdu, st
fd_set readfds;
struct timeval timeout, end_time;
int read;
uint8_t buffer[2048];
#if defined(BSD) || defined(__FreeBSD_kernel__)
// On *BSD, we need to allocate a buffer using the given size.
std::vector<uint8_t> actual_buffer(buffer_size);
uint8_t *buffer = &actual_buffer[0];
#else
uint8_t buffer[2048];
const int buffer_size = 2048;
#endif
timeout.tv_sec = _timeout;
end_time.tv_sec = time(0) + _timeout;
end_time.tv_usec = timeout.tv_usec = _timeout_usec;
@@ -333,13 +347,29 @@ PDU *PacketSender::recv_match_loop(const std::vector<int>& sockets, PDU &pdu, st
}
if((read = select(max_fd + 1, &readfds, 0, 0, &timeout)) == -1)
return 0;
for(std::vector<int>::const_iterator it = sockets.begin(); it != sockets.end(); ++it) {
if(FD_ISSET(*it, &readfds)) {
socket_len_type length = addrlen;
recvfrom_ret_type size;
size = recvfrom(*it, (char*)buffer, 2048, 0, link_addr, &length);
if(pdu.matches_response(buffer, size)) {
return Internals::pdu_from_flag(pdu.pdu_type(), buffer, size);
if(read > 0) {
for(std::vector<int>::const_iterator it = sockets.begin(); it != sockets.end(); ++it) {
if(FD_ISSET(*it, &readfds)) {
recvfrom_ret_type size;
#if defined(BSD) || defined(__FreeBSD_kernel__)
size = ::read(*it, buffer, buffer_size);
const uint8_t* ptr = buffer;
// We might see more than one packet
while(ptr < (buffer + size)) {
const bpf_hdr* bpf_header = reinterpret_cast<const bpf_hdr*>(ptr);
const uint8_t *pkt_start = ptr + bpf_header->bh_hdrlen;
if(pdu.matches_response(pkt_start, bpf_header->bh_caplen)) {
return Internals::pdu_from_flag(pdu.pdu_type(), pkt_start, bpf_header->bh_caplen);
}
ptr += BPF_WORDALIGN(bpf_header->bh_hdrlen + bpf_header->bh_caplen);
}
#else
socket_len_type length = addrlen;
size = ::recvfrom(*it, (char*)buffer, buffer_size, 0, link_addr, &length);
if(pdu.matches_response(buffer, size)) {
return Internals::pdu_from_flag(pdu.pdu_type(), buffer, size);
}
#endif
}
}
}