Commit e48e454b authored by Youness Alaoui's avatar Youness Alaoui

Move the trans stuff into the bind usage as it's the only place it's needed is...

Move the trans stuff into the bind usage as it's the only place it's needed is for the synchronous binding
parent 41dba789
...@@ -39,15 +39,26 @@ ...@@ -39,15 +39,26 @@
#ifdef _WIN32 #ifdef _WIN32
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h>
#include "win32_common.h" #include "win32_common.h"
#define close closesocket
#else #else
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h>
#include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h>
#include <sys/time.h> #include <sys/time.h>
#endif #endif
#ifdef HAVE_POLL
# include <poll.h>
#endif
#include "bind.h" #include "bind.h"
#include "stun/stunagent.h" #include "stun/stunagent.h"
...@@ -58,7 +69,8 @@ ...@@ -58,7 +69,8 @@
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include "timer.h" #include "timer.h"
#include "trans.h"
/** Non-blocking mode STUN binding discovery */ /** Non-blocking mode STUN binding discovery */
...@@ -157,6 +169,253 @@ stun_usage_bind_keepalive (StunAgent *agent, StunMessage *msg, ...@@ -157,6 +169,253 @@ stun_usage_bind_keepalive (StunAgent *agent, StunMessage *msg,
return stun_agent_finish_message (agent, msg, NULL, 0); return stun_agent_finish_message (agent, msg, NULL, 0);
} }
typedef struct stun_trans_s
{
int fd;
int own_fd;
socklen_t dstlen;
struct sockaddr_storage dst;
} StunTransport;
typedef enum {
STUN_USAGE_TRANS_RETURN_SUCCESS,
STUN_USAGE_TRANS_RETURN_ERROR,
STUN_USAGE_TRANS_RETURN_RETRY,
STUN_USAGE_TRANS_RETURN_INVALID_ADDRESS,
STUN_USAGE_TRANS_RETURN_UNSUPPORTED,
} StunUsageTransReturn;
static StunUsageTransReturn
stun_trans_init (StunTransport *tr, int fd,
const struct sockaddr *srv, socklen_t srvlen)
{
assert (fd != -1);
if ((size_t) srvlen > sizeof (tr->dst))
return STUN_USAGE_TRANS_RETURN_INVALID_ADDRESS;
tr->own_fd = -1;
tr->fd = fd;
tr->dstlen = srvlen;
memcpy (&tr->dst, srv, srvlen);
return STUN_USAGE_TRANS_RETURN_SUCCESS;
}
/*
* Creates and connects a socket. This is useful when a socket is to be used
* for multiple consecutive transactions (e.g. TURN).
*/
static int stun_socket (int family, int type, int proto)
{
int fd = socket (family, type, proto);
if (fd == -1)
return -1;
#ifdef FD_CLOEXEC
fcntl (fd, F_SETFD, fcntl (fd, F_GETFD) | FD_CLOEXEC);
#endif
#ifdef O_NONBLOCK
fcntl (fd, F_SETFL, fcntl (fd, F_GETFL) | O_NONBLOCK);
#endif
#ifdef MSG_ERRQUEUE
if (type == SOCK_DGRAM)
{
/* Linux specifics for ICMP errors on non-connected sockets */
int yes = 1;
switch (family)
{
case AF_INET:
setsockopt (fd, SOL_IP, IP_RECVERR, &yes, sizeof (yes));
break;
case AF_INET6:
setsockopt (fd, SOL_IPV6, IPV6_RECVERR, &yes, sizeof (yes));
break;
}
}
#endif
return fd;
}
static StunUsageTransReturn
stun_trans_create (StunTransport *tr, int type, int proto,
const struct sockaddr *srv, socklen_t srvlen)
{
StunUsageTransReturn val = STUN_USAGE_TRANS_RETURN_ERROR;
int fd;
if ((size_t) srvlen < sizeof(*srv))
return STUN_USAGE_TRANS_RETURN_INVALID_ADDRESS;
fd = stun_socket (srv->sa_family, type, proto);
if (fd == -1)
return STUN_USAGE_TRANS_RETURN_ERROR;
if (connect (fd, srv, srvlen) &&
#ifdef _WIN32
(WSAGetLastError () != WSAEINPROGRESS)) {
#else
(errno != EINPROGRESS)) {
#endif
goto error;
}
val = stun_trans_init (tr, fd, NULL, 0);
if (val)
goto error;
tr->own_fd = tr->fd;
return STUN_USAGE_TRANS_RETURN_SUCCESS;
error:
close (fd);
return val;
}
static void stun_trans_deinit (StunTransport *tr)
{
int saved = errno;
assert (tr->fd != -1);
if (tr->own_fd != -1)
close (tr->own_fd);
tr->own_fd = -1;
tr->fd = -1;
errno = saved;
}
#ifndef MSG_DONTWAIT
# define MSG_DONTWAIT 0
#endif
#ifndef MSG_NOSIGNAL
# define MSG_NOSIGNAL 0
#endif
static int stun_err_dequeue (int fd)
{
#ifdef MSG_ERRQUEUE
struct msghdr hdr;
int saved_errno = errno, ret;
memset (&hdr, 0, sizeof (hdr));
ret = (recvmsg (fd, &hdr, MSG_ERRQUEUE) >= 0);
errno = saved_errno;
return ret;
#else
return 0;
#endif
}
static ssize_t
stun_trans_sendto (StunTransport *tr, const uint8_t *buf, size_t len,
const struct sockaddr *dst, socklen_t dstlen)
{
static const int flags = MSG_DONTWAIT | MSG_NOSIGNAL;
ssize_t val;
do
{
if (dstlen > 0)
val = sendto (tr->fd, (void *)buf, len, flags, dst, dstlen);
else
val = send (tr->fd, (void *)buf, len, flags);
}
while ((val == -1) && stun_err_dequeue (tr->fd));
return val;
}
static ssize_t
stun_trans_recvfrom (StunTransport *tr, uint8_t *buf, size_t maxlen,
struct sockaddr * dst,
socklen_t * dstlen)
{
static const int flags = MSG_DONTWAIT | MSG_NOSIGNAL;
ssize_t val;
if (dstlen != NULL)
val = recvfrom (tr->fd, (void *)buf, maxlen, flags, dst, dstlen);
else
val = recv (tr->fd, (void *)buf, maxlen, flags);
if (val == -1)
stun_err_dequeue (tr->fd);
return val;
}
static ssize_t
stun_trans_send (StunTransport *tr, const uint8_t *buf, size_t len)
{
return stun_trans_sendto (tr, buf, len,
(struct sockaddr *)&tr->dst, tr->dstlen);
}
static ssize_t
stun_trans_recv (StunTransport *tr, uint8_t *buf, size_t maxlen)
{
return stun_trans_recvfrom (tr, buf, maxlen, NULL, NULL);
}
static int stun_trans_fd (const StunTransport *tr)
{
assert (tr != NULL);
return tr->fd;
}
/**
* Waits for a response or timeout to occur.
*
* @return ETIMEDOUT if the transaction has timed out, or 0 if an incoming
* message needs to be processed.
*/
static StunUsageTransReturn
stun_trans_poll (StunTransport *tr, unsigned int delay)
{
#ifdef HAVE_POLL
struct pollfd ufd;
memset (&ufd, 0, sizeof (ufd));
ufd.fd = stun_trans_fd (tr);
ufd.events |= POLLIN;
if (poll (&ufd, 1, delay) <= 0) {
return STUN_USAGE_TRANS_RETURN_RETRY;
}
return STUN_USAGE_TRANS_RETURN_SUCCESS;
#else
(void)tr;
return STUN_USAGE_TRANS_RETURN_UNSUPPORTED;
#endif
}
/** Blocking mode STUN binding discovery */ /** Blocking mode STUN binding discovery */
StunUsageBindReturn stun_usage_bind_run (const struct sockaddr *srv, StunUsageBindReturn stun_usage_bind_run (const struct sockaddr *srv,
socklen_t srvlen, struct sockaddr *addr, socklen_t *addrlen) socklen_t srvlen, struct sockaddr *addr, socklen_t *addrlen)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment