Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor: Modify udp_recvfrom. Raplace recvmsg with WSARecvMsg in windows #1324

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
32 changes: 17 additions & 15 deletions src/apps/common/apputils.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,19 +76,6 @@ int IS_TURN_SERVER = 0;

/*********************** Sockets *********************************/

int socket_set_nonblocking(evutil_socket_t fd) {
#if defined(WINDOWS)
unsigned long nonblocking = 1;
ioctlsocket(fd, FIONBIO, (unsigned long *)&nonblocking);
#else
if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
perror("O_NONBLOCK");
return -1;
}
#endif
return 0;
}

void read_spare_buffer(evutil_socket_t fd) {
if (fd >= 0) {
static char buffer[65536];
Expand Down Expand Up @@ -387,8 +374,23 @@ int get_raw_socket_tos(evutil_socket_t fd, int family) {
#else
socklen_t slen = (socklen_t)sizeof(tos);
if (getsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &tos, &slen) < 0) {
perror("get TCLASS on socket");
return -1;
#if defined(_MSC_VER)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this be checking defined(WINDOWS) like is done in other places?

/*NOTE: Because getsockopt is not support IPV6_TCLASS in windows.
* it need WSARecvMsg get IPV6_TCLASS. and it must called after bind().
* so there are ignore it!
* see: https://learn.microsoft.com/windows/win32/winsock/ipproto-ipv6-socket-options
* see: https://learn.microsoft.com/windows/win32/api/mswsock/nc-mswsock-lpfn_wsarecvmsg
*/
TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING,
"Because getsockopt is not support IPV6_TCLASS in windows. "
"it must use WSARecvMsg. so return TOS_DEFAULT. "
"Get TCLASS on fd[%d] fail. error code: %d\n",
fd, socket_errno());
return TOS_DEFAULT;
#else
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Get TCLASS on fd[%d] fail. error code: %d\n", fd, socket_errno());
#endif
return TOS_IGNORE;
}
#endif
} else {
Expand Down
1 change: 0 additions & 1 deletion src/apps/common/apputils.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,6 @@ int set_sock_buf_size(evutil_socket_t fd, int sz);
int socket_init(void);
int socket_set_reusable(evutil_socket_t fd, int reusable, SOCKET_TYPE st);
int sock_bind_to_device(evutil_socket_t fd, const unsigned char *ifname);
int socket_set_nonblocking(evutil_socket_t fd);
int socket_tcp_set_keepalive(evutil_socket_t fd, SOCKET_TYPE st);

int addr_connect(evutil_socket_t fd, const ioa_addr *addr, int *out_errno);
Expand Down
3 changes: 2 additions & 1 deletion src/apps/peer/udpserver.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ static int udp_create_server_socket(server_type *server, const char *ifname, con
if (addr_bind(udp_fd, server_addr, 1, 1, UDP_SOCKET) < 0)
return -1;

socket_set_nonblocking(udp_fd);
if (evutil_make_socket_nonblocking(udp_fd))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

braces please

TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Set socket nonblocking fail\n");

struct event *udp_ev =
event_new(server->event_base, udp_fd, EV_READ | EV_PERSIST, udp_server_input_handler, server_addr);
Expand Down
23 changes: 10 additions & 13 deletions src/apps/relay/dtls_listener.c
Original file line number Diff line number Diff line change
Expand Up @@ -467,28 +467,22 @@ static int create_new_connected_udp_socket(dtls_listener_relay_server_type *serv

evutil_socket_t udp_fd = socket(s->local_addr.ss.sa_family, CLIENT_DGRAM_SOCKET_TYPE, CLIENT_DGRAM_SOCKET_PROTOCOL);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check that s is valid to dereference before using operator->

if (udp_fd < 0) {
perror("socket");
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: Cannot allocate new socket\n", __FUNCTION__);
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Create socket fail: %d\n", socket_errno());
return -1;
}

if (sock_bind_to_device(udp_fd, (unsigned char *)(s->e->relay_ifname)) < 0) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot bind udp server socket to device %s\n", (char *)(s->e->relay_ifname));
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot bind udp server socket to device[%d]: %s\n", socket_errno(),
(char *)(s->e->relay_ifname));
}

ioa_socket_handle ret = (ioa_socket *)malloc(sizeof(ioa_socket));
ioa_socket_handle ret = create_ioa_socket_from_fd(NULL, udp_fd, NULL, s->st, CLIENT_SOCKET, NULL, NULL);
if (!ret) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: Cannot allocate new socket structure\n", __FUNCTION__);
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot allocate new ioa_socket\n");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would be nice to continue log the function name, as well as the file and line number.

Additionally, can the error code explaining the allocation failure be logged?

socket_closesocket(udp_fd);
return -1;
}

