summaryrefslogtreecommitdiff
path: root/pjnath/src/pjnath/turn_sock.c
diff options
context:
space:
mode:
Diffstat (limited to 'pjnath/src/pjnath/turn_sock.c')
-rw-r--r--pjnath/src/pjnath/turn_sock.c105
1 files changed, 86 insertions, 19 deletions
diff --git a/pjnath/src/pjnath/turn_sock.c b/pjnath/src/pjnath/turn_sock.c
index 287b0299..e2823ff3 100644
--- a/pjnath/src/pjnath/turn_sock.c
+++ b/pjnath/src/pjnath/turn_sock.c
@@ -273,14 +273,7 @@ static void timer_cb(pj_timer_heap_t *th, pj_timer_entry *e)
static void show_err(pj_turn_sock *turn_sock, const char *title,
pj_status_t status)
{
- char errmsg[PJ_ERR_MSG_SIZE];
-
- if (status != PJ_SUCCESS) {
- pj_strerror(status, errmsg, sizeof(errmsg));
- PJ_LOG(4,(turn_sock->obj_name, "%s: %s", title, errmsg));
- } else {
- PJ_LOG(4,(turn_sock->obj_name, "%s", title, errmsg));
- }
+ PJ_PERROR(4,(turn_sock->obj_name, status, title));
}
/* On error, terminate session */
@@ -288,8 +281,9 @@ static void sess_fail(pj_turn_sock *turn_sock, const char *title,
pj_status_t status)
{
show_err(turn_sock, title, status);
- if (turn_sock->sess)
- pj_turn_session_destroy(turn_sock->sess);
+ if (turn_sock->sess) {
+ pj_turn_session_destroy(turn_sock->sess, status);
+ }
}
/*
@@ -494,6 +488,49 @@ static pj_bool_t on_connect_complete(pj_activesock_t *asock,
return PJ_TRUE;
}
+static pj_uint16_t GETVAL16H(const pj_uint8_t *buf, unsigned pos)
+{
+ return (pj_uint16_t) ((buf[pos + 0] << 8) | \
+ (buf[pos + 1] << 0));
+}
+
+/* Quick check to determine if there is enough packet to process in the
+ * incoming buffer. Return the packet length, or zero if there's no packet.
+ */
+static unsigned has_packet(pj_turn_sock *turn_sock, const void *buf, pj_size_t bufsize)
+{
+ pj_bool_t is_stun;
+
+ if (turn_sock->conn_type == PJ_TURN_TP_UDP)
+ return bufsize;
+
+ /* Quickly check if this is STUN message, by checking the first two bits and
+ * size field which must be multiple of 4 bytes
+ */
+ is_stun = ((((pj_uint8_t*)buf)[0] & 0xC0) == 0) &&
+ ((GETVAL16H((const pj_uint8_t*)buf, 2) & 0x03)==0);
+
+ if (is_stun) {
+ pj_size_t msg_len = GETVAL16H((const pj_uint8_t*)buf, 2);
+ return (msg_len+20 <= bufsize) ? msg_len+20 : 0;
+ } else {
+ /* This must be ChannelData. */
+ pj_turn_channel_data cd;
+
+ if (bufsize < 4)
+ return 0;
+
+ /* Decode ChannelData packet */
+ pj_memcpy(&cd, buf, sizeof(pj_turn_channel_data));
+ cd.length = pj_ntohs(cd.length);
+
+ if (bufsize >= cd.length+sizeof(cd))
+ return (cd.length+sizeof(cd)+3) & (~3);
+ else
+ return 0;
+ }
+}
+
/*
* Notification from ioqueue when incoming UDP packet is received.
*/
@@ -504,21 +541,51 @@ static pj_bool_t on_data_read(pj_activesock_t *asock,
pj_size_t *remainder)
{
pj_turn_sock *turn_sock;
- pj_size_t parsed_len;
pj_bool_t ret = PJ_TRUE;
turn_sock = (pj_turn_sock*) pj_activesock_get_user_data(asock);
pj_lock_acquire(turn_sock->lock);
if (status == PJ_SUCCESS && turn_sock->sess) {
- /* Report incoming packet to TURN session */
- parsed_len = (unsigned)size;
- pj_turn_session_on_rx_pkt(turn_sock->sess, data, size, &parsed_len);
- if (parsed_len < (unsigned)size) {
- *remainder = size - parsed_len;
- pj_memmove(data, ((char*)data)+parsed_len, *remainder);
- } else {
- *remainder = 0;
+ /* Report incoming packet to TURN session, repeat while we have
+ * "packet" in the buffer (required for stream-oriented transports)
+ */
+ unsigned pkt_len;
+
+ //PJ_LOG(5,(turn_sock->pool->obj_name,
+ // "Incoming data, %lu bytes total buffer", size));
+
+ while ((pkt_len=has_packet(turn_sock, data, size)) != 0) {
+ pj_size_t parsed_len;
+ //const pj_uint8_t *pkt = (const pj_uint8_t*)data;
+
+ //PJ_LOG(5,(turn_sock->pool->obj_name,
+ // "Packet start: %02X %02X %02X %02X",
+ // pkt[0], pkt[1], pkt[2], pkt[3]));
+
+ //PJ_LOG(5,(turn_sock->pool->obj_name,
+ // "Processing %lu bytes packet of %lu bytes total buffer",
+ // pkt_len, size));
+
+ parsed_len = (unsigned)size;
+ pj_turn_session_on_rx_pkt(turn_sock->sess, data, size, &parsed_len);
+
+ /* parsed_len may be zero if we have parsing error, so use our
+ * previous calculation to exhaust the bad packet.
+ */
+ if (parsed_len == 0)
+ parsed_len = pkt_len;
+
+ if (parsed_len < (unsigned)size) {
+ *remainder = size - parsed_len;
+ pj_memmove(data, ((char*)data)+parsed_len, *remainder);
+ } else {
+ *remainder = 0;
+ }
+ size = *remainder;
+
+ //PJ_LOG(5,(turn_sock->pool->obj_name,
+ // "Buffer size now %lu bytes", size));
}
} else if (status != PJ_SUCCESS &&
turn_sock->conn_type != PJ_TURN_TP_UDP)