From bec19e0d3c8fd02ead56676fa540bba024e10113 Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Fri, 22 Aug 2008 17:46:33 +0000 Subject: Ticket #598: Update to draft-ietf-behave-rfc3489bis-18 and draft-ietf-behave-turn-09, and fix other things as well. Please see the ticket for more info git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@2234 74dad513-b988-da41-8d7b-12977e46ad98 --- pjnath/src/pjnath-test/server.c | 4 +- pjnath/src/pjnath-test/stun.c | 2 +- pjnath/src/pjnath/stun_msg.c | 87 ++++++++++++++++++++++++++++++++---- pjnath/src/pjnath/stun_msg_dump.c | 6 +-- pjnath/src/pjnath/stun_session.c | 4 +- pjnath/src/pjnath/stun_transaction.c | 41 ++++++++++++++++- pjnath/src/pjnath/turn_session.c | 75 ++++++++++++++++++++----------- pjnath/src/pjnath/turn_sock.c | 11 ++++- pjnath/src/pjturn-srv/allocation.c | 2 +- pjnath/src/pjturn-srv/listener_udp.c | 5 +-- pjnath/src/pjturn-srv/server.c | 45 +++++++++++++++++++ 11 files changed, 232 insertions(+), 50 deletions(-) (limited to 'pjnath/src') diff --git a/pjnath/src/pjnath-test/server.c b/pjnath/src/pjnath-test/server.c index 466b3a3d..360e17ce 100644 --- a/pjnath/src/pjnath-test/server.c +++ b/pjnath/src/pjnath-test/server.c @@ -309,8 +309,8 @@ static pj_stun_msg* create_success_response(test_server *test_srv, /* Add LIFETIME */ pj_stun_msg_add_uint_attr(pool, resp, PJ_STUN_ATTR_LIFETIME, lifetime); if (lifetime != 0) { - /* Add RELAY-ADDRESS */ - pj_stun_msg_add_sockaddr_attr(pool, resp, PJ_STUN_ATTR_RELAY_ADDR, PJ_TRUE, &alloc->alloc_addr, + /* Add RELAYED-ADDRESS */ + pj_stun_msg_add_sockaddr_attr(pool, resp, PJ_STUN_ATTR_RELAYED_ADDR, PJ_TRUE, &alloc->alloc_addr, pj_sockaddr_get_len(&alloc->alloc_addr)); /* Add XOR-MAPPED-ADDRESS */ pj_stun_msg_add_sockaddr_attr(pool, resp, PJ_STUN_ATTR_XOR_MAPPED_ADDR, PJ_TRUE, &alloc->client_addr, diff --git a/pjnath/src/pjnath-test/stun.c b/pjnath/src/pjnath-test/stun.c index 71775f6b..5d157053 100644 --- a/pjnath/src/pjnath-test/stun.c +++ b/pjnath/src/pjnath-test/stun.c @@ -694,7 +694,7 @@ static pj_stun_msg* create_msgint2(pj_pool_t *pool, test_vector *v) pj_stun_msg_create(pool, v->msg_type, PJ_STUN_MAGIC, (pj_uint8_t*)v->tsx_id, &msg); - pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_SERVER, + pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_SOFTWARE, pj_cstr(&s1, "test vector")); pj_sockaddr_in_init(&mapped_addr, pj_cstr(&s1, "127.0.0.1"), 32853); diff --git a/pjnath/src/pjnath/stun_msg.c b/pjnath/src/pjnath/stun_msg.c index 42df8c38..0d8c5c59 100644 --- a/pjnath/src/pjnath/stun_msg.c +++ b/pjnath/src/pjnath/stun_msg.c @@ -66,6 +66,7 @@ static struct { PJ_STUN_SC_ALLOCATION_MISMATCH, "Allocation Mismatch"}, { PJ_STUN_SC_STALE_NONCE, "Stale Nonce"}, { PJ_STUN_SC_TRANSITIONING, "Active Destination Already Set"}, + { PJ_STUN_SC_WRONG_CREDENTIALS, "Wrong Credentials"}, { PJ_STUN_SC_UNSUPP_TRANSPORT_PROTO, "Unsupported Transport Protocol"}, { PJ_STUN_SC_INVALID_IP_ADDR, "Invalid IP Address"}, { PJ_STUN_SC_INVALID_PORT, "Invalid Port"}, @@ -309,7 +310,7 @@ static struct attr_desc mandatory_attr_desc[] = }, { /* PJ_STUN_ATTR_RELAY_ADDRESS, */ - "RELAY-ADDRESS", + "RELAYED-ADDRESS", &decode_xored_sockaddr_attr, &encode_sockaddr_attr, &clone_sockaddr_attr @@ -420,11 +421,81 @@ static struct attr_desc mandatory_attr_desc[] = &clone_empty_attr }, { - /* PJ_STUN_ATTR_XOR_INTERNAL_ADDR, */ - "XOR-INTERNAL-ADDRESS", - &decode_xored_sockaddr_attr, - &encode_sockaddr_attr, - &clone_sockaddr_attr + /* ID 0x0026 is not assigned */ + NULL, + NULL, + NULL, + NULL + }, + { + /* ID 0x0027 is not assigned */ + NULL, + NULL, + NULL, + NULL + }, + { + /* ID 0x0028 is not assigned */ + NULL, + NULL, + NULL, + NULL + }, + { + /* ID 0x0029 is not assigned */ + NULL, + NULL, + NULL, + NULL + }, + { + /* ID 0x002a is not assigned */ + NULL, + NULL, + NULL, + NULL + }, + { + /* ID 0x002b is not assigned */ + NULL, + NULL, + NULL, + NULL + }, + { + /* ID 0x002c is not assigned */ + NULL, + NULL, + NULL, + NULL + }, + { + /* ID 0x002d is not assigned */ + NULL, + NULL, + NULL, + NULL + }, + { + /* ID 0x002e is not assigned */ + NULL, + NULL, + NULL, + NULL + }, + { + /* ID 0x002f is not assigned */ + NULL, + NULL, + NULL, + NULL + }, + { + /* PJ_STUN_ATTR_ICMP, */ + "ICMP", + &decode_uint_attr, + &encode_uint_attr, + &clone_uint_attr }, /* Sentinel */ @@ -447,8 +518,8 @@ static struct attr_desc extended_attr_desc[] = NULL }, { - /* PJ_STUN_ATTR_SERVER, */ - "SERVER", + /* PJ_STUN_ATTR_SOFTWARE, */ + "SOFTWARE", &decode_string_attr, &encode_string_attr, &clone_string_attr diff --git a/pjnath/src/pjnath/stun_msg_dump.c b/pjnath/src/pjnath/stun_msg_dump.c index a5556acc..8b6310a8 100644 --- a/pjnath/src/pjnath/stun_msg_dump.c +++ b/pjnath/src/pjnath/stun_msg_dump.c @@ -72,10 +72,9 @@ static int print_attr(char *buffer, unsigned length, case PJ_STUN_ATTR_CHANGED_ADDR: case PJ_STUN_ATTR_REFLECTED_FROM: case PJ_STUN_ATTR_PEER_ADDR: - case PJ_STUN_ATTR_RELAY_ADDR: + case PJ_STUN_ATTR_RELAYED_ADDR: case PJ_STUN_ATTR_XOR_MAPPED_ADDR: case PJ_STUN_ATTR_XOR_REFLECTED_FROM: - case PJ_STUN_ATTR_XOR_INTERNAL_ADDR: case PJ_STUN_ATTR_ALTERNATE_SERVER: { const pj_stun_sockaddr_attr *attr; @@ -122,6 +121,7 @@ static int print_attr(char *buffer, unsigned length, case PJ_STUN_ATTR_PRIORITY: case PJ_STUN_ATTR_FINGERPRINT: case PJ_STUN_ATTR_REFRESH_INTERVAL: + case PJ_STUN_ATTR_ICMP: { const pj_stun_uint_attr *attr; @@ -138,7 +138,7 @@ static int print_attr(char *buffer, unsigned length, case PJ_STUN_ATTR_PASSWORD: case PJ_STUN_ATTR_REALM: case PJ_STUN_ATTR_NONCE: - case PJ_STUN_ATTR_SERVER: + case PJ_STUN_ATTR_SOFTWARE: { const pj_stun_string_attr *attr; diff --git a/pjnath/src/pjnath/stun_session.c b/pjnath/src/pjnath/stun_session.c index bec02ca3..35c982f4 100644 --- a/pjnath/src/pjnath/stun_session.c +++ b/pjnath/src/pjnath/stun_session.c @@ -216,9 +216,9 @@ static pj_status_t apply_msg_options(pj_stun_session *sess, pj_status_t status = 0; pj_str_t realm, username, nonce, auth_key; - /* The server SHOULD include a SERVER attribute in all responses */ + /* The server SHOULD include a SOFTWARE attribute in all responses */ if (sess->srv_name.slen && PJ_STUN_IS_RESPONSE(msg->hdr.type)) { - pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_SERVER, + pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_SOFTWARE, &sess->srv_name); } diff --git a/pjnath/src/pjnath/stun_transaction.c b/pjnath/src/pjnath/stun_transaction.c index 1242dfe7..9942d83b 100644 --- a/pjnath/src/pjnath/stun_transaction.c +++ b/pjnath/src/pjnath/stun_transaction.c @@ -251,6 +251,8 @@ PJ_DEF(pj_status_t) pj_stun_client_tsx_send_msg(pj_stun_client_tsx *tsx, void *pkt, unsigned pkt_len) { + pj_status_t status; + PJ_ASSERT_RETURN(tsx && pkt && pkt_len, PJ_EINVAL); PJ_ASSERT_RETURN(tsx->retransmit_timer.id == 0, PJ_EBUSY); @@ -261,8 +263,45 @@ PJ_DEF(pj_status_t) pj_stun_client_tsx_send_msg(pj_stun_client_tsx *tsx, /* Update STUN retransmit flag */ tsx->require_retransmit = retransmit; + /* For TCP, schedule timeout timer after PJ_STUN_TIMEOUT_VALUE. + * Since we don't have timeout timer, simulate this by using + * retransmit timer. + */ + if (!retransmit) { + unsigned timeout; + + pj_assert(tsx->retransmit_timer.id == 0); + tsx->transmit_count = PJ_STUN_MAX_TRANSMIT_COUNT; + + timeout = tsx->rto_msec * 16; + tsx->retransmit_time.sec = timeout / 1000; + tsx->retransmit_time.msec = timeout % 1000; + + /* Schedule timer first because when send_msg() failed we can + * cancel it (as opposed to when schedule_timer() failed we cannot + * cancel transmission). + */; + status = pj_timer_heap_schedule(tsx->timer_heap, + &tsx->retransmit_timer, + &tsx->retransmit_time); + if (status != PJ_SUCCESS) { + tsx->retransmit_timer.id = 0; + return status; + } + } + /* Send the message */ - return tsx_transmit_msg(tsx); + status = tsx_transmit_msg(tsx); + if (status != PJ_SUCCESS) { + if (tsx->retransmit_timer.id != 0) { + pj_timer_heap_cancel(tsx->timer_heap, + &tsx->retransmit_timer); + tsx->retransmit_timer.id = 0; + } + return status; + } + + return PJ_SUCCESS; } diff --git a/pjnath/src/pjnath/turn_session.c b/pjnath/src/pjnath/turn_session.c index 8f50d820..ad3d99ab 100644 --- a/pjnath/src/pjnath/turn_session.c +++ b/pjnath/src/pjnath/turn_session.c @@ -914,7 +914,8 @@ on_return: */ PJ_DEF(pj_status_t) pj_turn_session_on_rx_pkt(pj_turn_session *sess, void *pkt, - unsigned pkt_len) + unsigned pkt_len, + unsigned *parsed_len) { pj_bool_t is_stun; pj_status_t status; @@ -940,47 +941,58 @@ PJ_DEF(pj_status_t) pj_turn_session_on_rx_pkt(pj_turn_session *sess, if (is_datagram) options |= PJ_STUN_IS_DATAGRAM; status=pj_stun_session_on_rx_pkt(sess->stun, pkt, pkt_len, - options, NULL, NULL, + options, NULL, parsed_len, sess->srv_addr, pj_sockaddr_get_len(sess->srv_addr)); - } else if (sess->cb.on_rx_data) { - - /* This must be ChannelData. Only makes sense when on_rx_data() is - * implemented by application. - */ + } else { + /* This must be ChannelData. */ pj_turn_channel_data cd; struct peer *peer; - PJ_ASSERT_RETURN(pkt_len >= 4, PJ_ETOOSMALL); + if (pkt_len < 4) { + if (parsed_len) *parsed_len = 0; + return PJ_ETOOSMALL; + } - /* Lookup peer */ + /* Decode ChannelData packet */ pj_memcpy(&cd, pkt, sizeof(pj_turn_channel_data)); cd.ch_number = pj_ntohs(cd.ch_number); cd.length = pj_ntohs(cd.length); - peer = lookup_peer_by_chnum(sess, cd.ch_number); - if (!peer || !peer->bound) { - status = PJ_ENOTFOUND; - goto on_return; - } - /* Check that size is correct, for UDP */ + /* Check that size is sane */ if (pkt_len < cd.length+sizeof(cd)) { + if (parsed_len) { + if (is_datagram) { + /* Discard the datagram */ + *parsed_len = pkt_len; + } else { + /* Insufficient fragment */ + *parsed_len = 0; + } + } status = PJ_ETOOSMALL; goto on_return; + } else { + if (parsed_len) { + *parsed_len = cd.length + sizeof(cd); + } + } + + /* Lookup peer */ + peer = lookup_peer_by_chnum(sess, cd.ch_number); + if (!peer || !peer->bound) { + status = PJ_ENOTFOUND; + goto on_return; } /* Notify application */ - (*sess->cb.on_rx_data)(sess, ((pj_uint8_t*)pkt)+sizeof(cd), - cd.length, &peer->addr, - pj_sockaddr_get_len(&peer->addr)); - - status = PJ_SUCCESS; + if (sess->cb.on_rx_data) { + (*sess->cb.on_rx_data)(sess, ((pj_uint8_t*)pkt)+sizeof(cd), + cd.length, &peer->addr, + pj_sockaddr_get_len(&peer->addr)); + } - } else { - /* This is ChannelData and application doesn't implement - * on_rx_data() callback. Just ignore the packet. - */ status = PJ_SUCCESS; } @@ -1077,7 +1089,7 @@ static void on_allocate_success(pj_turn_session *sess, const pj_stun_msg *msg) { const pj_stun_lifetime_attr *lf_attr; - const pj_stun_relay_addr_attr *raddr_attr; + const pj_stun_relayed_addr_attr *raddr_attr; const pj_stun_sockaddr_attr *mapped_attr; pj_str_t s; pj_time_val timeout; @@ -1125,8 +1137,8 @@ static void on_allocate_success(pj_turn_session *sess, /* Check that relayed transport address contains correct * address family. */ - raddr_attr = (const pj_stun_relay_addr_attr*) - pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_RELAY_ADDR, 0); + raddr_attr = (const pj_stun_relayed_addr_attr*) + pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_RELAYED_ADDR, 0); if (raddr_attr == NULL && method==PJ_STUN_ALLOCATE_METHOD) { on_session_fail(sess, method, PJNATH_EINSTUNMSG, pj_cstr(&s, "Error: Received ALLOCATE without " @@ -1341,6 +1353,7 @@ static pj_status_t stun_on_rx_indication(pj_stun_session *stun, { pj_turn_session *sess; pj_stun_peer_addr_attr *peer_attr; + pj_stun_icmp_attr *icmp; pj_stun_data_attr *data_attr; PJ_UNUSED_ARG(token); @@ -1358,6 +1371,14 @@ static pj_status_t stun_on_rx_indication(pj_stun_session *stun, return PJ_EINVALIDOP; } + /* Check if there is ICMP attribute in the message */ + icmp = (pj_stun_icmp_attr*) + pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_ICMP, 0); + if (icmp != NULL) { + /* This is a forwarded ICMP packet. Ignore it for now */ + return PJ_SUCCESS; + } + /* Get PEER-ADDRESS attribute */ peer_attr = (pj_stun_peer_addr_attr*) pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_PEER_ADDR, 0); diff --git a/pjnath/src/pjnath/turn_sock.c b/pjnath/src/pjnath/turn_sock.c index 94ff80ab..509efe22 100644 --- a/pjnath/src/pjnath/turn_sock.c +++ b/pjnath/src/pjnath/turn_sock.c @@ -463,6 +463,7 @@ static pj_bool_t on_data_read(pj_activesock_t *asock, pj_size_t *remainder) { pj_turn_sock *turn_sock; + unsigned parsed_len; pj_bool_t ret = PJ_TRUE; turn_sock = (pj_turn_sock*) pj_activesock_get_user_data(asock); @@ -470,8 +471,14 @@ static pj_bool_t on_data_read(pj_activesock_t *asock, if (status == PJ_SUCCESS && turn_sock->sess) { /* Report incoming packet to TURN session */ - PJ_TODO(REPORT_PARSED_LEN); - pj_turn_session_on_rx_pkt(turn_sock->sess, data, size); + 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; + } } else if (status != PJ_SUCCESS && turn_sock->conn_type != PJ_TURN_TP_UDP) { diff --git a/pjnath/src/pjturn-srv/allocation.c b/pjnath/src/pjturn-srv/allocation.c index b2215e0d..3e4b77f6 100644 --- a/pjnath/src/pjturn-srv/allocation.c +++ b/pjnath/src/pjturn-srv/allocation.c @@ -212,7 +212,7 @@ static pj_status_t send_allocate_response(pj_turn_allocation *alloc, /* Add RELAYED-ADDRESS attribute */ pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg, - PJ_STUN_ATTR_RELAY_ADDR, PJ_TRUE, + PJ_STUN_ATTR_RELAYED_ADDR, PJ_TRUE, &alloc->relay.hkey.addr, pj_sockaddr_get_len(&alloc->relay.hkey.addr)); diff --git a/pjnath/src/pjturn-srv/listener_udp.c b/pjnath/src/pjturn-srv/listener_udp.c index 2c0eccdc..9d600589 100644 --- a/pjnath/src/pjturn-srv/listener_udp.c +++ b/pjnath/src/pjturn-srv/listener_udp.c @@ -125,10 +125,9 @@ PJ_DEF(pj_status_t) pj_turn_listener_create_udp( pj_turn_srv *srv, /* Create each read_op and kick off read operation */ for (i=0; icore.pf, "rop%p", - sizeof(struct read_op)+1000, - 1000, NULL); + 1000, 1000, NULL); - udp->read_op[i] = PJ_POOL_ZALLOC_T(rpool, struct read_op); + udp->read_op[i] = PJ_POOL_ZALLOC_T(pool, struct read_op); udp->read_op[i]->pkt.pool = rpool; on_read_complete(udp->key, &udp->read_op[i]->op_key, 0); diff --git a/pjnath/src/pjturn-srv/server.c b/pjnath/src/pjturn-srv/server.c index 1089ec91..c277e11e 100644 --- a/pjnath/src/pjturn-srv/server.c +++ b/pjnath/src/pjturn-srv/server.c @@ -551,6 +551,43 @@ static pj_status_t on_rx_stun_request(pj_stun_session *sess, return PJ_SUCCESS; } +/* Handle STUN Binding request */ +static void handle_binding_request(pj_turn_pkt *pkt, + unsigned options) +{ + pj_stun_msg *request, *response; + pj_uint8_t pdu[200]; + pj_size_t len; + pj_status_t status; + + /* Decode request */ + status = pj_stun_msg_decode(pkt->pool, pkt->pkt, pkt->len, options, + &request, NULL, NULL); + if (status != PJ_SUCCESS) + return; + + /* Create response */ + status = pj_stun_msg_create_response(pkt->pool, request, 0, NULL, + &response); + if (status != PJ_SUCCESS) + return; + + /* Add XOR-MAPPED-ADDRESS */ + pj_stun_msg_add_sockaddr_attr(pkt->pool, response, + PJ_STUN_ATTR_XOR_MAPPED_ADDR, + PJ_TRUE, + &pkt->src.clt_addr, + pkt->src_addr_len); + + /* Encode */ + status = pj_stun_msg_encode(response, pdu, sizeof(pdu), 0, NULL, &len); + if (status != PJ_SUCCESS) + return; + + /* Send response */ + pkt->transport->sendto(pkt->transport, pdu, len, 0, + &pkt->src.clt_addr, pkt->src_addr_len); +} /* * This callback is called by UDP listener on incoming packet. This is @@ -615,6 +652,14 @@ PJ_DEF(void) pj_turn_srv_on_rx_pkt(pj_turn_srv *srv, return; } + /* Special handling for Binding Request. We won't give it to the + * STUN session since this request is not authenticated. + */ + if (pkt->pkt[1] == 1) { + handle_binding_request(pkt, options); + return; + } + /* Hand over processing to STUN session. This will trigger * on_rx_stun_request() callback to be called if the STUN * message is a request. -- cgit v1.2.3