memset(ret, 0, sizeof(ioa_socket));

ret->magic = SOCKET_MAGIC;

ret->fd = udp_fd;

ret->family = s->family;
ret->st = s->st;
ret->sat = CLIENT_SOCKET;
Expand Down Expand Up @@ -627,7 +621,7 @@ static void udp_server_input_handler(evutil_socket_t fd, short what, void *arg)
#else
int flags = MSG_DONTWAIT;
#endif
bsize = udp_recvfrom(fd, &(server->sm.m.sm.nd.src_addr), &(server->addr), (char *)ioa_network_buffer_data(elem),
bsize = udp_recvfrom(s, &(server->sm.m.sm.nd.src_addr), &(server->addr), (char *)ioa_network_buffer_data(elem),
(int)ioa_network_buffer_get_capacity_udp(), &(server->sm.m.sm.nd.recv_ttl),
&(server->sm.m.sm.nd.recv_tos), server->e->cmsg, flags, NULL);

Expand Down Expand Up @@ -664,7 +658,7 @@ static void udp_server_input_handler(evutil_socket_t fd, short what, void *arg)
int ttl = 0;
int tos = 0;
int slen = server->slen0;
udp_recvfrom(fd, &orig_addr, &(server->addr), buffer, (int)sizeof(buffer), &ttl, &tos, server->e->cmsg, eflags,
udp_recvfrom(s, &orig_addr, &(server->addr), buffer, (int)sizeof(buffer), &ttl, &tos, server->e->cmsg, eflags,
&errcode);
// try again...
do {
Expand Down Expand Up @@ -789,6 +783,9 @@ static int create_server_socket(dtls_listener_relay_server_type *server, int rep
}
}

if (evutil_make_socket_nonblocking(udp_listen_fd))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

braces please

TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Set nonblocking fail\n");

server->udp_listen_ev =
event_new(server->e->event_base, udp_listen_fd, EV_READ | EV_PERSIST, udp_server_input_handler, server);

Expand Down
159 changes: 146 additions & 13 deletions src/apps/relay/ns_ioalib_engine_impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -786,7 +786,8 @@ int set_socket_options_fd(evutil_socket_t fd, SOCKET_TYPE st, int family) {
}
}

socket_set_nonblocking(fd);
if (evutil_make_socket_nonblocking(fd))
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Set socket nonblocking fail\n");

if (!is_stream_socket(st)) {
set_raw_socket_ttl_options(fd, family);
Expand Down Expand Up @@ -884,11 +885,12 @@ ioa_socket_handle create_unbound_relay_ioa_socket(ioa_engine_handle e, int famil
return NULL;
}

ret = (ioa_socket *)calloc(sizeof(ioa_socket), 1);

ret->magic = SOCKET_MAGIC;
ret = create_ioa_socket_from_fd(e, fd, NULL, st, sat, NULL, NULL);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

declare and define on same line

if (!ret) {
socket_closesocket(fd);
return NULL;
}

ret->fd = fd;
ret->family = family;
ret->st = st;
ret->sat = sat;
Expand Down Expand Up @@ -1294,10 +1296,28 @@ ioa_socket_handle create_ioa_socket_from_fd(ioa_engine_handle e, ioa_socket_raw
}

ret = (ioa_socket *)calloc(sizeof(ioa_socket), 1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

declare and define on same line

if (!ret) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot allocate new ioa_socket structure\n");
return NULL;
}

ret->magic = SOCKET_MAGIC;

ret->fd = fd;

#if defined(_MSC_VER)

DWORD dwBytesRecvd = 0;
GUID guidWSARecvMsg = WSAID_WSARECVMSG;
int nRet = WSAIoctl(fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &guidWSARecvMsg, sizeof(guidWSARecvMsg), &ret->recvmsg,
sizeof(LPFN_WSARECVMSG), &dwBytesRecvd, NULL, NULL);
if (nRet)
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "WSAIoctl fail:%d\n", socket_errno());
else if (!ret->recvmsg)
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "ret->recvmsg is null\n");

#endif

