Changeset 1104 for pjproject/trunk/pjnath/src/pjnath/ice_stream_transport.c
- Timestamp:
- Mar 25, 2007 6:44:51 PM (17 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjnath/src/pjnath/ice_stream_transport.c
r1101 r1104 21 21 #include <pj/addr_resolv.h> 22 22 #include <pj/assert.h> 23 #include <pj/ip_helper.h> 23 24 #include <pj/log.h> 24 25 #include <pj/pool.h> … … 29 30 /* ICE callbacks */ 30 31 static void on_ice_complete(pj_ice *ice, pj_status_t status); 31 static pj_status_t on_tx_pkt(pj_ice *ice, 32 unsigned comp_id, unsigned cand_id, 33 const void *pkt, pj_size_t size, 34 const pj_sockaddr_t *dst_addr, 35 unsigned dst_addr_len); 36 static void on_rx_data(pj_ice *ice, 32 static pj_status_t ice_tx_pkt(pj_ice *ice, 37 33 unsigned comp_id, unsigned cand_id, 34 const void *pkt, pj_size_t size, 35 const pj_sockaddr_t *dst_addr, 36 unsigned dst_addr_len); 37 static void ice_rx_data(pj_ice *ice, 38 unsigned comp_id, 38 39 void *pkt, pj_size_t size, 39 40 const pj_sockaddr_t *src_addr, … … 45 46 pj_ssize_t bytes_read); 46 47 47 static void destroy_ ice_interface(pj_ice_st_interface *is);48 static void destroy_component(pj_ice_st_comp *comp); 48 49 static void destroy_ice_st(pj_ice_st *ice_st, pj_status_t reason); 49 50 … … 86 87 87 88 /* 88 * Create new interface (i.e. socket)89 */90 static pj_status_t create_ice_interface(pj_ice_st *ice_st,91 pj_ice_cand_type type,92 unsigned comp_id,93 pj_uint16_t local_pref,94 const pj_sockaddr_in *addr,95 pj_ice_st_interface **p_is)96 {97 pj_ioqueue_callback ioqueue_cb;98 pj_ice_st_interface *is;99 char foundation[32];100 int addr_len;101 pj_status_t status;102 103 is = PJ_POOL_ZALLOC_T(ice_st->pool, pj_ice_st_interface);104 is->type = type;105 is->comp_id = comp_id;106 is->cand_id = -1;107 is->sock = PJ_INVALID_SOCKET;108 is->ice_st = ice_st;109 is->local_pref = local_pref;110 111 status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &is->sock);112 if (status != PJ_SUCCESS)113 return status;114 115 /* Bind and get the local IP address */116 if (addr)117 pj_memcpy(&is->base_addr, addr, sizeof(pj_sockaddr_in));118 else119 pj_sockaddr_in_init(&is->base_addr.ipv4, NULL, 0);120 121 status = pj_sock_bind(is->sock, &is->base_addr, sizeof(pj_sockaddr_in));122 if (status != PJ_SUCCESS)123 goto on_error;124 125 addr_len = sizeof(is->base_addr);126 status = pj_sock_getsockname(is->sock, &is->base_addr, &addr_len);127 if (status != PJ_SUCCESS)128 goto on_error;129 130 if (is->base_addr.ipv4.sin_addr.s_addr == 0) {131 status = pj_gethostip(&is->base_addr.ipv4.sin_addr);132 if (status != PJ_SUCCESS)133 goto on_error;134 }135 136 /* Assign foundation */137 pj_ansi_snprintf(foundation, sizeof(foundation), "%c%x",138 get_type_prefix(type),139 (int)pj_ntohl(is->base_addr.ipv4.sin_addr.s_addr));140 pj_strdup2(ice_st->pool, &is->foundation, foundation);141 142 143 /* Register to ioqueue */144 pj_bzero(&ioqueue_cb, sizeof(ioqueue_cb));145 ioqueue_cb.on_read_complete = &on_read_complete;146 status = pj_ioqueue_register_sock(ice_st->pool, ice_st->stun_cfg.ioqueue,147 is->sock, is, &ioqueue_cb, &is->key);148 if (status != PJ_SUCCESS)149 goto on_error;150 151 pj_ioqueue_op_key_init(&is->read_op, sizeof(is->read_op));152 pj_ioqueue_op_key_init(&is->write_op, sizeof(is->write_op));153 154 /* Kick start reading the socket */155 on_read_complete(is->key, &is->read_op, 0);156 157 /* Done */158 *p_is = is;159 return PJ_SUCCESS;160 161 on_error:162 destroy_ice_interface(is);163 return status;164 }165 166 /*167 * This is callback called by ioqueue on incoming packet168 */169 static void on_read_complete(pj_ioqueue_key_t *key,170 pj_ioqueue_op_key_t *op_key,171 pj_ssize_t bytes_read)172 {173 pj_ice_st_interface *is = (pj_ice_st_interface*)174 pj_ioqueue_get_user_data(key);175 pj_ice_st *ice_st = is->ice_st;176 pj_ssize_t pkt_size;177 pj_status_t status;178 179 if (bytes_read > 0) {180 181 /* If we have an active ICE session, hand over all incoming182 * packets to the ICE session. Otherwise just drop the packet.183 */184 if (ice_st->ice) {185 status = pj_ice_on_rx_pkt(ice_st->ice,186 is->comp_id, is->cand_id,187 is->pkt, bytes_read,188 &is->src_addr, is->src_addr_len);189 } else if (is->stun_sess) {190 status = pj_stun_msg_check(is->pkt, bytes_read, PJ_STUN_IS_DATAGRAM);191 if (status == PJ_SUCCESS) {192 status = pj_stun_session_on_rx_pkt(is->stun_sess, is->pkt,193 bytes_read,194 PJ_STUN_IS_DATAGRAM, NULL,195 &is->src_addr,196 is->src_addr_len);197 } else {198 (*ice_st->cb.on_rx_data)(ice_st, is->comp_id, is->cand_id,199 is->pkt, bytes_read,200 &is->src_addr, is->src_addr_len);201 202 }203 } else {204 (*ice_st->cb.on_rx_data)(ice_st, is->comp_id, is->cand_id,205 is->pkt, bytes_read,206 &is->src_addr, is->src_addr_len);207 }208 209 } else if (bytes_read < 0) {210 ice_st_perror(is->ice_st, "ioqueue read callback error", -bytes_read);211 }212 213 /* Read next packet */214 pkt_size = sizeof(is->pkt);215 is->src_addr_len = sizeof(is->src_addr);216 status = pj_ioqueue_recvfrom(key, op_key, is->pkt, &pkt_size,217 PJ_IOQUEUE_ALWAYS_ASYNC,218 &is->src_addr, &is->src_addr_len);219 if (status != PJ_SUCCESS && status != PJ_EPENDING) {220 ice_st_perror(is->ice_st, "ioqueue recvfrom() error", status);221 }222 }223 224 /*225 * Destroy an interface226 */227 static void destroy_ice_interface(pj_ice_st_interface *is)228 {229 if (is->stun_sess) {230 pj_stun_session_destroy(is->stun_sess);231 is->stun_sess = NULL;232 }233 234 if (is->key) {235 pj_ioqueue_unregister(is->key);236 is->key = NULL;237 is->sock = PJ_INVALID_SOCKET;238 } else if (is->sock != PJ_INVALID_SOCKET && is->sock != 0) {239 pj_sock_close(is->sock);240 is->sock = PJ_INVALID_SOCKET;241 }242 }243 244 /*245 89 * Create ICE stream transport 246 90 */ 247 91 PJ_DECL(pj_status_t) pj_ice_st_create(pj_stun_config *stun_cfg, 248 92 const char *name, 93 unsigned comp_cnt, 249 94 void *user_data, 250 95 const pj_ice_st_cb *cb, … … 254 99 pj_ice_st *ice_st; 255 100 256 PJ_ASSERT_RETURN(stun_cfg && c b && p_ice_st, PJ_EINVAL);101 PJ_ASSERT_RETURN(stun_cfg && comp_cnt && cb && p_ice_st, PJ_EINVAL); 257 102 PJ_ASSERT_RETURN(stun_cfg->ioqueue && stun_cfg->timer_heap, PJ_EINVAL); 258 103 … … 266 111 ice_st->user_data = user_data; 267 112 113 ice_st->comp_cnt = comp_cnt; 114 ice_st->comp = (pj_ice_st_comp**) pj_pool_calloc(pool, comp_cnt, 115 sizeof(void*)); 116 268 117 pj_memcpy(&ice_st->cb, cb, sizeof(*cb)); 269 118 pj_memcpy(&ice_st->stun_cfg, stun_cfg, sizeof(*stun_cfg)); 270 119 120 271 121 PJ_LOG(4,(ice_st->obj_name, "ICE stream transport created")); 272 122 … … 275 125 } 276 126 127 /* Destroy ICE */ 277 128 static void destroy_ice_st(pj_ice_st *ice_st, pj_status_t reason) 278 129 { … … 291 142 } 292 143 293 /* Destroy all interfaces */ 294 for (i=0; i<ice_st->itf_cnt; ++i) { 295 destroy_ice_interface(ice_st->itfs[i]); 296 ice_st->itfs[i] = NULL; 297 } 298 ice_st->itf_cnt = 0; 144 /* Destroy all components */ 145 for (i=0; i<ice_st->comp_cnt; ++i) { 146 if (ice_st->comp[i]) { 147 destroy_component(ice_st->comp[i]); 148 ice_st->comp[i] = NULL; 149 } 150 } 151 ice_st->comp_cnt = 0; 299 152 300 153 /* Done */ … … 318 171 * Resolve STUN server 319 172 */ 320 PJ_DEF(pj_status_t) pj_ice_st_set_stun( pj_ice_st *ice_st, 321 pj_dns_resolver *resolver, 322 pj_bool_t enable_relay, 323 const pj_str_t *domain) 173 PJ_DEF(pj_status_t) pj_ice_st_set_stun_domain(pj_ice_st *ice_st, 174 pj_dns_resolver *resolver, 175 const pj_str_t *domain) 324 176 { 325 177 /* Yeah, TODO */ 326 178 PJ_UNUSED_ARG(ice_st); 327 179 PJ_UNUSED_ARG(resolver); 328 PJ_UNUSED_ARG(enable_relay);329 180 PJ_UNUSED_ARG(domain); 330 181 return -1; … … 334 185 * Set STUN server address. 335 186 */ 336 PJ_DEF(pj_status_t) pj_ice_st_set_stun_addr( pj_ice_st *ice_st, 337 pj_bool_t enable_relay, 338 const pj_sockaddr_in *srv_addr) 339 { 340 341 PJ_ASSERT_RETURN(ice_st && srv_addr, PJ_EINVAL); 342 343 ice_st->relay_enabled = enable_relay; 344 pj_strdup2(ice_st->pool, &ice_st->stun_domain, 345 pj_inet_ntoa(srv_addr->sin_addr)); 346 pj_memcpy(&ice_st->stun_srv, srv_addr, sizeof(pj_sockaddr_in)); 187 PJ_DEF(pj_status_t) pj_ice_st_set_stun_srv( pj_ice_st *ice_st, 188 const pj_sockaddr_in *stun_srv, 189 const pj_sockaddr_in *turn_srv) 190 { 191 PJ_ASSERT_RETURN(ice_st, PJ_EINVAL); 192 /* Must not have pending resolver job */ 193 PJ_ASSERT_RETURN(ice_st->has_resolver_job==PJ_FALSE, PJ_EINVALIDOP); 194 195 if (stun_srv) { 196 pj_memcpy(&ice_st->stun_srv, stun_srv, sizeof(pj_sockaddr_in)); 197 } else { 198 pj_bzero(&ice_st->stun_srv, sizeof(pj_sockaddr_in)); 199 } 200 201 if (turn_srv) { 202 pj_memcpy(&ice_st->turn_srv, turn_srv, sizeof(pj_sockaddr_in)); 203 } else { 204 pj_bzero(&ice_st->turn_srv, sizeof(pj_sockaddr_in)); 205 } 347 206 348 207 return PJ_SUCCESS; 349 208 } 350 209 351 /* 352 * Add new component. 353 */ 354 PJ_DEF(pj_status_t) pj_ice_st_add_comp(pj_ice_st *ice_st, 355 unsigned comp_id) 356 { 357 /* Verify arguments */ 358 PJ_ASSERT_RETURN(ice_st && comp_id, PJ_EINVAL); 359 360 /* Can only add component when we don't have active ICE session */ 361 PJ_ASSERT_RETURN(ice_st->ice == NULL, PJ_EBUSY); 362 363 /* Check that we don't have too many components */ 364 PJ_ASSERT_RETURN(ice_st->comp_cnt < PJ_ICE_MAX_COMP, PJ_ETOOMANY); 365 366 /* Component ID must be valid */ 367 PJ_ASSERT_RETURN(comp_id <= PJ_ICE_MAX_COMP, PJNATH_EICEINCOMPID); 368 369 /* First component ID must be 1, second must be 2, etc., and 370 * they must be registered in order. 371 */ 372 PJ_ASSERT_RETURN(ice_st->comps[comp_id-1] == ice_st->comp_cnt, 373 PJNATH_EICEINCOMPID); 374 375 /* All in order, add the component. */ 376 ice_st->comps[ice_st->comp_cnt++] = comp_id; 377 378 return PJ_SUCCESS; 379 } 380 381 /* Add interface */ 382 static void add_interface(pj_ice_st *ice_st, pj_ice_st_interface *is, 383 unsigned *p_itf_id) 384 { 385 unsigned itf_id; 386 387 itf_id = ice_st->itf_cnt++; 388 ice_st->itfs[itf_id] = is; 389 390 if (p_itf_id) 391 *p_itf_id = itf_id; 392 } 393 394 /* 395 * Add new host interface. 396 */ 397 PJ_DEF(pj_status_t) pj_ice_st_add_host_interface(pj_ice_st *ice_st, 398 unsigned comp_id, 399 pj_uint16_t local_pref, 400 const pj_sockaddr_in *addr, 401 unsigned *p_itf_id) 402 { 403 pj_ice_st_interface *is; 210 211 /* Calculate foundation */ 212 static pj_str_t calc_foundation(pj_pool_t *pool, 213 pj_ice_cand_type type, 214 const pj_in_addr *base_addr) 215 { 216 char foundation[32]; 217 pj_str_t result; 218 219 pj_ansi_snprintf(foundation, sizeof(foundation), "%c%x", 220 get_type_prefix(type), 221 (int)pj_ntohl(base_addr->s_addr)); 222 pj_strdup2(pool, &result, foundation); 223 224 return result; 225 } 226 227 /* Create new component (i.e. socket) */ 228 static pj_status_t create_component(pj_ice_st *ice_st, 229 unsigned comp_id, 230 pj_uint32_t options, 231 const pj_sockaddr_in *addr, 232 pj_ice_st_comp **p_comp) 233 { 234 enum { MAX_RETRY=100, PORT_INC=2 }; 235 pj_ioqueue_callback ioqueue_cb; 236 pj_ice_st_comp *comp; 237 int retry, addr_len; 404 238 pj_status_t status; 405 239 406 /* Verify arguments */ 407 PJ_ASSERT_RETURN(ice_st && comp_id, PJ_EINVAL); 408 409 /* Check that component ID present */ 410 PJ_ASSERT_RETURN(comp_id <= ice_st->comp_cnt, PJNATH_EICEINCOMPID); 411 412 /* Can't add new interface while ICE is running */ 413 PJ_ASSERT_RETURN(ice_st->ice == NULL, PJ_EBUSY); 414 415 /* Create interface */ 416 status = create_ice_interface(ice_st, PJ_ICE_CAND_TYPE_HOST, comp_id, 417 local_pref, addr, &is); 240 comp = PJ_POOL_ZALLOC_T(ice_st->pool, pj_ice_st_comp); 241 comp->ice_st = ice_st; 242 comp->comp_id = comp_id; 243 comp->options = options; 244 comp->sock = PJ_INVALID_SOCKET; 245 comp->last_status = PJ_SUCCESS; 246 247 /* Create socket */ 248 status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &comp->sock); 418 249 if (status != PJ_SUCCESS) 419 250 return status; 420 251 421 /* For host interface, the address is the base address */ 422 pj_memcpy(&is->addr, &is->base_addr, sizeof(is->addr)); 423 424 /* Store this interface */ 425 add_interface(ice_st, is, p_itf_id); 426 427 /* Set interface status to SUCCESS */ 428 is->status = PJ_SUCCESS; 252 /* Init address */ 253 if (addr) 254 pj_memcpy(&comp->local_addr, addr, sizeof(pj_sockaddr_in)); 255 else 256 pj_sockaddr_in_init(&comp->local_addr.ipv4, NULL, 0); 257 258 /* Retry binding socket */ 259 for (retry=0; retry<MAX_RETRY; ++retry) { 260 pj_uint16_t port; 261 262 status = pj_sock_bind(comp->sock, &comp->local_addr, 263 sizeof(pj_sockaddr_in)); 264 if (status == PJ_SUCCESS) 265 break; 266 267 if (options & PJ_ICE_ST_OPT_NO_PORT_RETRY) 268 goto on_error; 269 270 port = pj_ntohs(comp->local_addr.ipv4.sin_port); 271 port += PORT_INC; 272 comp->local_addr.ipv4.sin_port = pj_htons(port); 273 } 274 275 /* Get the actual port where the socket is bound to. 276 * (don't care about the address, it will be retrieved later) 277 */ 278 addr_len = sizeof(comp->local_addr); 279 status = pj_sock_getsockname(comp->sock, &comp->local_addr, &addr_len); 280 if (status != PJ_SUCCESS) 281 goto on_error; 282 283 /* Register to ioqueue */ 284 pj_bzero(&ioqueue_cb, sizeof(ioqueue_cb)); 285 ioqueue_cb.on_read_complete = &on_read_complete; 286 status = pj_ioqueue_register_sock(ice_st->pool, ice_st->stun_cfg.ioqueue, 287 comp->sock, comp, &ioqueue_cb, 288 &comp->key); 289 if (status != PJ_SUCCESS) 290 goto on_error; 291 292 pj_ioqueue_op_key_init(&comp->read_op, sizeof(comp->read_op)); 293 pj_ioqueue_op_key_init(&comp->write_op, sizeof(comp->write_op)); 294 295 /* Kick start reading the socket */ 296 on_read_complete(comp->key, &comp->read_op, 0); 297 298 /* If the socket is bound to INADDR_ANY, then lookup all interfaces in 299 * the host and add them into cand_list. Otherwise if the socket is bound 300 * to a specific interface, then only add that specific interface to 301 * cand_list. 302 */ 303 if (comp->local_addr.ipv4.sin_addr.s_addr == 0) { 304 /* Socket is bound to INADDR_ANY */ 305 unsigned i, ifs_cnt; 306 pj_in_addr ifs[PJ_ICE_ST_MAX_ALIASES-2]; 307 308 /* Reset default candidate */ 309 comp->default_cand = -1; 310 311 /* Enum all IP interfaces in the host */ 312 ifs_cnt = PJ_ARRAY_SIZE(ifs); 313 status = pj_enum_ip_interface(&ifs_cnt, ifs); 314 if (status != PJ_SUCCESS) 315 goto on_error; 316 317 /* Set default IP interface as the base address */ 318 status = pj_gethostip(&comp->local_addr.ipv4.sin_addr); 319 if (status != PJ_SUCCESS) 320 return status; 321 322 /* Add candidate entry for each interface */ 323 for (i=0; i<ifs_cnt; ++i) { 324 pj_ice_st_cand *cand = &comp->cand_list[i]; 325 326 cand->type = PJ_ICE_CAND_TYPE_HOST; 327 cand->status = PJ_SUCCESS; 328 pj_memcpy(&cand->addr, &comp->local_addr, sizeof(pj_sockaddr_in)); 329 cand->addr.ipv4.sin_addr.s_addr = ifs[i].s_addr; 330 cand->cand_id = -1; 331 cand->local_pref = 65535; 332 cand->foundation = calc_foundation(ice_st->pool, 333 PJ_ICE_CAND_TYPE_HOST, 334 &cand->addr.ipv4.sin_addr); 335 336 /* If the IP address is equal to local address, assign it 337 * as default candidate. 338 */ 339 if (cand->addr.ipv4.sin_addr.s_addr == 340 comp->local_addr.ipv4.sin_addr.s_addr) 341 { 342 comp->default_cand = i; 343 } 344 345 PJ_LOG(5,(ice_st->obj_name, 346 "Interface %s:%d added to component %d", 347 pj_inet_ntoa(cand->addr.ipv4.sin_addr), 348 (int)pj_ntohs(cand->addr.ipv4.sin_port), comp_id)); 349 } 350 comp->cand_cnt = ifs_cnt; 351 352 353 } else { 354 /* Socket is bound to specific address. 355 * In this case only add that address as a single entry in the 356 * cand_list table. 357 */ 358 pj_ice_st_cand *cand = &comp->cand_list[0]; 359 360 cand->type = PJ_ICE_CAND_TYPE_HOST; 361 cand->status = PJ_SUCCESS; 362 pj_memcpy(&cand->addr, &comp->local_addr, sizeof(pj_sockaddr_in)); 363 cand->cand_id = -1; 364 cand->local_pref = 65535; 365 cand->foundation = calc_foundation(ice_st->pool, 366 PJ_ICE_CAND_TYPE_HOST, 367 &cand->addr.ipv4.sin_addr); 368 369 comp->cand_cnt = 1; 370 comp->default_cand = 0; 371 372 PJ_LOG(5,(ice_st->obj_name, 373 "Interface %s:%d added to component %d", 374 pj_inet_ntoa(cand->addr.ipv4.sin_addr), 375 (int)pj_ntohs(cand->addr.ipv4.sin_port), comp_id)); 376 377 } 378 379 /* Done */ 380 if (p_comp) 381 *p_comp = comp; 429 382 430 383 return PJ_SUCCESS; 431 } 432 433 /* 434 * Enumerate and add all host interfaces. 435 */ 436 PJ_DEF(pj_status_t) pj_ice_st_add_all_host_interfaces(pj_ice_st *ice_st, 437 unsigned comp_id, 438 unsigned port) 439 { 440 pj_sockaddr_in addr; 384 385 on_error: 386 destroy_component(comp); 387 return status; 388 } 389 390 /* 391 * This is callback called by ioqueue on incoming packet 392 */ 393 static void on_read_complete(pj_ioqueue_key_t *key, 394 pj_ioqueue_op_key_t *op_key, 395 pj_ssize_t bytes_read) 396 { 397 pj_ice_st_comp *comp = (pj_ice_st_comp*) 398 pj_ioqueue_get_user_data(key); 399 pj_ice_st *ice_st = comp->ice_st; 400 pj_ssize_t pkt_size; 441 401 pj_status_t status; 442 402 443 /* Yeah, TODO. 444 * For now just add the default interface. 445 */ 446 pj_sockaddr_in_init(&addr, NULL, (pj_uint16_t)port); 447 448 status = pj_gethostip(&addr.sin_addr); 449 if (status != PJ_SUCCESS) 450 return status; 451 452 return pj_ice_st_add_host_interface(ice_st, comp_id, 65535, &addr, NULL); 453 } 454 455 /* 456 * Add STUN mapping interface. 457 */ 458 PJ_DEF(pj_status_t) pj_ice_st_add_stun_interface(pj_ice_st *ice_st, 459 unsigned comp_id, 460 unsigned local_port, 461 unsigned *p_itf_id) 462 { 463 pj_ice_st_interface *is; 464 pj_sockaddr_in local_addr; 403 if (bytes_read > 0) { 404 /* 405 * Okay, we got a packet from the socket for the component. There is 406 * a bit of situation here, since this packet could be one of these: 407 * 408 * 1) this could be the response of STUN binding request sent by 409 * this component to a) an initial request to get the STUN mapped 410 * address of this component, or b) subsequent request to keep 411 * the binding alive. 412 * 413 * 2) this could be a packet (STUN or not STUN) sent from the STUN 414 * relay server. In this case, still there are few options to do 415 * for this packet: a) process this locally if this packet is 416 * related to TURN session management (e.g. Allocate response), 417 * b) forward this packet to ICE if this is related to ICE 418 * discovery process. 419 * 420 * 3) this could be a STUN request or response sent as part of ICE 421 * discovery process. 422 * 423 * 4) this could be application's packet, e.g. when ICE processing 424 * is done and agents start sending RTP/RTCP packets to each 425 * other, or when ICE processing is not done and this ICE stream 426 * transport decides to allow sending data. 427 * 428 * So far we don't have good solution for this. 429 * The process below is just a workaround. 430 */ 431 if (ice_st->ice) { 432 PJ_TODO(DISTINGUISH_BETWEEN_LOCAL_AND_RELAY); 433 status = pj_ice_on_rx_pkt(ice_st->ice, comp->comp_id, 434 comp->cand_list[0].cand_id, 435 comp->pkt, bytes_read, 436 &comp->src_addr, comp->src_addr_len); 437 } else if (comp->stun_sess) { 438 status = pj_stun_msg_check(comp->pkt, bytes_read, 439 PJ_STUN_IS_DATAGRAM); 440 if (status == PJ_SUCCESS) { 441 status = pj_stun_session_on_rx_pkt(comp->stun_sess, comp->pkt, 442 bytes_read, 443 PJ_STUN_IS_DATAGRAM, NULL, 444 &comp->src_addr, 445 comp->src_addr_len); 446 } else { 447 (*ice_st->cb.on_rx_data)(ice_st, comp->comp_id, 448 comp->pkt, bytes_read, 449 &comp->src_addr, comp->src_addr_len); 450 451 } 452 } else { 453 (*ice_st->cb.on_rx_data)(ice_st, comp->comp_id, 454 comp->pkt, bytes_read, 455 &comp->src_addr, comp->src_addr_len); 456 } 457 458 } else if (bytes_read < 0) { 459 ice_st_perror(comp->ice_st, "ioqueue read callback error", 460 -bytes_read); 461 } 462 463 /* Read next packet */ 464 pkt_size = sizeof(comp->pkt); 465 comp->src_addr_len = sizeof(comp->src_addr); 466 status = pj_ioqueue_recvfrom(key, op_key, comp->pkt, &pkt_size, 467 PJ_IOQUEUE_ALWAYS_ASYNC, 468 &comp->src_addr, &comp->src_addr_len); 469 if (status != PJ_SUCCESS && status != PJ_EPENDING) { 470 ice_st_perror(comp->ice_st, "ioqueue recvfrom() error", status); 471 } 472 } 473 474 /* 475 * Destroy a component 476 */ 477 static void destroy_component(pj_ice_st_comp *comp) 478 { 479 if (comp->stun_sess) { 480 pj_stun_session_destroy(comp->stun_sess); 481 comp->stun_sess = NULL; 482 } 483 484 if (comp->key) { 485 pj_ioqueue_unregister(comp->key); 486 comp->key = NULL; 487 comp->sock = PJ_INVALID_SOCKET; 488 } else if (comp->sock != PJ_INVALID_SOCKET && comp->sock != 0) { 489 pj_sock_close(comp->sock); 490 comp->sock = PJ_INVALID_SOCKET; 491 } 492 } 493 494 495 496 /* 497 * Add STUN mapping to a component. 498 */ 499 static pj_status_t get_stun_mapped_addr(pj_ice_st *ice_st, 500 pj_ice_st_comp *comp) 501 { 502 pj_ice_st_cand *cand; 465 503 pj_stun_session_cb sess_cb; 466 504 pj_stun_tx_data *tdata; 467 505 pj_status_t status; 468 506 469 PJ_ASSERT_RETURN(ice_st && comp _id, PJ_EINVAL);507 PJ_ASSERT_RETURN(ice_st && comp, PJ_EINVAL); 470 508 471 /* STUN server must have been configured */ 472 PJ_ASSERT_RETURN(ice_st->stun_srv.sin_family != 0, PJ_EINVALIDOP); 473 474 475 /* Create interface */ 476 pj_sockaddr_in_init(&local_addr, NULL, (pj_uint16_t)local_port); 477 status = create_ice_interface(ice_st, PJ_ICE_CAND_TYPE_SRFLX, comp_id, 478 65535, &local_addr, &is); 479 if (status != PJ_SUCCESS) 480 return status; 481 482 /* Create STUN session */ 509 /* Bail out if STUN server is still being resolved */ 510 if (ice_st->has_resolver_job) 511 return PJ_EBUSY; 512 513 /* Just return (successfully) if STUN server is not configured */ 514 if (ice_st->stun_srv.sin_family == 0) 515 return PJ_SUCCESS; 516 517 518 /* Create STUN session for this component */ 483 519 pj_bzero(&sess_cb, sizeof(sess_cb)); 484 520 sess_cb.on_request_complete = &stun_on_request_complete; 485 521 sess_cb.on_send_msg = &stun_on_send_msg; 486 522 status = pj_stun_session_create(&ice_st->stun_cfg, ice_st->obj_name, 487 &sess_cb, PJ_FALSE, & is->stun_sess);523 &sess_cb, PJ_FALSE, &comp->stun_sess); 488 524 if (status != PJ_SUCCESS) 489 goto on_error;490 491 /* Associate interfacewith STUN session */492 pj_stun_session_set_user_data( is->stun_sess, (void*)is);493 494 /* Create and sendSTUN binding request */495 status = pj_stun_session_create_req( is->stun_sess,525 return status; 526 527 /* Associate component with STUN session */ 528 pj_stun_session_set_user_data(comp->stun_sess, (void*)comp); 529 530 /* Create STUN binding request */ 531 status = pj_stun_session_create_req(comp->stun_sess, 496 532 PJ_STUN_BINDING_REQUEST, &tdata); 497 533 if (status != PJ_SUCCESS) 498 goto on_error; 499 500 status = pj_stun_session_send_msg(is->stun_sess, PJ_FALSE, 534 return status; 535 536 /* Attach alias instance to tdata */ 537 cand = &comp->cand_list[comp->cand_cnt]; 538 tdata->user_data = (void*)cand; 539 540 /* Send STUN binding request */ 541 status = pj_stun_session_send_msg(comp->stun_sess, PJ_FALSE, 501 542 &ice_st->stun_srv, 502 543 sizeof(pj_sockaddr_in), tdata); 503 544 if (status != PJ_SUCCESS) 504 goto on_error; 505 506 /* Mark interface as pending */ 507 is->status = PJ_EPENDING; 508 509 add_interface(ice_st, is, p_itf_id); 545 return status; 546 547 548 /* Add new alias to this component */ 549 cand->type = PJ_ICE_CAND_TYPE_SRFLX; 550 cand->status = PJ_EPENDING; 551 cand->cand_id = -1; 552 cand->local_pref = 65535; 553 cand->foundation = calc_foundation(ice_st->pool, PJ_ICE_CAND_TYPE_SRFLX, 554 &comp->local_addr.ipv4.sin_addr); 555 556 ++comp->cand_cnt; 557 558 /* Add pending count for this component */ 559 comp->pending_cnt++; 510 560 511 561 return PJ_SUCCESS; 512 513 on_error: 514 destroy_ice_interface(is); 515 return status; 516 } 517 518 /* 519 * Add TURN mapping interface. 520 */ 521 PJ_DEF(pj_status_t) pj_ice_st_add_relay_interface(pj_ice_st *ice_st, 522 unsigned comp_id, 523 unsigned local_port, 524 pj_bool_t notify, 525 void *notify_data) 526 { 527 /* Yeah, TODO */ 528 PJ_UNUSED_ARG(ice_st); 529 PJ_UNUSED_ARG(comp_id); 530 PJ_UNUSED_ARG(local_port); 531 PJ_UNUSED_ARG(notify); 532 PJ_UNUSED_ARG(notify_data); 533 return -1; 534 } 535 536 PJ_DEF(pj_status_t) pj_ice_st_get_interfaces_status(pj_ice_st *ice_st) 562 } 563 564 565 /* 566 * Create the component. 567 */ 568 PJ_DEF(pj_status_t) pj_ice_st_create_comp(pj_ice_st *ice_st, 569 unsigned comp_id, 570 pj_uint32_t options, 571 const pj_sockaddr_in *addr, 572 unsigned *p_itf_id) 573 { 574 pj_ice_st_comp *comp; 575 pj_status_t status; 576 577 /* Verify arguments */ 578 PJ_ASSERT_RETURN(ice_st && comp_id, PJ_EINVAL); 579 580 /* Check that component ID present */ 581 PJ_ASSERT_RETURN(comp_id <= ice_st->comp_cnt, PJNATH_EICEINCOMPID); 582 583 /* Can't add new component while ICE is running */ 584 PJ_ASSERT_RETURN(ice_st->ice == NULL, PJ_EBUSY); 585 586 /* Can't add new component while resolver is running */ 587 PJ_ASSERT_RETURN(ice_st->has_resolver_job == PJ_FALSE, PJ_EBUSY); 588 589 590 /* Create component */ 591 status = create_component(ice_st, comp_id, options, addr, &comp); 592 if (status != PJ_SUCCESS) 593 return status; 594 595 if ((options & PJ_ICE_ST_OPT_DISABLE_STUN) == 0) { 596 status = get_stun_mapped_addr(ice_st, comp); 597 if (status != PJ_SUCCESS) { 598 destroy_component(comp); 599 return status; 600 } 601 } 602 603 /* Store this component */ 604 if (p_itf_id) 605 *p_itf_id = ice_st->comp_cnt; 606 607 ice_st->comp[comp_id-1] = comp; 608 609 return PJ_SUCCESS; 610 } 611 612 613 PJ_DEF(pj_status_t) pj_ice_st_get_comps_status(pj_ice_st *ice_st) 537 614 { 538 615 unsigned i; 539 616 pj_status_t worst = PJ_SUCCESS; 540 617 541 for (i=0; i<ice_st-> itf_cnt; ++i) {542 pj_ice_st_ interface *itf = ice_st->itfs[i];543 544 if ( itf->status == PJ_SUCCESS) {618 for (i=0; i<ice_st->comp_cnt; ++i) { 619 pj_ice_st_comp *comp = ice_st->comp[i]; 620 621 if (comp->last_status == PJ_SUCCESS) { 545 622 /* okay */ 546 } else if (itf->status == PJ_EPENDING && worst==PJ_SUCCESS) { 547 worst = itf->status; 548 } else { 549 worst = itf->status; 623 } else if (comp->pending_cnt && worst==PJ_SUCCESS) { 624 worst = PJ_EPENDING; 625 break; 626 } else if (comp->last_status != PJ_SUCCESS) { 627 worst = comp->last_status; 628 break; 550 629 } 630 631 if (worst != PJ_SUCCESS) 632 break; 551 633 } 552 634 … … 574 656 pj_bzero(&ice_cb, sizeof(ice_cb)); 575 657 ice_cb.on_ice_complete = &on_ice_complete; 576 ice_cb.on_rx_data = & on_rx_data;577 ice_cb.on_tx_pkt = & on_tx_pkt;658 ice_cb.on_rx_data = &ice_rx_data; 659 ice_cb.on_tx_pkt = &ice_tx_pkt; 578 660 579 661 /* Create! */ … … 588 670 589 671 /* Add candidates */ 590 for (i=0; i<ice_st->itf_cnt; ++i) { 591 pj_ice_st_interface *is= ice_st->itfs[i]; 592 status = pj_ice_add_cand(ice_st->ice, is->comp_id, is->type, 593 is->local_pref, &is->foundation, 594 &is->addr, &is->base_addr, NULL, 595 sizeof(pj_sockaddr_in), 596 (unsigned*)&is->cand_id); 597 if (status != PJ_SUCCESS) 598 goto on_error; 672 for (i=0; i<ice_st->comp_cnt; ++i) { 673 unsigned j; 674 pj_ice_st_comp *comp= ice_st->comp[i]; 675 676 for (j=0; j<comp->cand_cnt; ++j) { 677 pj_ice_st_cand *cand = &comp->cand_list[j]; 678 679 /* Skip if candidate is not ready */ 680 if (cand->status != PJ_SUCCESS) { 681 PJ_LOG(5,(ice_st->obj_name, 682 "Candidate %d in component %d is not added", 683 j, i)); 684 continue; 685 } 686 687 status = pj_ice_add_cand(ice_st->ice, comp->comp_id, cand->type, 688 cand->local_pref, &cand->foundation, 689 &cand->addr, &comp->local_addr, NULL, 690 sizeof(pj_sockaddr_in), 691 (unsigned*)&cand->cand_id); 692 if (status != PJ_SUCCESS) 693 goto on_error; 694 } 599 695 } 600 696 … … 602 698 603 699 on_error: 604 for (i=0; i<ice_st->itf_cnt; ++i) { 605 ice_st->itfs[i]->cand_id = -1; 606 } 607 if (ice_st->ice) { 608 pj_ice_destroy(ice_st->ice); 609 ice_st->ice = NULL; 610 } 700 pj_ice_st_stop_ice(ice_st); 611 701 return status; 612 702 } … … 654 744 return status; 655 745 656 return pj_ice_start_check(ice_st->ice); 746 status = pj_ice_start_check(ice_st->ice); 747 if (status != PJ_SUCCESS) { 748 pj_ice_st_stop_ice(ice_st); 749 } 750 751 return status; 657 752 } 658 753 … … 662 757 PJ_DECL(pj_status_t) pj_ice_st_stop_ice(pj_ice_st *ice_st) 663 758 { 759 unsigned i; 760 664 761 if (ice_st->ice) { 665 762 pj_ice_destroy(ice_st->ice); … … 667 764 } 668 765 766 /* Invalidate all candidate Ids */ 767 for (i=0; i<ice_st->comp_cnt; ++i) { 768 unsigned j; 769 for (j=0; j<ice_st->comp[i]->cand_cnt; ++j) { 770 ice_st->comp[i]->cand_list[j].cand_id = -1; 771 } 772 } 773 669 774 return PJ_SUCCESS; 670 }671 672 /*673 * Send data to peer agent.674 */675 PJ_DEF(pj_status_t) pj_ice_st_send_data( pj_ice_st *ice_st,676 unsigned comp_id,677 const void *data,678 pj_size_t data_len)679 {680 if (!ice_st->ice)681 return PJNATH_ENOICE;682 683 return pj_ice_send_data(ice_st->ice, comp_id, data, data_len);684 775 } 685 776 … … 689 780 PJ_DEF(pj_status_t) pj_ice_st_sendto( pj_ice_st *ice_st, 690 781 unsigned comp_id, 691 unsigned itf_id,692 782 const void *data, 693 783 pj_size_t data_len, … … 696 786 { 697 787 pj_ssize_t pkt_size; 698 pj_ice_st_ interface *is = ice_st->itfs[itf_id];788 pj_ice_st_comp *comp; 699 789 pj_status_t status; 700 790 791 PJ_ASSERT_RETURN(ice_st && comp_id && comp_id <= ice_st->comp_cnt && 792 dst_addr && dst_addr_len, PJ_EINVAL); 793 794 comp = ice_st->comp[comp_id-1]; 795 796 /* If ICE is available, send data with ICE */ 797 if (ice_st->ice) { 798 return pj_ice_send_data(ice_st->ice, comp_id, data, data_len); 799 } 800 801 /* Otherwise send direcly with the socket */ 701 802 pkt_size = data_len; 702 status = pj_ioqueue_sendto( is->key, &is->write_op,803 status = pj_ioqueue_sendto(comp->key, &comp->write_op, 703 804 data, &pkt_size, 0, 704 805 dst_addr, dst_addr_len); … … 722 823 * Callback called by ICE session when it wants to send outgoing packet. 723 824 */ 724 static pj_status_t on_tx_pkt(pj_ice *ice,725 unsigned comp_id, unsigned cand_id,726 const void *pkt, pj_size_t size,727 const pj_sockaddr_t *dst_addr,728 unsigned dst_addr_len)825 static pj_status_t ice_tx_pkt(pj_ice *ice, 826 unsigned comp_id, unsigned cand_id, 827 const void *pkt, pj_size_t size, 828 const pj_sockaddr_t *dst_addr, 829 unsigned dst_addr_len) 729 830 { 730 831 pj_ice_st *ice_st = (pj_ice_st*)ice->user_data; 731 pj_ice_st_interface *is = NULL; 732 unsigned i; 832 pj_ice_st_comp *comp = NULL; 733 833 pj_ssize_t pkt_size; 734 834 pj_status_t status; 735 835 736 PJ_UNUSED_ARG(comp_id); 737 738 for (i=0; i<ice_st->itf_cnt; ++i) { 739 if (ice_st->itfs[i]->cand_id == (int)cand_id) { 740 is = ice_st->itfs[i]; 741 break; 742 } 743 } 744 if (is == NULL) { 745 return PJNATH_EICEINCANDID; 746 } 836 PJ_TODO(TX_TO_RELAY); 837 838 PJ_ASSERT_RETURN(comp_id && comp_id <= ice_st->comp_cnt, PJ_EINVAL); 839 comp = ice_st->comp[comp_id-1]; 747 840 748 841 pkt_size = size; 749 status = pj_ioqueue_sendto( is->key, &is->write_op,842 status = pj_ioqueue_sendto(comp->key, &comp->write_op, 750 843 pkt, &pkt_size, 0, 751 844 dst_addr, dst_addr_len); … … 757 850 * Callback called by ICE session when it receives application data. 758 851 */ 759 static void on_rx_data(pj_ice *ice,760 unsigned comp_id, unsigned cand_id,761 void *pkt, pj_size_t size,762 const pj_sockaddr_t *src_addr,763 unsigned src_addr_len)852 static void ice_rx_data(pj_ice *ice, 853 unsigned comp_id, 854 void *pkt, pj_size_t size, 855 const pj_sockaddr_t *src_addr, 856 unsigned src_addr_len) 764 857 { 765 858 pj_ice_st *ice_st = (pj_ice_st*)ice->user_data; 766 859 767 860 if (ice_st->cb.on_rx_data) { 768 (*ice_st->cb.on_rx_data)(ice_st, comp_id, cand_id,769 pkt, size,src_addr, src_addr_len);861 (*ice_st->cb.on_rx_data)(ice_st, comp_id, pkt, size, 862 src_addr, src_addr_len); 770 863 } 771 864 } … … 780 873 unsigned dst_addr_len) 781 874 { 782 pj_ice_st_ interface *is;875 pj_ice_st_comp *comp; 783 876 pj_ssize_t pkt_size; 784 877 pj_status_t status; 785 878 786 is = (pj_ice_st_interface*) pj_stun_session_get_user_data(sess);879 comp = (pj_ice_st_comp*) pj_stun_session_get_user_data(sess); 787 880 pkt_size = size; 788 status = pj_ioqueue_sendto( is->key, &is->write_op,881 status = pj_ioqueue_sendto(comp->key, &comp->write_op, 789 882 pkt, &pkt_size, 0, 790 883 dst_addr, dst_addr_len); … … 802 895 const pj_stun_msg *response) 803 896 { 804 pj_ice_st_interface *is; 897 pj_ice_st_comp *comp; 898 pj_ice_st_cand *cand = NULL; 805 899 pj_stun_xor_mapped_addr_attr *xa; 806 900 pj_stun_mapped_addr_attr *ma; 807 901 pj_sockaddr *mapped_addr; 808 902 809 PJ_UNUSED_ARG(tdata); 810 811 is = (pj_ice_st_interface*) pj_stun_session_get_user_data(sess); 903 comp = (pj_ice_st_comp*) pj_stun_session_get_user_data(sess); 904 cand = (pj_ice_st_cand*) tdata->user_data; 905 906 /* Decrement pending count for this component */ 907 pj_assert(comp->pending_cnt > 0); 908 comp->pending_cnt--; 909 812 910 if (status != PJ_SUCCESS) { 813 is->status = status; 814 ice_st_perror(is->ice_st, "STUN Binding request failed", is->status); 911 comp->last_status = cand->status = status; 912 ice_st_perror(comp->ice_st, "STUN Binding request failed", 913 cand->status); 815 914 return; 816 915 } … … 826 925 mapped_addr = &ma->sockaddr; 827 926 else { 828 is->status = PJNATH_ESTUNNOMAPPEDADDR; 829 ice_st_perror(is->ice_st, "STUN Binding request failed", is->status); 927 cand->status = PJNATH_ESTUNNOMAPPEDADDR; 928 ice_st_perror(comp->ice_st, "STUN Binding request failed", 929 cand->status); 830 930 return; 831 931 } 832 932 833 PJ_LOG(4,( is->ice_st->obj_name,933 PJ_LOG(4,(comp->ice_st->obj_name, 834 934 "STUN mapped address: %s:%d", 835 935 pj_inet_ntoa(mapped_addr->ipv4.sin_addr), 836 936 (int)pj_ntohs(mapped_addr->ipv4.sin_port))); 837 pj_memcpy(&is->addr, mapped_addr, sizeof(pj_sockaddr_in)); 838 is->status = PJ_SUCCESS; 839 840 } 841 937 pj_memcpy(&cand->addr, mapped_addr, sizeof(pj_sockaddr_in)); 938 cand->status = PJ_SUCCESS; 939 940 /* Set this candidate as the default candidate */ 941 comp->default_cand = (cand - comp->cand_list); 942 comp->last_status = PJ_SUCCESS; 943 } 944
Note: See TracChangeset
for help on using the changeset viewer.