Commit da94499c authored by Kai Vehmanen's avatar Kai Vehmanen

Fixes to ICMP error handling. Fixed issues with role conflicts in STUN code.

darcs-hash:20070720212737-77cd4-8fe19842428b5eee01428a4fa0ab4d1f14f83479.gz
parent db89c760
...@@ -78,18 +78,30 @@ int stun_bind_run (int fd, ...@@ -78,18 +78,30 @@ int stun_bind_run (int fd,
unsigned delay = stun_bind_timeout (ctx); unsigned delay = stun_bind_timeout (ctx);
memset (ufd, 0, sizeof (ufd)); memset (ufd, 0, sizeof (ufd));
ufd[0].fd = stun_bind_fd (ctx), ufd[0].fd = fd = stun_bind_fd (ctx),
ufd[0].events = POLLIN; ufd[0].events = POLLIN;
poll (ufd, sizeof (ufd) / sizeof (ufd[0]), delay); if (poll (ufd, sizeof (ufd) / sizeof (ufd[0]), delay) <= 0)
val = recv (ufd[0].fd, buf + len, sizeof (buf) - len, MSG_DONTWAIT); {
if (val == -1)
val = stun_bind_elapse (ctx); val = stun_bind_elapse (ctx);
else continue;
}
val = recv (fd, buf + len, sizeof (buf) - len, MSG_DONTWAIT);
if (val == -1)
{ {
len += val; #ifdef MSG_ERRQUEUE
val = stun_bind_process (ctx, buf, len, addr, addrlen); /* FIXME: do proper ICMP error handling? */
struct msghdr hdr;
memset (&hdr, 0, sizeof (hdr));
recvmsg (fd, &hdr, MSG_ERRQUEUE);
#endif
val = EAGAIN;
continue;
} }
len += val;
val = stun_bind_process (ctx, buf, len, addr, addrlen);
} }
while (val == EAGAIN); while (val == EAGAIN);
...@@ -224,11 +236,11 @@ int stun_bind_process (stun_bind_t *restrict ctx, ...@@ -224,11 +236,11 @@ int stun_bind_process (stun_bind_t *restrict ctx,
const void *restrict buf, size_t len, const void *restrict buf, size_t len,
struct sockaddr *restrict addr, socklen_t *addrlen) struct sockaddr *restrict addr, socklen_t *addrlen)
{ {
int val; int val, code;
assert (ctx != NULL); assert (ctx != NULL);
val = stun_trans_preprocess (&ctx->trans, buf, len); val = stun_trans_preprocess (&ctx->trans, &code, buf, len);
switch (val) switch (val)
{ {
case EAGAIN: case EAGAIN:
...@@ -236,6 +248,8 @@ int stun_bind_process (stun_bind_t *restrict ctx, ...@@ -236,6 +248,8 @@ int stun_bind_process (stun_bind_t *restrict ctx,
case 0: case 0:
break; break;
default: default:
if (code == STUN_ROLE_CONFLICT)
val = ECONNRESET;
stun_bind_cancel (ctx); stun_bind_cancel (ctx);
return val; return val;
} }
...@@ -265,14 +279,16 @@ int ...@@ -265,14 +279,16 @@ int
stun_bind_keepalive (int fd, const struct sockaddr *restrict srv, stun_bind_keepalive (int fd, const struct sockaddr *restrict srv,
socklen_t srvlen) socklen_t srvlen)
{ {
size_t val;
uint8_t buf[28]; uint8_t buf[28];
size_t len = sizeof (buf);
int val;
stun_init_indication (buf, STUN_BINDING); stun_init_indication (buf, STUN_BINDING);
(void)stun_finish (buf, &val); val = stun_finish (buf, &len);
assert (val == 0);
/* NOTE: hopefully, this is only needed for non-stream sockets */ /* NOTE: hopefully, this is only needed for non-stream sockets */
if (sendto (fd, buf, val, MSG_DONTWAIT, srv, srvlen) == -1) if (stun_sendto (fd, buf, len, srv, srvlen) == -1)
return errno; return errno;
return 0; return 0;
} }
......
...@@ -142,7 +142,8 @@ int stun_bind_fd (const stun_bind_t *context); ...@@ -142,7 +142,8 @@ int stun_bind_fd (const stun_bind_t *context);
* *
* @return 0 on success, an error code otherwise: * @return 0 on success, an error code otherwise:
* - EAGAIN: ignored invalid message (non-fatal error) * - EAGAIN: ignored invalid message (non-fatal error)
* - ECONNREFUSED: error message from server * - ECONNRESET: role conflict error from server
* - ECONNREFUSED: any other fatal error message from server
* - EPROTO: unsupported message from server * - EPROTO: unsupported message from server
* - ENOENT: no mapped address in message from server * - ENOENT: no mapped address in message from server
* - EAFNOSUPPORT: unsupported mapped address family from server * - EAFNOSUPPORT: unsupported mapped address family from server
......
...@@ -50,14 +50,21 @@ static int ...@@ -50,14 +50,21 @@ static int
stun_bind_error (uint8_t *buf, size_t *plen, const uint8_t *req, stun_bind_error (uint8_t *buf, size_t *plen, const uint8_t *req,
stun_error_t code, const char *pass) stun_error_t code, const char *pass)
{ {
int val = stun_init_error (buf, *plen, req, code); size_t len = *plen;
int val;
*plen = 0;
DBG ("STUN Binding Error Reply (buffer size: %u)...\n", (unsigned)len);
val = stun_init_error (buf, len, req, code);
if (val) if (val)
return val; return val;
val = stun_finish_short (buf, plen, NULL, pass, NULL, 0); val = stun_finish_short (buf, &len, NULL, pass, NULL, 0);
if (val) if (val)
return val; return val;
*plen = len;
DBG (" Error response (%u) of %u bytes\n", (unsigned)code, DBG (" Error response (%u) of %u bytes\n", (unsigned)code,
(unsigned)*plen); (unsigned)*plen);
return 0; return 0;
...@@ -71,11 +78,16 @@ stun_binding_reply (uint8_t *buf, size_t *restrict plen, const uint8_t *msg, ...@@ -71,11 +78,16 @@ stun_binding_reply (uint8_t *buf, size_t *restrict plen, const uint8_t *msg,
{ {
size_t len = *plen; size_t len = *plen;
int val; int val;
*plen = 0;
#define err( code ) \ #define err( code ) \
stun_bind_error (buf, &len, msg, code, pass); \ stun_bind_error (buf, &len, msg, code, pass); \
*plen = len *plen = len
#define autherr( code ) \
stun_bind_error (buf, &len, msg, code, NULL); \
*plen = len
*plen = 0;
DBG ("STUN Binding Reply (buffer size = %u)...\n", (unsigned)len);
if (stun_get_class (msg) != STUN_REQUEST) if (stun_get_class (msg) != STUN_REQUEST)
{ {
...@@ -102,30 +114,23 @@ stun_binding_reply (uint8_t *buf, size_t *restrict plen, const uint8_t *msg, ...@@ -102,30 +114,23 @@ stun_binding_reply (uint8_t *buf, size_t *restrict plen, const uint8_t *msg,
if (!stun_has_integrity (msg)) if (!stun_has_integrity (msg))
{ {
DBG (" Message Authentication Code missing.\n"); DBG (" Message Authentication Code missing.\n");
err (STUN_BAD_REQUEST); autherr (STUN_UNAUTHORIZED);
return EPERM; return EPERM;
} }
if (!stun_present (msg, STUN_USERNAME)) if (!stun_present (msg, STUN_USERNAME))
{ {
DBG (" Username missing.\n"); DBG (" Username missing.\n");
err (STUN_BAD_REQUEST); autherr (STUN_UNAUTHORIZED);
return EPERM; return EPERM;
} }
/* FIXME: verify USERNAME, return 401 if wrong */ /* FIXME: verify USERNAME, return STUN_UNAUTHORIZED if wrong */
/* NOTE: should check in that order:
* - missing realm
* - missing nonce
* - stale nonce
* - unknown user / stale credentials
*/
if (stun_verify_password (msg, pass)) if (stun_verify_password (msg, pass))
{ {
DBG (" Integrity check failed.\n"); DBG (" Integrity check failed.\n");
err (STUN_INTEGRITY_CHECK_FAILURE); autherr (STUN_INTEGRITY_CHECK_FAILURE);
return EPERM; return EPERM;
} }
} }
...@@ -151,7 +156,7 @@ stun_binding_reply (uint8_t *buf, size_t *restrict plen, const uint8_t *msg, ...@@ -151,7 +156,7 @@ stun_binding_reply (uint8_t *buf, size_t *restrict plen, const uint8_t *msg,
return EPROTO; return EPROTO;
} }
stun_init_response (buf, msg); stun_init_response (buf, len, msg);
val = muxed val = muxed
? stun_append_xor_addr (buf, len, STUN_XOR_MAPPED_ADDRESS, src, srclen) ? stun_append_xor_addr (buf, len, STUN_XOR_MAPPED_ADDRESS, src, srclen)
: stun_append_addr (buf, len, STUN_MAPPED_ADDRESS, src, srclen); : stun_append_addr (buf, len, STUN_MAPPED_ADDRESS, src, srclen);
...@@ -166,9 +171,12 @@ stun_binding_reply (uint8_t *buf, size_t *restrict plen, const uint8_t *msg, ...@@ -166,9 +171,12 @@ stun_binding_reply (uint8_t *buf, size_t *restrict plen, const uint8_t *msg,
goto failure; goto failure;
*plen = len; *plen = len;
DBG (" All done (response size: %u)\n", (unsigned)len);
return 0; return 0;
failure: failure:
assert (*plen == 0);
DBG (" Fatal error formatting Binding Response: %s\n", strerror (val));
return val; return val;
} }
#undef err #undef err
...@@ -191,6 +199,7 @@ stun_conncheck_reply (uint8_t *buf, size_t *restrict plen, const uint8_t *msg, ...@@ -191,6 +199,7 @@ stun_conncheck_reply (uint8_t *buf, size_t *restrict plen, const uint8_t *msg,
const struct sockaddr *restrict src, socklen_t srclen, const struct sockaddr *restrict src, socklen_t srclen,
const char *pass, bool *restrict control, uint64_t tie) const char *pass, bool *restrict control, uint64_t tie)
{ {
size_t len = *plen;
uint64_t q; uint64_t q;
int val = stun_binding_reply (buf, plen, msg, src, srclen, true, pass); int val = stun_binding_reply (buf, plen, msg, src, srclen, true, pass);
...@@ -198,8 +207,7 @@ stun_conncheck_reply (uint8_t *buf, size_t *restrict plen, const uint8_t *msg, ...@@ -198,8 +207,7 @@ stun_conncheck_reply (uint8_t *buf, size_t *restrict plen, const uint8_t *msg,
return val; return val;
/* Role conflict handling */ /* Role conflict handling */
assert (buf != msg); /* cannot operate in place */
// FIXME: breaks if buf == msg
assert (val == 0); assert (val == 0);
if (!stun_find64 (msg, *control ? STUN_ICE_CONTROLLING if (!stun_find64 (msg, *control ? STUN_ICE_CONTROLLING
: STUN_ICE_CONTROLLED, &q)) : STUN_ICE_CONTROLLED, &q))
...@@ -217,9 +225,16 @@ stun_conncheck_reply (uint8_t *buf, size_t *restrict plen, const uint8_t *msg, ...@@ -217,9 +225,16 @@ stun_conncheck_reply (uint8_t *buf, size_t *restrict plen, const uint8_t *msg,
{ {
DBG (" staying \"controll%s\" (sending error)\n", DBG (" staying \"controll%s\" (sending error)\n",
*control ? "ing" : "ed"); *control ? "ing" : "ed");
*plen = len;
stun_bind_error (buf, plen, msg, STUN_ROLE_CONFLICT, pass); stun_bind_error (buf, plen, msg, STUN_ROLE_CONFLICT, pass);
} }
} }
#ifndef NDEBUG
else
if (stun_find64 (msg, *control ? STUN_ICE_CONTROLLED
: STUN_ICE_CONTROLLING, &q))
DBG ("STUN Role not specified by peer!\n");
#endif
return val; return val;
} }
......
...@@ -179,7 +179,7 @@ typedef enum ...@@ -179,7 +179,7 @@ typedef enum
STUN_ROLE_CONFLICT=487, /* ICE-17 */ STUN_ROLE_CONFLICT=487, /* ICE-17 */
STUN_SERVER_ERROR=500, /* RFC3489bis-07 */ STUN_SERVER_ERROR=500, /* RFC3489bis-07 */
STUN_SERVER_CAPACITY=507, /* TURN-04 */ STUN_SERVER_CAPACITY=507, /* TURN-04 */
STUN_GLOBAL_FAILURE=600 // FIXME STUN_ERROR_MAX=699
} stun_error_t; } stun_error_t;
...@@ -441,21 +441,23 @@ void stun_init_request (uint8_t *msg, stun_method_t m); ...@@ -441,21 +441,23 @@ void stun_init_request (uint8_t *msg, stun_method_t m);
void stun_init_indication (uint8_t *msg, stun_method_t m); void stun_init_indication (uint8_t *msg, stun_method_t m);
/** /**
* Initializes a STUN message buffer with no attributes, * Initializes a STUN message buffer with a SERVER attribute (if there is
* in response to a given valid STUN request messsage. * enough room for it), in response to a given valid STUN request messsage.
* STUN method and transaction ID are copied from the request message. * STUN method and transaction ID are copied from the request message.
* *
* @param ans [OUT] STUN message buffer * @param ans [OUT] STUN message buffer
* @param msize STUN message buffer size
* @param req STUN message query * @param req STUN message query
* *
* ans == req is allowed. * ans == req is allowed.
*/ */
void stun_init_response (uint8_t *ans, const uint8_t *req); void stun_init_response (uint8_t *ans, size_t msize, const uint8_t *req);
/** /**
* Initializes a STUN error response message buffer with an ERROR-CODE * Initializes a STUN error response message buffer with an ERROR-CODE
* attribute, in response to a given valid STUN request messsage. * and a SERVER attributes, in response to a given valid STUN request
* STUN method and transaction ID are copied from the request message. * messsage. STUN method and transaction ID are copied from the request
* message.
* *
* @param ans [OUT] STUN message buffer * @param ans [OUT] STUN message buffer
* @param msize STUN message buffer size * @param msize STUN message buffer size
...@@ -612,4 +614,22 @@ static inline bool stun_has_integrity (const uint8_t *msg) ...@@ -612,4 +614,22 @@ static inline bool stun_has_integrity (const uint8_t *msg)
return stun_present (msg, STUN_MESSAGE_INTEGRITY); return stun_present (msg, STUN_MESSAGE_INTEGRITY);
} }
# ifndef NDEBUG
/**
* This function is for debugging only, which is why it is only defined under
* !NDEBUG. It should really only be used in run-time assertions, as it cannot
* detect all possible errors. stun_validate() should be used instead in real
* code.
*
* @param msg pointer to a potential STUN message
* @return whether the pointer refers to a valid STUN message
*/
static inline bool stun_valid (const uint8_t *msg)
{
size_t length = 20u + stun_length (msg);
return stun_validate (msg, length) == (ssize_t)length;
}
# endif
#endif #endif
...@@ -523,20 +523,19 @@ int stun_find_errno (const uint8_t *restrict msg, int *restrict code) ...@@ -523,20 +523,19 @@ int stun_find_errno (const uint8_t *restrict msg, int *restrict code)
{ {
uint16_t alen; uint16_t alen;
const uint8_t *ptr = stun_find (msg, STUN_ERROR_CODE, &alen); const uint8_t *ptr = stun_find (msg, STUN_ERROR_CODE, &alen);
uint8_t class, number;
*code = -1;
if (ptr == NULL) if (ptr == NULL)
return ENOENT; return ENOENT;
if (alen < 4) if (alen < 4)
return EINVAL; return EINVAL;
*code = ((ptr[2] & 0x7) * 100) + ptr[3]; class = ptr[2] & 0x7;
/* NOTE: we are a bit laxist here. We should also ignore packets where number = ptr[3];
* the "Number" (ptr[3]) > 99 */ if ((class < 3) || (class > 6) || (number > 99))
if ((*code < 100) || (*code > 699))
return EINVAL; return EINVAL;
*code = (class * 100) + number;
return 0; return 0;
} }
...@@ -561,6 +560,11 @@ stun_match_answer (const uint8_t *msg, stun_method_t method, ...@@ -561,6 +560,11 @@ stun_match_answer (const uint8_t *msg, stun_method_t method,
assert (stun_valid (msg)); assert (stun_valid (msg));
assert (error != NULL); assert (error != NULL);
if ((stun_get_method (msg) != method) /* wrong request type */
|| !check_cookie (msg) /* response to old-style request */
|| memcmp (msg + 8, id, 12)) /* wrong transaction ID */
return false;
switch (stun_get_class (msg)) switch (stun_get_class (msg))
{ {
case STUN_REQUEST: case STUN_REQUEST:
...@@ -573,18 +577,10 @@ stun_match_answer (const uint8_t *msg, stun_method_t method, ...@@ -573,18 +577,10 @@ stun_match_answer (const uint8_t *msg, stun_method_t method,
case STUN_ERROR: case STUN_ERROR:
if (stun_find_errno (msg, error)) if (stun_find_errno (msg, error))
{ return false; // missing ERROR-CODE: ignore message
assert (*error == -1);
return false; // missing ERROR-CODE?!
}
break; break;
} }
if ((stun_get_method (msg) != method) /* wrong request type */
|| !check_cookie (msg) /* response to old-style request */
|| memcmp (msg + 8, id, 12)) /* wrong transaction ID */
return false;
if ((key != NULL) && stun_verify_key (msg, key, keylen)) if ((key != NULL) && stun_verify_key (msg, key, keylen))
return false; return false;
......
...@@ -111,15 +111,6 @@ void stun_init_indication (uint8_t *req, stun_method_t m) ...@@ -111,15 +111,6 @@ void stun_init_indication (uint8_t *req, stun_method_t m)
} }
void stun_init_response (uint8_t *ans, const uint8_t *req)
{
//assert (stun_valid (req));
assert (stun_get_class (req) == STUN_REQUEST);
stun_init (ans, STUN_RESPONSE, stun_get_method (req), stun_id (req));
}
/** /**
* Reserves room for appending an attribute to an unfinished STUN message. * Reserves room for appending an attribute to an unfinished STUN message.
* @param msg STUN message buffer * @param msg STUN message buffer
...@@ -137,6 +128,7 @@ stun_append (uint8_t *msg, size_t msize, stun_attr_type_t type, size_t length) ...@@ -137,6 +128,7 @@ stun_append (uint8_t *msg, size_t msize, stun_attr_type_t type, size_t length)
uint8_t *a; uint8_t *a;
uint16_t mlen = stun_length (msg); uint16_t mlen = stun_length (msg);
assert (stun_valid (msg));
assert (stun_padding (mlen) == 0); assert (stun_padding (mlen) == 0);
if (msize > STUN_MAXMSG) if (msize > STUN_MAXMSG)
...@@ -216,6 +208,26 @@ stun_append_string (uint8_t *restrict msg, size_t msize, ...@@ -216,6 +208,26 @@ stun_append_string (uint8_t *restrict msg, size_t msize,
} }
static int stun_append_server (uint8_t *restrict msg, size_t msize)
{
static const char server[] = PACKAGE_STRING;
assert (strlen (server) < 128);
return stun_append_string (msg, msize, STUN_SERVER, server);
}
void stun_init_response (uint8_t *ans, size_t msize, const uint8_t *req)
{
assert (stun_valid (req));
assert (stun_get_class (req) == STUN_REQUEST);
assert (msize >= 20u);
stun_init (ans, STUN_RESPONSE, stun_get_method (req), stun_id (req));
(void)stun_append_server (ans, msize);
}
/** /**
* @param code host-byte order error code * @param code host-byte order error code
* @return a static pointer to a nul-terminated error message string. * @return a static pointer to a nul-terminated error message string.
...@@ -257,15 +269,21 @@ static const char *stun_strerror (stun_error_t code) ...@@ -257,15 +269,21 @@ static const char *stun_strerror (stun_error_t code)
{ STUN_SERVER_CAPACITY, "Temporary server congestion" }, { STUN_SERVER_CAPACITY, "Temporary server congestion" },
{ 0, "" } { 0, "" }
}; };
const char *str = "Unknown error";
unsigned i; unsigned i;
for (i = 0; tab[i].phrase[0]; i++) for (i = 0; tab[i].phrase[0]; i++)
{ {
if (tab[i].code == code) if (tab[i].code == code)
return tab[i].phrase; {
str = tab[i].phrase;
break;
}
} }
return "Unknown error"; /* Maximum allowed error message length */
assert (strlen (str) < 128);
return str;
} }
...@@ -299,9 +317,11 @@ stun_append_error (uint8_t *restrict msg, size_t msize, stun_error_t code) ...@@ -299,9 +317,11 @@ stun_append_error (uint8_t *restrict msg, size_t msize, stun_error_t code)
int stun_init_error (uint8_t *ans, size_t msize, const uint8_t *req, int stun_init_error (uint8_t *ans, size_t msize, const uint8_t *req,
stun_error_t err) stun_error_t err)
{ {
//assert (stun_valid (req)); assert (stun_valid (req));
assert (msize >= 20u);
stun_init (ans, STUN_ERROR, stun_get_method (req), stun_id (req)); stun_init (ans, STUN_ERROR, stun_get_method (req), stun_id (req));
(void)stun_append_server (ans, msize);
return stun_append_error (ans, msize, err); return stun_append_error (ans, msize, err);
} }
...@@ -315,7 +335,7 @@ int stun_init_error_unknown (uint8_t *ans, size_t msize, const uint8_t *req) ...@@ -315,7 +335,7 @@ int stun_init_error_unknown (uint8_t *ans, size_t msize, const uint8_t *req)
uint16_t ids[256]; uint16_t ids[256];
#endif #endif
//assert (stun_valid (req)); assert (stun_valid (req));
assert (stun_get_class (req) == STUN_REQUEST); assert (stun_get_class (req) == STUN_REQUEST);
counter = stun_find_unknown (req, ids, sizeof (ids) / sizeof (ids[0])); counter = stun_find_unknown (req, ids, sizeof (ids) / sizeof (ids[0]));
...@@ -390,13 +410,16 @@ int stun_append_xor_addr (uint8_t *restrict msg, size_t msize, ...@@ -390,13 +410,16 @@ int stun_append_xor_addr (uint8_t *restrict msg, size_t msize,
const struct sockaddr *restrict addr, const struct sockaddr *restrict addr,
socklen_t addrlen) socklen_t addrlen)
{ {
struct sockaddr_storage xor;
int val; int val;
union
{
struct sockaddr addr;
char fill[addrlen];
} xor;
if (addrlen > sizeof (xor)) assert (sizeof (xor) >= addrlen);
return ENOBUFS;
memcpy (&xor, addr, addrlen); memcpy (&xor, addr, addrlen);
val = stun_xor_address (msg, (struct sockaddr *)&xor, addrlen); val = stun_xor_address (msg, (struct sockaddr *)&xor, addrlen);
if (val) if (val)
return val; return val;
......
...@@ -71,8 +71,8 @@ int stun_trans_init (stun_trans_t *restrict tr, int fd, ...@@ -71,8 +71,8 @@ int stun_trans_init (stun_trans_t *restrict tr, int fd,
tr->key.length = 0; tr->key.length = 0;
tr->key.value = NULL; tr->key.value = NULL;
if (getsockopt (fd, SOL_SOCKET, SO_TYPE, &sotype, &solen)) assert (getsockopt (fd, SOL_SOCKET, SO_TYPE, &sotype, &solen) == 0);
return errno; (void)getsockopt (fd, SOL_SOCKET, SO_TYPE, &sotype, &solen);
switch (sotype) switch (sotype)
{ {
...@@ -186,14 +186,36 @@ static inline int stun_err_dequeue (int fd) ...@@ -186,14 +186,36 @@ static inline int stun_err_dequeue (int fd)
{ {
#ifdef MSG_ERRQUEUE #ifdef MSG_ERRQUEUE
struct msghdr hdr; struct msghdr hdr;
int saved_errno = errno, ret;
memset (&hdr, 0, sizeof (hdr)); memset (&hdr, 0, sizeof (hdr));
return recvmsg (fd, &hdr, MSG_ERRQUEUE) == 0; ret = (recvmsg (fd, &hdr, MSG_ERRQUEUE) >= 0);
errno = saved_errno;
return ret;
#else #else
return 0; return 0;
#endif #endif
} }
ssize_t stun_sendto (int fd, 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 (fd, buf, len, flags, dst, dstlen);
else
val = send (fd, buf, len, flags);
}
while ((val == -1) && stun_err_dequeue (fd));
return val;
}
/** /**
* Try to send STUN request/indication * Try to send STUN request/indication
*/ */
...@@ -203,31 +225,18 @@ stun_trans_send (stun_trans_t *tr) ...@@ -203,31 +225,18 @@ stun_trans_send (stun_trans_t *tr)
const uint8_t *data = tr->msg.buf + tr->msg.offset; const uint8_t *data = tr->msg.buf + tr->msg.offset;
size_t len = tr->msg.length - tr->msg.offset; size_t len = tr->msg.length - tr->msg.offset;
ssize_t val; ssize_t val;
int errval;
do
{
if (tr->sock.dstlen > 0)
val = sendto (tr->sock.fd, data, len, MSG_DONTWAIT | MSG_NOSIGNAL,
(struct sockaddr *)&tr->sock.dst, tr->sock.dstlen);
else
val = send (tr->sock.fd, data, len, MSG_DONTWAIT | MSG_NOSIGNAL);
if (val >= 0) val = stun_sendto (tr->sock.fd, data, len,
{ (struct sockaddr *)&tr->sock.dst, tr->sock.dstlen);
/* Message sent succesfully! */ if (val < 0)
tr->msg.offset += val; return errno;
assert (tr->msg.offset <= tr->msg.length);
if (tr->msg.offset == tr->msg.length)
tr->msg.offset = 0;
return 0;
}
errval = errno;
}
while (stun_err_dequeue (tr->sock.fd));
return errval; /* Message sent succesfully! */
tr->msg.offset += val;
assert (tr->msg.offset <= tr->msg.length);
if (tr->msg.offset == tr->msg.length)
tr->msg.offset = 0; // FIXME: temporary hack, may break TCP
return 0;
} }
...@@ -248,26 +257,27 @@ int stun_trans_tick (stun_trans_t *tr) ...@@ -248,26 +257,27 @@ int stun_trans_tick (stun_trans_t *tr)
} }
int stun_trans_preprocess (stun_trans_t *restrict tr, int stun_trans_preprocess (stun_trans_t *restrict tr, int *pcode,
const void *restrict buf, size_t len) const void *restrict buf, size_t len)
{ {
int code; assert (pcode != NULL);
if (stun_validate (buf, len) <= 0) if (stun_validate (buf, len) <= 0)
return EAGAIN; return EAGAIN;
DBG ("Received %u-bytes STUN message\n", DBG ("Received %u-bytes STUN message\n",
(unsigned)stun_validate (buf, len)); (unsigned)stun_validate (buf, len));
/* FIXME: some error messages cannot be authenticated!! */ /* NOTE: currently we ignore unauthenticated messages if the context
* is authenticated, for security reasons. */
if (!stun_match_messages (buf, tr->msg.buf, tr->key.value, tr->key.length, if (!stun_match_messages (buf, tr->msg.buf, tr->key.value, tr->key.length,
&code)) pcode))
return EAGAIN; return EAGAIN;
if (code >= 0) if (*pcode >= 0)
{ {
DBG (" STUN error message received (code: %d)\n", code); DBG (" STUN error message received (code: %d)\n", *pcode);
return ECONNREFUSED; // FIXME: better error value return ECONNREFUSED;
} }
if (stun_has_unknown (buf)) if (stun_has_unknown (buf))
......
...@@ -103,7 +103,7 @@ void stun_trans_deinit (stun_trans_t *restrict tr); ...@@ -103,7 +103,7 @@ void stun_trans_deinit (stun_trans_t *restrict tr);
int stun_trans_start (stun_trans_t *restrict tr); int stun_trans_start (stun_trans_t *restrict tr);
int stun_trans_tick (stun_trans_t *tr); int stun_trans_tick (stun_trans_t *tr);
int stun_trans_preprocess (stun_trans_t *restrict tr, int stun_trans_preprocess (stun_trans_t *restrict tr, int *code,
const void *restrict buf, size_t len); const void *restrict buf, size_t len);
/** /**
...@@ -122,6 +122,9 @@ unsigned stun_trans_timeout (const stun_trans_t *tr); ...@@ -122,6 +122,9 @@ unsigned stun_trans_timeout (const stun_trans_t *tr);
*/ */
int stun_trans_fd (const stun_trans_t *tr); int stun_trans_fd (const stun_trans_t *tr);
ssize_t stun_sendto (int fd, const uint8_t *buf, size_t len,
const struct sockaddr *dst, socklen_t dstlen);
# ifdef __cplusplus # ifdef __cplusplus
} }
# endif # endif
......
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