ret->st = st;
ret->sat = sat;
ret->e = e;
Expand Down Expand Up @@ -1933,11 +1953,15 @@ static int socket_readerr(evutil_socket_t fd, ioa_addr *orig_addr) {
typedef unsigned char recv_ttl_t;
typedef unsigned char recv_tos_t;

int udp_recvfrom(evutil_socket_t fd, ioa_addr *orig_addr, const ioa_addr *like_addr, char *buffer, int buf_size,
int udp_recvfrom(ioa_socket_handle s, ioa_addr *orig_addr, const ioa_addr *like_addr, char *buffer, int buf_size,
int *ttl, int *tos, char *ecmsg, int flags, uint32_t *errcode) {
int len = 0;

if (fd < 0 || !orig_addr || !like_addr || !buffer)
if (!s || !orig_addr || !like_addr || !buffer)
return -1;

evutil_socket_t fd = s->fd;
if (fd < 0)
return -1;

if (errcode)
Expand All @@ -1947,13 +1971,122 @@ int udp_recvfrom(evutil_socket_t fd, ioa_addr *orig_addr, const ioa_addr *like_a
recv_ttl_t recv_ttl = TTL_DEFAULT;
recv_tos_t recv_tos = TOS_DEFAULT;

#if defined(_MSC_VER) || !defined(CMSG_SPACE)
#if defined(_MSC_VER)

DWORD bytes_received = 0;
WSAMSG msg = {0};
WSABUF sbuf = {0};
uint8_t cmdbuf[512];
WSACMSGHDR *cmsg;
PIN6_PKTINFO pi;

sbuf.buf = (char FAR *)buffer;
sbuf.len = (u_long)buf_size;
msg.lpBuffers = &sbuf;
msg.dwBufferCount = 1;
msg.name = (LPSOCKADDR)orig_addr;
msg.namelen = slen;
msg.Control.buf = (char FAR *)cmdbuf;
msg.Control.len = (u_long)sizeof(cmdbuf);

if (!s->recvmsg) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING,
"WSARecvMsg is null. use recvfrom. the ttl and tos is not got. So set it to the default value\n");
len = recvfrom(fd, buffer, buf_size, flags, (struct sockaddr *)orig_addr, (socklen_t *)&slen);
if (len < 0 && errcode) {
*errcode = (uint32_t)socket_errno();
return -1;
}
return len;
}

int nRet = 0;
/* Receive a packet */
nRet = (s->recvmsg)(s->fd, &msg, &bytes_received, NULL, NULL);
if (nRet) {
if (s->e->verbose && socket_ewouldblock() == socket_errno())
TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "WSARecvMsg fail:%d\n", socket_errno());
else
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "WSARecvMsg fail:%d\n", socket_errno());
if (errcode)
*errcode = (uint32_t)socket_errno();
return -1;
}

/* Parse the header info, look for the local address */
cmsg = WSA_CMSG_FIRSTHDR(&msg);
for (; cmsg != NULL; cmsg = WSA_CMSG_NXTHDR(&msg, cmsg)) {
// TURN_LOG_FUNC(TURN_LOG_LEVEL_DEBUG, "level: %d; type:%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
switch (cmsg->cmsg_level) {
case IPPROTO_IP:
switch (cmsg->cmsg_type) {
#if defined(IP_RECVTTL) && !defined(__sparc_v9__)
case IP_RECVTTL:
case IP_TTL:
recv_ttl = *((recv_ttl_t *)WSA_CMSG_DATA(cmsg));
break;
#endif
#if defined(IP_RECVTOS)
case IP_RECVTOS:
case IP_TOS:
recv_tos = *((recv_tos_t *)WSA_CMSG_DATA(cmsg));
break;
#endif
#if defined(IP_RECVERR)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what would cause these various defines to be defined or not defined?

Having some documentation in the code explaining that would be helpful.

case IP_RECVERR: {
struct turn_sock_extended_err *e = (struct turn_sock_extended_err *)WSA_CMSG_DATA(cmsg);
if (errcode)
*errcode = e->ee_errno;
} break;
#endif
default:;
/* no break */
};
break;
case IPPROTO_IPV6:
switch (cmsg->cmsg_type) {
#if defined(IPV6_RECVHOPLIMIT) && !defined(__sparc_v9__)
case IPV6_RECVHOPLIMIT:
case IPV6_HOPLIMIT:
recv_ttl = *((recv_ttl_t *)CMSG_DATA(cmsg));
break;
#endif
#if defined(IPV6_RECVTCLASS)
case IPV6_RECVTCLASS:
case IPV6_TCLASS:
recv_tos = *((recv_tos_t *)WSA_CMSG_DATA(cmsg));
break;
#endif
#if defined(IPV6_RECVERR)
case IPV6_RECVERR: {
struct turn_sock_extended_err *e = (struct turn_sock_extended_err *)WSA_CMSG_DATA(cmsg);
if (errcode)
*errcode = e->ee_errno;
} break;
#endif
default:;
/* no break */
};
break;
default:;
/* no break */
};
}

