Divided the logic of the capwap_recvfrom function into two distinct functions:

poll (capwap_wait_recvready) and recv (capwap_recvfrom_fd)
This commit is contained in:
vemax78 2013-11-02 19:08:05 +01:00
parent 769d0f414e
commit 6ee885f9b6
2 changed files with 157 additions and 125 deletions

View File

@ -308,25 +308,14 @@ int capwap_compare_ip(struct sockaddr_storage* addr1, struct sockaddr_storage* a
return 1; return 1;
} }
/* Receive packet with timeout */ /* Wait receive packet with timeout */
int capwap_recvfrom(struct pollfd* fds, int fdscount, void* buffer, int* size, struct sockaddr_storage* recvfromaddr, struct sockaddr_storage* recvtoaddr, struct timeout_control* timeout) { int capwap_wait_recvready(struct pollfd* fds, int fdscount, struct timeout_control* timeout) {
int i; int i;
int polltimeout = -1;
int readysocket; int readysocket;
int result = CAPWAP_RECV_ERROR_SOCKET; int polltimeout = -1;
ASSERT(fds); ASSERT(fds);
ASSERT(fdscount > 0); ASSERT(fdscount > 0);
ASSERT(buffer != NULL);
ASSERT(size != NULL);
ASSERT(*size > 0);
ASSERT(recvfromaddr != NULL);
ASSERT(recvtoaddr != NULL);
memset(recvfromaddr, 0, sizeof(struct sockaddr_storage));
if (recvtoaddr) {
memset(recvtoaddr, 0, sizeof(struct sockaddr_storage));
}
/* Check timeout */ /* Check timeout */
if (timeout) { if (timeout) {
@ -349,101 +338,142 @@ int capwap_recvfrom(struct pollfd* fds, int fdscount, void* buffer, int* size, s
/* Get packet from only one socket */ /* Get packet from only one socket */
for (i = 0; i < fdscount; i++) { for (i = 0; i < fdscount; i++) {
if ((fds[i].revents & POLLIN) != 0) { if ((fds[i].revents & POLLIN) != 0) {
int packetsize = -1; return i;
socklen_t sendaddresslen = sizeof(struct sockaddr_storage);
struct sockaddr_storage sockinfo;
socklen_t sockinfolen = sizeof(struct sockaddr_storage);
struct iovec iov;
struct msghdr msgh;
struct cmsghdr* cmsg;
char cbuf[256];
/* Information socket */
memset(&sockinfo, 0, sizeof(struct sockaddr_storage));
if (getsockname(fds[i].fd, (struct sockaddr*)&sockinfo, &sockinfolen) < 0) {
break;
}
iov.iov_base = buffer;
iov.iov_len = *size;
memset(&msgh, 0, sizeof(struct msghdr));
msgh.msg_control = cbuf;
msgh.msg_controllen = sizeof(cbuf);
msgh.msg_name = recvfromaddr;
msgh.msg_namelen = sendaddresslen;
msgh.msg_iov = &iov;
msgh.msg_iovlen = 1;
msgh.msg_flags = 0;
/* Receive packet with recvmsg */
do {
packetsize = recvmsg(fds[i].fd, &msgh, 0);
} while ((packetsize < 0) && ((errno == EAGAIN) || (errno == EINTR)));
if (packetsize > 0) {
for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
#ifdef IP_PKTINFO
if ((cmsg->cmsg_level == SOL_IP) && (cmsg->cmsg_type == IP_PKTINFO)) {
struct in_pktinfo* i = (struct in_pktinfo*)CMSG_DATA(cmsg);
struct sockaddr_in* addr = (struct sockaddr_in*)recvtoaddr;
addr->sin_family = AF_INET;
memcpy(&addr->sin_addr, &i->ipi_addr, sizeof(struct in_addr));
addr->sin_port = ((struct sockaddr_in*)&sockinfo)->sin_port;
break;
}
#elif defined IP_RECVDSTADDR
if ((cmsg->cmsg_level == IPPROTO_IP) && (cmsg->cmsg_type == IP_RECVDSTADDR)) {
struct in_addr* i = (struct in_addr*)CMSG_DATA(cmsg);
struct sockaddr_in* addr = (struct sockaddr_in*)recvtoaddr;
addr->sin_family = AF_INET;
memcpy(&addr->sin_addr, i, sizeof(struct in_addr));
addr->sin_port = ((struct sockaddr_in*)&sockinfo)->sin_port;
break;
}
#else
#error "No method of getting the destination ip address supported"
#endif
if ((cmsg->cmsg_level == IPPROTO_IPV6) && ((cmsg->cmsg_type == IPV6_PKTINFO) || (cmsg->cmsg_type == IPV6_RECVPKTINFO))) {
struct in6_pktinfo* i = (struct in6_pktinfo*)CMSG_DATA(cmsg);
struct sockaddr_in6* addr = (struct sockaddr_in6*)recvtoaddr;
addr->sin6_family = AF_INET6;
memcpy(&addr->sin6_addr, &i->ipi6_addr, sizeof(struct in6_addr));
addr->sin6_port = ((struct sockaddr_in6*)&sockinfo)->sin6_port;
break;
}
}
} else if (packetsize < 0) {
break;
}
*size = packetsize;
result = i;
break;
} else if ((fds[i].revents & (POLLHUP | POLLERR | POLLNVAL)) != 0) { } else if ((fds[i].revents & (POLLHUP | POLLERR | POLLNVAL)) != 0) {
break; return CAPWAP_RECV_ERROR_SOCKET;
} }
} }
} else if (readysocket == 0) { } else if (readysocket == 0) {
result = CAPWAP_RECV_ERROR_TIMEOUT; /* Update timer for detect timeout */
if (timeout) { if (timeout) {
/* Update timer for detect timeout */
capwap_update_timeout(timeout); capwap_update_timeout(timeout);
} }
} else {
if (errno == EINTR) { return CAPWAP_RECV_ERROR_TIMEOUT;
result = CAPWAP_RECV_ERROR_INTR; } else if (errno == EINTR) {
} return CAPWAP_RECV_ERROR_INTR;
} }
return result; return CAPWAP_RECV_ERROR_SOCKET;
}
/* Receive packet from fd */
int capwap_recvfrom_fd(int fd, void* buffer, int* size, struct sockaddr_storage* recvfromaddr, struct sockaddr_storage* recvtoaddr) {
int packetsize = -1;
socklen_t sendaddresslen = sizeof(struct sockaddr_storage);
struct sockaddr_storage sockinfo;
socklen_t sockinfolen = sizeof(struct sockaddr_storage);
struct iovec iov;
struct msghdr msgh;
struct cmsghdr* cmsg;
char cbuf[256];
ASSERT(fd >= 0);
ASSERT(buffer != NULL);
ASSERT(size != NULL);
ASSERT(*size > 0);
ASSERT(recvfromaddr != NULL);
ASSERT(recvtoaddr != NULL);
memset(recvfromaddr, 0, sizeof(struct sockaddr_storage));
if (recvtoaddr) {
memset(recvtoaddr, 0, sizeof(struct sockaddr_storage));
}
/* Information socket */
memset(&sockinfo, 0, sizeof(struct sockaddr_storage));
if (getsockname(fd, (struct sockaddr*)&sockinfo, &sockinfolen) < 0) {
return 0;
}
iov.iov_base = buffer;
iov.iov_len = *size;
memset(&msgh, 0, sizeof(struct msghdr));
msgh.msg_control = cbuf;
msgh.msg_controllen = sizeof(cbuf);
msgh.msg_name = recvfromaddr;
msgh.msg_namelen = sendaddresslen;
msgh.msg_iov = &iov;
msgh.msg_iovlen = 1;
msgh.msg_flags = 0;
/* Receive packet with recvmsg */
do {
packetsize = recvmsg(fd, &msgh, 0);
} while ((packetsize < 0) && ((errno == EAGAIN) || (errno == EINTR)));
if (packetsize > 0) {
for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
#ifdef IP_PKTINFO
if ((cmsg->cmsg_level == SOL_IP) && (cmsg->cmsg_type == IP_PKTINFO)) {
struct in_pktinfo* i = (struct in_pktinfo*)CMSG_DATA(cmsg);
struct sockaddr_in* addr = (struct sockaddr_in*)recvtoaddr;
addr->sin_family = AF_INET;
memcpy(&addr->sin_addr, &i->ipi_addr, sizeof(struct in_addr));
addr->sin_port = ((struct sockaddr_in*)&sockinfo)->sin_port;
break;
}
#elif defined IP_RECVDSTADDR
if ((cmsg->cmsg_level == IPPROTO_IP) && (cmsg->cmsg_type == IP_RECVDSTADDR)) {
struct in_addr* i = (struct in_addr*)CMSG_DATA(cmsg);
struct sockaddr_in* addr = (struct sockaddr_in*)recvtoaddr;
addr->sin_family = AF_INET;
memcpy(&addr->sin_addr, i, sizeof(struct in_addr));
addr->sin_port = ((struct sockaddr_in*)&sockinfo)->sin_port;
break;
}
#else
#error "No method of getting the destination ip address supported"
#endif
if ((cmsg->cmsg_level == IPPROTO_IPV6) && ((cmsg->cmsg_type == IPV6_PKTINFO) || (cmsg->cmsg_type == IPV6_RECVPKTINFO))) {
struct in6_pktinfo* i = (struct in6_pktinfo*)CMSG_DATA(cmsg);
struct sockaddr_in6* addr = (struct sockaddr_in6*)recvtoaddr;
addr->sin6_family = AF_INET6;
memcpy(&addr->sin6_addr, &i->ipi6_addr, sizeof(struct in6_addr));
addr->sin6_port = ((struct sockaddr_in6*)&sockinfo)->sin6_port;
break;
}
}
} else if (packetsize < 0) {
return 0;
}
/* Packet receive */
*size = packetsize;
return 1;
}
/* Receive packet with timeout */
int capwap_recvfrom(struct pollfd* fds, int fdscount, void* buffer, int* size, struct sockaddr_storage* recvfromaddr, struct sockaddr_storage* recvtoaddr, struct timeout_control* timeout) {
int index;
ASSERT(fds);
ASSERT(fdscount > 0);
ASSERT(buffer != NULL);
ASSERT(size != NULL);
ASSERT(*size > 0);
ASSERT(recvfromaddr != NULL);
ASSERT(recvtoaddr != NULL);
/* Wait packet */
index = capwap_wait_recvready(fds, fdscount, timeout);
if (index < 0) {
return index;
}
/* Receive packet */
if (!capwap_recvfrom_fd(fds[index].fd, buffer, size, recvfromaddr, recvtoaddr)) {
return CAPWAP_RECV_ERROR_SOCKET;
}
return index;
} }
/* */ /* */
@ -1138,12 +1168,11 @@ static short capwap_get_interface_flags(char* iface) {
} }
strcpy(req.ifr_name, iface); strcpy(req.ifr_name, iface);
if (ioctl(sock, SIOCGIFFLAGS, &req) < 0) { if (ioctl(sock, SIOCGIFFLAGS, &req) < 0) {
req.ifr_flags = 0; req.ifr_flags = 0;
} }
close(sock); close(sock);
return req.ifr_flags; return req.ifr_flags;
} }

View File

@ -85,6 +85,9 @@ int capwap_compare_ip(struct sockaddr_storage* addr1, struct sockaddr_storage* a
int capwap_sendto(int sock, void* buffer, int size, struct sockaddr_storage* sendfromaddr, struct sockaddr_storage* sendtoaddr); int capwap_sendto(int sock, void* buffer, int size, struct sockaddr_storage* sendfromaddr, struct sockaddr_storage* sendtoaddr);
int capwap_sendto_fragmentpacket(int sock, struct capwap_list* fragmentlist, struct sockaddr_storage* sendfromaddr, struct sockaddr_storage* sendtoaddr); int capwap_sendto_fragmentpacket(int sock, struct capwap_list* fragmentlist, struct sockaddr_storage* sendfromaddr, struct sockaddr_storage* sendtoaddr);
int capwap_wait_recvready(struct pollfd* fds, int fdscount, struct timeout_control* timeout);
int capwap_recvfrom_fd(int fd, void* buffer, int* size, struct sockaddr_storage* recvfromaddr, struct sockaddr_storage* recvtoaddr);
int capwap_recvfrom(struct pollfd* fds, int fdscount, void* buffer, int* size, struct sockaddr_storage* recvfromaddr, struct sockaddr_storage* recvtoaddr, struct timeout_control* timeout); int capwap_recvfrom(struct pollfd* fds, int fdscount, void* buffer, int* size, struct sockaddr_storage* recvfromaddr, struct sockaddr_storage* recvtoaddr, struct timeout_control* timeout);
int capwap_ipv4_mapped_ipv6(struct sockaddr_storage* source, struct sockaddr_storage* dest); int capwap_ipv4_mapped_ipv6(struct sockaddr_storage* source, struct sockaddr_storage* dest);