patch: add turnc_send() and turnc_recv()

This commit is contained in:
Alfred E. Heggestad 2011-05-25 08:12:48 +00:00
parent 7f973a8bc8
commit 3a209fa607
2 changed files with 155 additions and 1 deletions

View file

@ -22,6 +22,8 @@ int turnc_alloc(struct turnc **turncp, const struct stun_conf *conf, int proto,
void *sock, int layer, const struct sa *srv,
const char *username, const char *password,
uint32_t lifetime, turnc_h *th, void *arg);
int turnc_send(struct turnc *turnc, const struct sa *dst, struct mbuf *mb);
int turnc_recv(struct turnc *turnc, struct sa *src, struct mbuf *mb);
int turnc_add_perm(struct turnc *turnc, const struct sa *peer,
turnc_perm_h *ph, void *arg);
int turnc_add_chan(struct turnc *turnc, const struct sa *peer,

View file

@ -234,7 +234,7 @@ static int refresh_request(struct turnc *t, uint32_t lifetime, bool reset_ls,
}
static inline size_t stun_indlen(struct sa *sa)
static inline size_t stun_indlen(const struct sa *sa)
{
size_t len = STUN_HEADER_SIZE + STUN_ATTR_HEADER_SIZE * 2;
@ -460,6 +460,158 @@ int turnc_alloc(struct turnc **turncp, const struct stun_conf *conf, int proto,
}
int turnc_send(struct turnc *turnc, const struct sa *dst, struct mbuf *mb)
{
size_t pos, indlen;
struct chan *chan;
int err;
if (!turnc || !dst || !mb)
return EINVAL;
chan = turnc_chan_find_peer(turnc, dst);
if (chan) {
struct chan_hdr hdr;
if (mb->pos < CHAN_HDR_SIZE)
return EINVAL;
hdr.nr = turnc_chan_numb(chan);
hdr.len = mbuf_get_left(mb);
mb->pos -= CHAN_HDR_SIZE;
pos = mb->pos;
err = turnc_chan_hdr_encode(&hdr, mb);
if (err)
return err;
if (turnc->proto == IPPROTO_TCP) {
mb->pos = mb->end;
/* padding */
while (hdr.len++ & 0x03) {
err = mbuf_write_u8(mb, 0x00);
if (err)
return err;
}
}
mb->pos = pos;
}
else {
indlen = stun_indlen(dst);
if (mb->pos < indlen)
return EINVAL;
mb->pos -= indlen;
pos = mb->pos;
err = stun_msg_encode(mb, STUN_METHOD_SEND,
STUN_CLASS_INDICATION, sendind_tid,
NULL, NULL, 0, false, 0x00, 2,
STUN_ATTR_XOR_PEER_ADDR, dst,
STUN_ATTR_DATA, mb);
if (err)
return err;
mb->pos = pos;
}
switch (turnc->proto) {
case IPPROTO_UDP:
err = udp_send(turnc->sock, &turnc->srv, mb);
break;
case IPPROTO_TCP:
err = tcp_send(turnc->sock, mb);
break;
default:
err = EPROTONOSUPPORT;
break;
}
return err;
}
int turnc_recv(struct turnc *turnc, struct sa *src, struct mbuf *mb)
{
struct stun_attr *peer, *data;
struct stun_unknown_attr ua;
struct stun_msg *msg;
int err = 0;
if (!turnc || !src || !mb)
return EINVAL;
if (stun_msg_decode(&msg, mb, &ua)) {
struct chan_hdr hdr;
struct chan *chan;
if (turnc_chan_hdr_decode(&hdr, mb))
return EBADMSG;
if (mbuf_get_left(mb) < hdr.len)
return EBADMSG;
chan = turnc_chan_find_numb(turnc, hdr.nr);
if (!chan)
return EBADMSG;
*src = *turnc_chan_peer(chan);
return 0;
}
switch (stun_msg_class(msg)) {
case STUN_CLASS_INDICATION:
if (ua.typec > 0) {
err = ENOSYS;
break;
}
if (stun_msg_method(msg) != STUN_METHOD_DATA) {
err = ENOSYS;
break;
}
peer = stun_msg_attr(msg, STUN_ATTR_XOR_PEER_ADDR);
data = stun_msg_attr(msg, STUN_ATTR_DATA);
if (!peer || !data) {
err = EPROTO;
break;
}
*src = peer->v.xor_peer_addr;
mb->pos = data->v.data.pos;
mb->end = data->v.data.end;
break;
case STUN_CLASS_ERROR_RESP:
case STUN_CLASS_SUCCESS_RESP:
(void)stun_ctrans_recv(turnc->stun, msg, &ua);
mb->pos = mb->end;
break;
default:
err = ENOSYS;
break;
}
mem_deref(msg);
return err;
}
bool turnc_request_loops(struct loop_state *ls, uint16_t scode)
{
bool loop = false;