len = bytes_received;

if (s->e->verbose)
TURN_LOG_FUNC(TURN_LOG_LEVEL_DEBUG, "WSARecvMsg len: %d; ttl: %08X; tos: %08X\n", bytes_received, recv_ttl,
recv_tos);

#elif !defined(CMSG_SPACE)
do {
len = recvfrom(fd, buffer, buf_size, flags, (struct sockaddr *)orig_addr, (socklen_t *)&slen);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what prevents this from looping forever?

} while (len < 0 && socket_eintr());
if (len < 0 && errcode)
*errcode = (uint32_t)socket_errno();
*errcode = (uint32_t)errno;
#else

struct msghdr msg;
struct iovec iov;

Expand All @@ -1977,7 +2110,7 @@ int udp_recvfrom(evutil_socket_t fd, ioa_addr *orig_addr, const ioa_addr *like_a
#endif

do {
len = recvmsg(fd, &msg, flags);
len = recvmsg(s->fd, &msg, flags);
} while (len < 0 && socket_eintr());

#if defined(MSG_ERRQUEUE)
Expand All @@ -1991,7 +2124,7 @@ int udp_recvfrom(evutil_socket_t fd, ioa_addr *orig_addr, const ioa_addr *like_a
// Linux
int eflags = MSG_ERRQUEUE | MSG_DONTWAIT;
uint32_t errcode1 = 0;
udp_recvfrom(fd, orig_addr, like_addr, buffer, buf_size, ttl, tos, ecmsg, eflags, &errcode1);
udp_recvfrom(s, orig_addr, like_addr, buffer, buf_size, ttl, tos, ecmsg, eflags, &errcode1);
// try again...
do {
len = recvmsg(fd, &msg, flags);
Expand Down Expand Up @@ -2507,8 +2640,8 @@ static int socket_input_worker(ioa_socket_handle s) {
if (len == 0)
len = -1;
} else if (s->fd >= 0) { /* UDP and DTLS */
ret = udp_recvfrom(s->fd, &remote_addr, &(s->local_addr), (char *)(buf_elem->buf.buf), UDP_STUN_BUFFER_SIZE, &ttl,
&tos, s->e->cmsg, 0, NULL);
ret = udp_recvfrom(s, &remote_addr, &(s->local_addr), (char *)(buf_elem->buf.buf), UDP_STUN_BUFFER_SIZE, &ttl, &tos,
s->e->cmsg, 0, NULL);
len = ret;
if (s->ssl && (len > 0)) { /* DTLS */
send_ssl_backlog_buffers(s);
Expand Down
9 changes: 8 additions & 1 deletion src/apps/relay/ns_ioalib_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@

#include <pthread.h>

#if defined(WINDOWS)
#include <mswsock.h>
#endif

#ifdef __cplusplus
extern "C" {
#endif
Expand Down Expand Up @@ -166,6 +170,9 @@ struct traffic_bytes {

struct _ioa_socket {
evutil_socket_t fd;
#if _MSC_VER
LPFN_WSARECVMSG recvmsg;
#endif
struct _ioa_socket *parent_s;
uint32_t magic;
ur_addr_map *sockets_container; /* relay container for UDP sockets */
Expand Down Expand Up @@ -262,7 +269,7 @@ void delete_socket_from_map(ioa_socket_handle s);
int is_connreset(void);
int would_block(void);
int udp_send(ioa_socket_handle s, const ioa_addr *dest_addr, const char *buffer, int len);
int udp_recvfrom(evutil_socket_t fd, ioa_addr *orig_addr, const ioa_addr *like_addr, char *buffer, int buf_size,
int udp_recvfrom(ioa_socket_handle s, ioa_addr *orig_addr, const ioa_addr *like_addr, char *buffer, int buf_size,
int *ttl, int *tos, char *ecmsg, int flags, uint32_t *errcode);
int ssl_read(evutil_socket_t fd, SSL *ssl, ioa_network_buffer_handle nbh, int verbose);

Expand Down