/*! * \brief Pass WebSocket data into pjsip transport manager. */ static int transport_read(void *data) { struct transport_read_data *read_data = data; struct ws_transport *newtransport = read_data->transport; struct ast_websocket *session = newtransport->ws_session; pjsip_rx_data *rdata = &newtransport->rdata; int recvd; pj_str_t buf; int pjsip_pkt_len; pj_gettimeofday(&rdata->pkt_info.timestamp); pjsip_pkt_len = PJSIP_MAX_PKT_LEN < read_data->payload_len ? PJSIP_MAX_PKT_LEN : read_data->payload_len; pj_memcpy(rdata->pkt_info.packet, read_data->payload, pjsip_pkt_len); rdata->pkt_info.len = pjsip_pkt_len; rdata->pkt_info.zero = 0; pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&buf, ast_sockaddr_stringify(ast_websocket_remote_address(session))), &rdata->pkt_info.src_addr); rdata->pkt_info.src_addr.addr.sa_family = pj_AF_INET(); rdata->pkt_info.src_addr_len = sizeof(rdata->pkt_info.src_addr); pj_ansi_strcpy(rdata->pkt_info.src_name, ast_sockaddr_stringify_host(ast_websocket_remote_address(session))); rdata->pkt_info.src_port = ast_sockaddr_port(ast_websocket_remote_address(session)); recvd = pjsip_tpmgr_receive_packet(rdata->tp_info.transport->tpmgr, rdata); pj_pool_reset(rdata->tp_info.pool); return (read_data->payload_len == recvd) ? 0 : -1; }
/* * Set presence status. */ PJ_DEF(pj_status_t) pjsip_pres_set_status( pjsip_evsub *sub, const pjsip_pres_status *status ) { unsigned i; pj_pool_t *tmp; pjsip_pres *pres; PJ_ASSERT_RETURN(sub && status, PJ_EINVAL); pres = (pjsip_pres*) pjsip_evsub_get_mod_data(sub, mod_presence.id); PJ_ASSERT_RETURN(pres!=NULL, PJSIP_SIMPLE_ENOPRESENCE); for (i=0; i<status->info_cnt; ++i) { pres->status.info[i].basic_open = status->info[i].basic_open; if (pres->status.info[i].id.slen) { /* Id already set */ } else if (status->info[i].id.slen == 0) { pj_create_unique_string(pres->dlg->pool, &pres->status.info[i].id); } else { pj_strdup(pres->dlg->pool, &pres->status.info[i].id, &status->info[i].id); } pj_strdup(pres->tmp_pool, &pres->status.info[i].contact, &status->info[i].contact); /* Duplicate <person> */ pres->status.info[i].rpid.activity = status->info[i].rpid.activity; pj_strdup(pres->tmp_pool, &pres->status.info[i].rpid.id, &status->info[i].rpid.id); pj_strdup(pres->tmp_pool, &pres->status.info[i].rpid.note, &status->info[i].rpid.note); pj_strdup(pres->tmp_pool, &pres->status.info[i].rpid.component, &status->info[i].rpid.component); } pres->status.info_cnt = status->info_cnt; /* Swap pools */ tmp = pres->tmp_pool; pres->tmp_pool = pres->status_pool; pres->status_pool = tmp; pj_pool_reset(pres->tmp_pool); return PJ_SUCCESS; }
/* * Create NOTIFY */ PJ_DEF(pj_status_t) pjsip_mwi_notify( pjsip_evsub *sub, pjsip_evsub_state state, const pj_str_t *state_str, const pj_str_t *reason, const pjsip_media_type *mime_type, const pj_str_t *body, pjsip_tx_data **p_tdata) { pjsip_mwi *mwi; pjsip_tx_data *tdata; pj_status_t status; /* Check arguments. */ PJ_ASSERT_RETURN(sub && mime_type && body && p_tdata, PJ_EINVAL); /* Get the mwi object. */ mwi = (pjsip_mwi*) pjsip_evsub_get_mod_data(sub, mod_mwi.id); PJ_ASSERT_RETURN(mwi != NULL, PJ_EINVALIDOP); /* Lock object. */ pjsip_dlg_inc_lock(mwi->dlg); /* Create the NOTIFY request. */ status = pjsip_evsub_notify( sub, state, state_str, reason, &tdata); if (status != PJ_SUCCESS) goto on_return; /* Update the cached message body */ if (mime_type || body) pj_pool_reset(mwi->body_pool); if (mime_type) pjsip_media_type_cp(mwi->body_pool, &mwi->mime_type, mime_type); if (body) pj_strdup(mwi->body_pool, &mwi->body, body); /* Create message body */ status = mwi_create_msg_body( mwi, tdata ); if (status != PJ_SUCCESS) goto on_return; /* Done. */ *p_tdata = tdata; on_return: pjsip_dlg_dec_lock(mwi->dlg); return status; }
/* Test that the alignment works. */ static int pool_alignment_test(void) { pj_pool_t *pool; void *ptr; enum { MEMSIZE = 64, LOOP = 100 }; unsigned i; PJ_LOG(3,("test", "...alignment test")); pool = pj_pool_create(mem, NULL, PJ_POOL_SIZE+MEMSIZE, MEMSIZE, NULL); if (!pool) return -300; #define IS_ALIGNED(p) ((((unsigned long)p) & (PJ_POOL_ALIGNMENT-1)) == 0) for (i=0; i<LOOP; ++i) { /* Test first allocation */ ptr = pj_pool_alloc(pool, 1); if (!IS_ALIGNED(ptr)) { pj_pool_release(pool); return -310; } /* Test subsequent allocation */ ptr = pj_pool_alloc(pool, 1); if (!IS_ALIGNED(ptr)) { pj_pool_release(pool); return -320; } /* Test allocation after new block is created */ ptr = pj_pool_alloc(pool, MEMSIZE*2+1); if (!IS_ALIGNED(ptr)) { pj_pool_release(pool); return -330; } /* Reset the pool */ pj_pool_reset(pool); } /* Done */ pj_pool_release(pool); return 0; }
/* * Callback on received packet. */ static void on_read_complete(pj_ioqueue_key_t *key, pj_ioqueue_op_key_t *op_key, pj_ssize_t bytes_read) { struct udp_listener *udp; struct read_op *read_op = (struct read_op*) op_key; pj_status_t status; udp = (struct udp_listener*) pj_ioqueue_get_user_data(key); do { pj_pool_t *rpool; /* Report to server */ if (bytes_read > 0) { read_op->pkt.len = bytes_read; pj_gettimeofday(&read_op->pkt.rx_time); pj_turn_srv_on_rx_pkt(udp->base.server, &read_op->pkt); } /* Reset pool */ rpool = read_op->pkt.pool; pj_pool_reset(rpool); read_op->pkt.pool = rpool; read_op->pkt.transport = &udp->tp; read_op->pkt.src.tp_type = udp->base.tp_type; /* Read next packet */ bytes_read = sizeof(read_op->pkt.pkt); read_op->pkt.src_addr_len = sizeof(read_op->pkt.src.clt_addr); pj_bzero(&read_op->pkt.src.clt_addr, sizeof(read_op->pkt.src.clt_addr)); status = pj_ioqueue_recvfrom(udp->key, op_key, read_op->pkt.pkt, &bytes_read, 0, &read_op->pkt.src.clt_addr, &read_op->pkt.src_addr_len); if (status != PJ_EPENDING && status != PJ_SUCCESS) bytes_read = -status; } while (status != PJ_EPENDING && status != PJ_ECANCELLED && status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL)); }
/* * Stop the clock. */ PJ_DEF(pj_status_t) pjmedia_clock_stop(pjmedia_clock *clock) { PJ_ASSERT_RETURN(clock != NULL, PJ_EINVAL); clock->running = PJ_FALSE; clock->quitting = PJ_TRUE; if (clock->thread) { // printf("%s:------------1--------------, 0x%02x, %d\n", THIS_FILE, clock, (int)(clock->quitting)); if (pj_thread_join(clock->thread) == PJ_SUCCESS) { // printf("%s:------------2--------------\n", THIS_FILE); pj_thread_destroy(clock->thread); clock->thread = NULL; pj_pool_reset(clock->pool); } else { // printf("%s:------------3--------------\n", THIS_FILE); clock->quitting = PJ_FALSE; } } return PJ_SUCCESS; }
void SipIceTransport::onRecv() { rdata_.pkt_info.len += ice_->recv(comp_id_, (uint8_t*)rdata_.pkt_info.packet+rdata_.pkt_info.len, sizeof(rdata_.pkt_info.packet)-rdata_.pkt_info.len); rdata_.pkt_info.zero = 0; pj_gettimeofday(&rdata_.pkt_info.timestamp); auto eaten = pjsip_tpmgr_receive_packet(rdata_.tp_info.transport->tpmgr, &rdata_); /* Move unprocessed data to the front of the buffer */ auto rem = rdata_.pkt_info.len - eaten; if (rem > 0 && rem != rdata_.pkt_info.len) { std::move(rdata_.pkt_info.packet + eaten, rdata_.pkt_info.packet + eaten + rem, rdata_.pkt_info.packet); } rdata_.pkt_info.len = rem; /* Reset pool */ pj_pool_reset(rdata_.tp_info.pool); }
static int sdp_perform_test(pj_pool_factory *pf) { pj_pool_t *pool; int inputlen, len; pjsdp_session_desc *ses; char buf[1500]; enum { LOOP=1000000 }; int i; pj_time_val start, end; printf("Parsing and printing %d SDP messages..\n", LOOP); pool = pj_pool_create(pf, "", 4096, 0, NULL); inputlen = strlen(sdp[0]); pj_gettimeofday(&start); for (i=0; i<LOOP; ++i) { ses = pjsdp_parse(sdp[0], inputlen, pool); len = pjsdp_print(ses, buf, sizeof(buf)); buf[len] = '\0'; pj_pool_reset(pool); } pj_gettimeofday(&end); printf("Original:\n%s\n", sdp[0]); printf("Parsed:\n%s\n", buf); PJ_TIME_VAL_SUB(end, start); printf("Time: %ld:%03lds\n", end.sec, end.msec); if (end.msec==0 && end.sec==0) end.msec=1; printf("Performance: %ld msg/sec\n", LOOP*1000/PJ_TIME_VAL_MSEC(end)); puts(""); pj_pool_release(pool); return 0; }
/* Test that the alignment works for pool on buf. */ static int pool_buf_alignment_test(void) { pj_pool_t *pool; char buf[512]; void *ptr; enum { LOOP = 100 }; unsigned i; PJ_LOG(3,("test", "...pool_buf alignment test")); pool = pj_pool_create_on_buf(NULL, buf, sizeof(buf)); if (!pool) return -400; for (i=0; i<LOOP; ++i) { /* Test first allocation */ ptr = pj_pool_alloc(pool, 1); if (!IS_ALIGNED(ptr)) { pj_pool_release(pool); return -410; } /* Test subsequent allocation */ ptr = pj_pool_alloc(pool, 1); if (!IS_ALIGNED(ptr)) { pj_pool_release(pool); return -420; } /* Reset the pool */ pj_pool_reset(pool); } /* Done */ return 0; }
/* Release pool */ PJ_DEF(void) pj_pool_release_imp(pj_pool_t *pool) { pj_pool_reset(pool); free(pool); }
static void register_aor_core(pjsip_rx_data *rdata, struct ast_sip_endpoint *endpoint, struct ast_sip_aor *aor, const char *aor_name, struct ao2_container *contacts, struct aor_core_response *response) { static const pj_str_t USER_AGENT = { "User-Agent", 10 }; int added = 0; int updated = 0; int deleted = 0; int permanent = 0; int contact_count; struct ao2_container *existing_contacts = NULL; pjsip_contact_hdr *contact_hdr = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr; struct registrar_contact_details details = { 0, }; pjsip_tx_data *tdata; RAII_VAR(struct ast_str *, path_str, NULL, ast_free); struct ast_sip_contact *response_contact; char *user_agent = NULL; pjsip_user_agent_hdr *user_agent_hdr; pjsip_expires_hdr *expires_hdr; pjsip_via_hdr *via_hdr; pjsip_via_hdr *via_hdr_last; char *via_addr = NULL; int via_port = 0; pjsip_cid_hdr *call_id_hdr; char *call_id = NULL; size_t alloc_size; /* We create a single pool and use it throughout this function where we need one */ details.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Contact Comparison", 1024, 256); if (!details.pool) { response->code = 500; return; } /* If there are any permanent contacts configured on the AOR we need to take them * into account when counting contacts. */ if (aor->permanent_contacts) { permanent = ao2_container_count(aor->permanent_contacts); } if (registrar_validate_contacts(rdata, details.pool, contacts, aor, permanent, &added, &updated, &deleted)) { /* The provided Contact headers do not conform to the specification */ ast_sip_report_failed_acl(endpoint, rdata, "registrar_invalid_contacts_provided"); ast_log(LOG_WARNING, "Failed to validate contacts in REGISTER request from '%s'\n", ast_sorcery_object_get_id(endpoint)); response->code = 400; pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool); return; } if (registrar_validate_path(rdata, aor, &path_str)) { /* Ensure that intervening proxies did not make invalid modifications to the request */ ast_log(LOG_WARNING, "Invalid modifications made to REGISTER request from '%s' by intervening proxy\n", ast_sorcery_object_get_id(endpoint)); response->code = 420; pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool); return; } if (aor->remove_existing) { /* Cumulative number of contacts affected by this registration */ contact_count = MAX(updated + added - deleted, 0); /* We need to keep track of only existing contacts so we can later * remove them if need be. */ existing_contacts = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, NULL, ast_sorcery_object_id_compare); if (!existing_contacts) { response->code = 500; pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool); return; } ao2_callback(contacts, OBJ_NODATA, registrar_add_non_permanent, existing_contacts); } else { /* Total contacts after this registration */ contact_count = ao2_container_count(contacts) - permanent + added - deleted; } if (contact_count > aor->max_contacts) { /* Enforce the maximum number of contacts */ ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_exceeds_maximum_configured_contacts"); ast_log(LOG_WARNING, "Registration attempt from endpoint '%s' to AOR '%s' will exceed max contacts of %u\n", ast_sorcery_object_get_id(endpoint), aor_name, aor->max_contacts); response->code = 403; pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool); ao2_cleanup(existing_contacts); return; } user_agent_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &USER_AGENT, NULL); if (user_agent_hdr) { alloc_size = pj_strlen(&user_agent_hdr->hvalue) + 1; user_agent = ast_alloca(alloc_size); ast_copy_pj_str(user_agent, &user_agent_hdr->hvalue, alloc_size); } /* Find the first Via header */ via_hdr = via_hdr_last = (pjsip_via_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_VIA, NULL); if (via_hdr) { /* Find the last Via header */ while ( (via_hdr = (pjsip_via_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_VIA, via_hdr->next)) != NULL) { via_hdr_last = via_hdr; } alloc_size = pj_strlen(&via_hdr_last->sent_by.host) + 1; via_addr = ast_alloca(alloc_size); ast_copy_pj_str(via_addr, &via_hdr_last->sent_by.host, alloc_size); via_port=via_hdr_last->sent_by.port; } call_id_hdr = (pjsip_cid_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CALL_ID, NULL); if (call_id_hdr) { alloc_size = pj_strlen(&call_id_hdr->id) + 1; call_id = ast_alloca(alloc_size); ast_copy_pj_str(call_id, &call_id_hdr->id, alloc_size); } /* Iterate each provided Contact header and add, update, or delete */ for (; (contact_hdr = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr->next)); pj_pool_reset(details.pool)) { int expiration; char contact_uri[pjsip_max_url_size]; RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup); if (contact_hdr->star) { /* A star means to unregister everything, so do so for the possible contacts */ ao2_callback(contacts, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, registrar_delete_contact, (void *)aor_name); /* If we are keeping track of existing contacts for removal then, well, there is * absolutely nothing left so no need to try to remove any. */ if (existing_contacts) { ao2_ref(existing_contacts, -1); existing_contacts = NULL; } break; } if (!PJSIP_URI_SCHEME_IS_SIP(contact_hdr->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact_hdr->uri)) { /* This registrar only currently supports sip: and sips: URI schemes */ continue; } expiration = registrar_get_expiration(aor, contact_hdr, rdata); details.uri = pjsip_uri_get_uri(contact_hdr->uri); pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri)); contact = ao2_callback(contacts, OBJ_UNLINK, registrar_find_contact, &details); /* If a contact was returned and we need to keep track of existing contacts then it * should be removed. */ if (contact && existing_contacts) { ao2_unlink(existing_contacts, contact); } if (!contact) { int prune_on_boot; /* If they are actually trying to delete a contact that does not exist... be forgiving */ if (!expiration) { ast_verb(3, "Attempted to remove non-existent contact '%s' from AOR '%s' by request\n", contact_uri, aor_name); continue; } prune_on_boot = !ast_sip_will_uri_survive_restart(details.uri, endpoint, rdata); contact = ast_sip_location_create_contact(aor, contact_uri, ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1)), path_str ? ast_str_buffer(path_str) : NULL, user_agent, via_addr, via_port, call_id, prune_on_boot, endpoint); if (!contact) { ast_log(LOG_ERROR, "Unable to bind contact '%s' to AOR '%s'\n", contact_uri, aor_name); continue; } if (prune_on_boot) { const char *contact_name; struct contact_transport_monitor *monitor; /* * Monitor the transport in case it gets disconnected because * the contact won't be valid anymore if that happens. */ contact_name = ast_sorcery_object_get_id(contact); monitor = ao2_alloc_options(sizeof(*monitor) + 2 + strlen(aor_name) + strlen(contact_name), NULL, AO2_ALLOC_OPT_LOCK_NOLOCK); if (monitor) { strcpy(monitor->aor_name, aor_name);/* Safe */ monitor->contact_name = monitor->aor_name + strlen(aor_name) + 1; strcpy(monitor->contact_name, contact_name);/* Safe */ ast_sip_transport_monitor_register(rdata->tp_info.transport, register_contact_transport_shutdown_cb, monitor); ao2_ref(monitor, -1); } } ast_verb(3, "Added contact '%s' to AOR '%s' with expiration of %d seconds\n", contact_uri, aor_name, expiration); ast_test_suite_event_notify("AOR_CONTACT_ADDED", "Contact: %s\r\n" "AOR: %s\r\n" "Expiration: %d\r\n" "UserAgent: %s", contact_uri, aor_name, expiration, user_agent); ao2_link(contacts, contact); } else if (expiration) { struct ast_sip_contact *contact_update; contact_update = ast_sorcery_copy(ast_sip_get_sorcery(), contact); if (!contact_update) { ast_log(LOG_ERROR, "Failed to update contact '%s' expiration time to %d seconds.\n", contact->uri, expiration); continue; } contact_update->expiration_time = ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1)); contact_update->qualify_frequency = aor->qualify_frequency; contact_update->authenticate_qualify = aor->authenticate_qualify; if (path_str) { ast_string_field_set(contact_update, path, ast_str_buffer(path_str)); } if (user_agent) { ast_string_field_set(contact_update, user_agent, user_agent); } if (!ast_strlen_zero(ast_config_AST_SYSTEM_NAME)) { ast_string_field_set(contact_update, reg_server, ast_config_AST_SYSTEM_NAME); } if (ast_sip_location_update_contact(contact_update)) { ast_log(LOG_ERROR, "Failed to update contact '%s' expiration time to %d seconds.\n", contact->uri, expiration); ast_sip_location_delete_contact(contact); continue; } ast_debug(3, "Refreshed contact '%s' on AOR '%s' with new expiration of %d seconds\n", contact_uri, aor_name, expiration); ast_test_suite_event_notify("AOR_CONTACT_REFRESHED", "Contact: %s\r\n" "AOR: %s\r\n" "Expiration: %d\r\n" "UserAgent: %s", contact_uri, aor_name, expiration, contact_update->user_agent); ao2_link(contacts, contact_update); ao2_cleanup(contact_update); } else { if (contact->prune_on_boot) { struct contact_transport_monitor *monitor; const char *contact_name = ast_sorcery_object_get_id(contact); monitor = ast_alloca(sizeof(*monitor) + 2 + strlen(aor_name) + strlen(contact_name)); strcpy(monitor->aor_name, aor_name);/* Safe */ monitor->contact_name = monitor->aor_name + strlen(aor_name) + 1; strcpy(monitor->contact_name, contact_name);/* Safe */ ast_sip_transport_monitor_unregister(rdata->tp_info.transport, register_contact_transport_shutdown_cb, monitor, contact_transport_monitor_matcher); } /* We want to report the user agent that was actually in the removed contact */ ast_sip_location_delete_contact(contact); ast_verb(3, "Removed contact '%s' from AOR '%s' due to request\n", contact_uri, aor_name); ast_test_suite_event_notify("AOR_CONTACT_REMOVED", "Contact: %s\r\n" "AOR: %s\r\n" "UserAgent: %s", contact_uri, aor_name, contact->user_agent); } } pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool); /* * If the AOR is configured to remove any contacts over max_contacts * that have not been updated/added/deleted as a result of this * REGISTER do so. * * The existing contacts container holds all contacts that were not * involved in this REGISTER. * The contacts container holds the current contacts of the AOR. */ if (aor->remove_existing && existing_contacts) { /* Total contacts after this registration */ contact_count = ao2_container_count(existing_contacts) + updated + added; if (contact_count > aor->max_contacts) { /* Remove excess existing contacts that expire the soonest */ remove_excess_contacts(existing_contacts, contacts, contact_count - aor->max_contacts); } ao2_ref(existing_contacts, -1); } response_contact = ao2_callback(contacts, 0, NULL, NULL); /* Send a response containing all of the contacts (including static) that are present on this AOR */ if (ast_sip_create_response(rdata, 200, response_contact, &tdata) != PJ_SUCCESS) { ao2_cleanup(response_contact); ao2_cleanup(contacts); response->code = 500; return; } ao2_cleanup(response_contact); /* Add the date header to the response, some UAs use this to set their date and time */ registrar_add_date_header(tdata); ao2_callback(contacts, 0, registrar_add_contact, tdata); if ((expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL))) { expires_hdr = pjsip_expires_hdr_create(tdata->pool, registrar_get_expiration(aor, NULL, rdata)); pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)expires_hdr); } response->tdata = tdata; }
/* * udp_on_read_complete() * * This is callback notification from ioqueue that a pending recvfrom() * operation has completed. */ static void udp_on_read_complete( pj_ioqueue_key_t *key, pj_ioqueue_op_key_t *op_key, pj_ssize_t bytes_read) { /* See https://trac.pjsip.org/repos/ticket/1197 */ enum { MAX_IMMEDIATE_PACKET = 50 }; pjsip_rx_data_op_key *rdata_op_key = (pjsip_rx_data_op_key*) op_key; pjsip_rx_data *rdata = rdata_op_key->rdata; struct udp_transport *tp = (struct udp_transport*)rdata->tp_info.transport; int i; pj_status_t status; /* Don't do anything if transport is closing. */ if (tp->is_closing) { tp->is_closing++; return; } /* Don't do anything if transport is being paused. */ if (tp->is_paused) return; /* * The idea of the loop is to process immediate data received by * pj_ioqueue_recvfrom(), as long as i < MAX_IMMEDIATE_PACKET. When * i is >= MAX_IMMEDIATE_PACKET, we force the recvfrom() operation to * complete asynchronously, to allow other sockets to get their data. */ for (i=0;; ++i) { enum { MIN_SIZE = 32 }; pj_uint32_t flags; /* Report the packet to transport manager. Only do so if packet size * is relatively big enough for a SIP packet. */ if (bytes_read > MIN_SIZE) { pj_ssize_t size_eaten; const pj_sockaddr *src_addr = &rdata->pkt_info.src_addr; /* Init pkt_info part. */ rdata->pkt_info.len = bytes_read; rdata->pkt_info.zero = 0; pj_gettimeofday(&rdata->pkt_info.timestamp); if (src_addr->addr.sa_family == pj_AF_INET()) { pj_ansi_strcpy(rdata->pkt_info.src_name, pj_inet_ntoa(src_addr->ipv4.sin_addr)); rdata->pkt_info.src_port = pj_ntohs(src_addr->ipv4.sin_port); } else { pj_inet_ntop(pj_AF_INET6(), pj_sockaddr_get_addr(&rdata->pkt_info.src_addr), rdata->pkt_info.src_name, sizeof(rdata->pkt_info.src_name)); rdata->pkt_info.src_port = pj_ntohs(src_addr->ipv6.sin6_port); } size_eaten = pjsip_tpmgr_receive_packet(rdata->tp_info.transport->tpmgr, rdata); if (size_eaten < 0) { pj_assert(!"It shouldn't happen!"); size_eaten = rdata->pkt_info.len; } /* Since this is UDP, the whole buffer is the message. */ rdata->pkt_info.len = 0; } else if (bytes_read <= MIN_SIZE) { /* TODO: */ } else if (-bytes_read != PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK) && -bytes_read != PJ_STATUS_FROM_OS(OSERR_EINPROGRESS) && -bytes_read != PJ_STATUS_FROM_OS(OSERR_ECONNRESET)) { /* Report error to endpoint. */ PJSIP_ENDPT_LOG_ERROR((rdata->tp_info.transport->endpt, rdata->tp_info.transport->obj_name, (pj_status_t)-bytes_read, "Warning: pj_ioqueue_recvfrom()" " callback error")); } if (i >= MAX_IMMEDIATE_PACKET) { /* Force ioqueue_recvfrom() to return PJ_EPENDING */ flags = PJ_IOQUEUE_ALWAYS_ASYNC; } else { flags = 0; } /* Reset pool. * Need to copy rdata fields to temp variable because they will * be invalid after pj_pool_reset(). */ { pj_pool_t *rdata_pool = rdata->tp_info.pool; struct udp_transport *rdata_tp ; unsigned rdata_index; rdata_tp = (struct udp_transport*)rdata->tp_info.transport; rdata_index = (unsigned)(unsigned long)(pj_ssize_t) rdata->tp_info.tp_data; pj_pool_reset(rdata_pool); init_rdata(rdata_tp, rdata_index, rdata_pool, &rdata); /* Change some vars to point to new location after * pool reset. */ op_key = &rdata->tp_info.op_key.op_key; } /* Only read next packet if transport is not being paused. This * check handles the case where transport is paused while endpoint * is still processing a SIP message. */ if (tp->is_paused) return; /* Read next packet. */ bytes_read = sizeof(rdata->pkt_info.packet); rdata->pkt_info.src_addr_len = sizeof(rdata->pkt_info.src_addr); status = pj_ioqueue_recvfrom(key, op_key, rdata->pkt_info.packet, &bytes_read, flags, &rdata->pkt_info.src_addr, &rdata->pkt_info.src_addr_len); if (status == PJ_SUCCESS) { /* Continue loop. */ pj_assert(i < MAX_IMMEDIATE_PACKET); } else if (status == PJ_EPENDING) { break; } else { if (i < MAX_IMMEDIATE_PACKET) { /* Report error to endpoint if this is not EWOULDBLOCK error.*/ if (status != PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK) && status != PJ_STATUS_FROM_OS(OSERR_EINPROGRESS) && status != PJ_STATUS_FROM_OS(OSERR_ECONNRESET)) { PJSIP_ENDPT_LOG_ERROR((rdata->tp_info.transport->endpt, rdata->tp_info.transport->obj_name, status, "Warning: pj_ioqueue_recvfrom")); } /* Continue loop. */ bytes_read = 0; } else { /* This is fatal error. * Ioqueue operation will stop for this transport! */ PJSIP_ENDPT_LOG_ERROR((rdata->tp_info.transport->endpt, rdata->tp_info.transport->obj_name, status, "FATAL: pj_ioqueue_recvfrom() error, " "UDP transport stopping! Error")); break; } } } }
static int server_thread_proc(void *p) { struct stun_test_session *test_sess = (struct stun_test_session*)p; pj_pool_t *pool; pj_status_t status; PJ_LOG(4,(THIS_FILE, "Server thread running")); pool = pj_pool_create(test_sess->stun_cfg.pf, "server", 512, 512, NULL); while (!test_sess->thread_quit_flag) { pj_time_val timeout = {0, 10}; pj_fd_set_t rdset; int n; /* Serve client */ PJ_FD_ZERO(&rdset); PJ_FD_SET(test_sess->server_sock, &rdset); n = pj_sock_select(test_sess->server_sock+1, &rdset, NULL, NULL, &timeout); if (n==1 && PJ_FD_ISSET(test_sess->server_sock, &rdset)) { pj_uint8_t pkt[512]; pj_ssize_t pkt_len; pj_size_t res_len; pj_sockaddr client_addr; int addr_len; pj_stun_msg *stun_req, *stun_res; pj_pool_reset(pool); /* Got query */ pkt_len = sizeof(pkt); addr_len = sizeof(client_addr); status = pj_sock_recvfrom(test_sess->server_sock, pkt, &pkt_len, 0, &client_addr, &addr_len); if (status != PJ_SUCCESS) { continue; } status = pj_stun_msg_decode(pool, pkt, pkt_len, PJ_STUN_IS_DATAGRAM, &stun_req, NULL, NULL); if (status != PJ_SUCCESS) { PJ_PERROR(1,(THIS_FILE, status, "STUN request decode error")); continue; } status = pj_stun_msg_create_response(pool, stun_req, PJ_STUN_SC_BAD_REQUEST, NULL, &stun_res); if (status != PJ_SUCCESS) { PJ_PERROR(1,(THIS_FILE, status, "STUN create response error")); continue; } status = pj_stun_msg_encode(stun_res, pkt, sizeof(pkt), 0, NULL, &res_len); if (status != PJ_SUCCESS) { PJ_PERROR(1,(THIS_FILE, status, "STUN encode error")); continue; } /* Ignore request */ if (test_sess->param.server_drop_request) continue; /* Wait for signal to continue */ if (test_sess->param.server_wait_for_event) pj_event_wait(test_sess->server_event); pkt_len = res_len; pj_sock_sendto(test_sess->server_sock, pkt, &pkt_len, 0, &client_addr, pj_sockaddr_get_len(&client_addr)); } } pj_pool_release(pool); PJ_LOG(4,(THIS_FILE, "Server thread quitting")); return 0; }
// // Reset pool. // void reset() { pj_pool_reset(p_); }
static void cpool_release_pool( pj_pool_factory *pf, pj_pool_t *pool) { pj_caching_pool *cp = (pj_caching_pool*)pf; unsigned pool_capacity; unsigned i; PJ_CHECK_STACK(); PJ_ASSERT_ON_FAIL(pf && pool, return); pj_lock_acquire(cp->lock); #if PJ_SAFE_POOL /* Make sure pool is still in our used list */ if (pj_list_find_node(&cp->used_list, pool) != pool) { pj_assert(!"Attempt to destroy pool that has been destroyed before"); return; } #endif /* Erase from the used list. */ pj_list_erase(pool); /* Decrement used count. */ --cp->used_count; pool_capacity = pj_pool_get_capacity(pool); /* Destroy the pool if the size is greater than our size or if the total * capacity in our recycle list (plus the size of the pool) exceeds * maximum capacity. . */ if (pool_capacity > pool_sizes[PJ_CACHING_POOL_ARRAY_SIZE-1] || cp->capacity + pool_capacity > cp->max_capacity) { pj_pool_destroy_int(pool); pj_lock_release(cp->lock); return; } /* Reset pool. */ PJ_LOG(6, (pool->obj_name, "recycle(): cap=%d, used=%d(%d%%)", pool_capacity, pj_pool_get_used_size(pool), pj_pool_get_used_size(pool)*100/pool_capacity)); pj_pool_reset(pool); pool_capacity = pj_pool_get_capacity(pool); /* * Otherwise put the pool in our recycle list. */ i = (unsigned) (unsigned long) pool->factory_data; pj_assert(i<PJ_CACHING_POOL_ARRAY_SIZE); if (i >= PJ_CACHING_POOL_ARRAY_SIZE ) { /* Something has gone wrong with the pool. */ pj_pool_destroy_int(pool); pj_lock_release(cp->lock); return; } pj_list_insert_after(&cp->free_list[i], pool); cp->capacity += pool_capacity; pj_lock_release(cp->lock); }
/*! \brief Internal function which validates provided Contact headers to confirm that they are acceptable, and returns number of contacts */ static int registrar_validate_contacts(const pjsip_rx_data *rdata, pj_pool_t *pool, struct ao2_container *contacts, struct ast_sip_aor *aor, int permanent, int *added, int *updated, int *deleted) { pjsip_contact_hdr *previous = NULL; pjsip_contact_hdr *contact = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr; struct registrar_contact_details details = { .pool = pool, }; for (; (contact = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next)); pj_pool_reset(pool)) { int expiration = registrar_get_expiration(aor, contact, rdata); struct ast_sip_contact *existing; char contact_uri[pjsip_max_url_size]; if (contact->star) { /* The expiration MUST be 0 when a '*' contact is used and there must be no other contact */ if (expiration != 0 || previous) { return -1; } /* Count all contacts to delete */ *deleted = ao2_container_count(contacts) - permanent; previous = contact; continue; } else if (previous && previous->star) { /* If there is a previous contact and it is a '*' this is a deal breaker */ return -1; } previous = contact; if (!PJSIP_URI_SCHEME_IS_SIP(contact->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact->uri)) { continue; } details.uri = pjsip_uri_get_uri(contact->uri); /* pjsip_uri_print returns -1 if there's not enough room in the buffer */ if (pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri)) < 0) { /* If the total length of the uri is greater than pjproject can handle, go no further */ return -1; } if (details.uri->host.slen >= pj_max_hostname) { /* If the length of the hostname is greater than pjproject can handle, go no further */ return -1; } /* Determine if this is an add, update, or delete for policy enforcement purposes */ existing = ao2_callback(contacts, 0, registrar_find_contact, &details); ao2_cleanup(existing); if (!existing) { if (expiration) { ++*added; } } else if (expiration) { ++*updated; } else { ++*deleted; } } return 0; }
/* API: refresh the list of devices */ static pj_status_t and_factory_refresh(pjmedia_vid_dev_factory *ff) { and_factory *f = (and_factory*)ff; pj_status_t status = PJ_SUCCESS; JNIEnv *jni_env; pj_bool_t with_attach, found_front = PJ_FALSE; int i, dev_count = 0; /* Clean up device info and pool */ f->dev_count = 0; pj_pool_reset(f->dev_pool); with_attach = jni_get_env(&jni_env); /* dev_count = PjCameraInfo::GetCameraCount() */ dev_count = (*jni_env)->CallStaticIntMethod(jni_env, jobjs.cam_info.cls, jobjs.cam_info.m_get_cnt); if (dev_count < 0) { PJ_LOG(3, (THIS_FILE, "Failed to get camera count")); status = PJMEDIA_EVID_SYSERR; goto on_return; } /* Start querying device info */ f->dev_info = (and_dev_info*) pj_pool_calloc(f->dev_pool, dev_count, sizeof(and_dev_info)); for (i = 0; i < dev_count; i++) { and_dev_info *adi = &f->dev_info[f->dev_count]; pjmedia_vid_dev_info *vdi = &adi->info; jobject jdev_info; jobject jtmp; int facing, max_fmt_cnt = PJMEDIA_VID_DEV_INFO_FMT_CNT; /* jdev_info = PjCameraInfo::GetCameraInfo(i) */ jdev_info = (*jni_env)->CallStaticObjectMethod( jni_env, jobjs.cam_info.cls, jobjs.cam_info.m_get_info, i); if (jdev_info == NULL) continue; /* Get camera facing: 0=back 1=front */ facing = (*jni_env)->GetIntField(jni_env, jdev_info, jobjs.cam_info.f_facing); if (facing < 0) goto on_skip_dev; /* Set device ID, direction, and has_callback info */ adi->dev_idx = i; vdi->id = f->dev_count; vdi->dir = PJMEDIA_DIR_CAPTURE; vdi->has_callback = PJ_TRUE; vdi->caps = PJMEDIA_VID_DEV_CAP_SWITCH | PJMEDIA_VID_DEV_CAP_ORIENTATION; /* Set driver & name info */ pj_ansi_strncpy(vdi->driver, "Android", sizeof(vdi->driver)); adi->facing = facing; if (facing == 0) { pj_ansi_strncpy(vdi->name, "Back camera", sizeof(vdi->name)); } else { pj_ansi_strncpy(vdi->name, "Front camera", sizeof(vdi->name)); } /* Get supported sizes */ jtmp = (*jni_env)->GetObjectField(jni_env, jdev_info, jobjs.cam_info.f_sup_size); if (jtmp) { jintArray jiarray = (jintArray*)jtmp; jint *sizes; jsize cnt, j; cnt = (*jni_env)->GetArrayLength(jni_env, jiarray); sizes = (*jni_env)->GetIntArrayElements(jni_env, jiarray, 0); adi->sup_size_cnt = cnt/2; adi->sup_size = pj_pool_calloc(f->dev_pool, adi->sup_size_cnt, sizeof(adi->sup_size[0])); for (j = 0; j < adi->sup_size_cnt; j++) { adi->sup_size[j].w = sizes[j*2]; adi->sup_size[j].h = sizes[j*2+1]; } (*jni_env)->ReleaseIntArrayElements(jni_env, jiarray, sizes, 0); (*jni_env)->DeleteLocalRef(jni_env, jtmp); } else { goto on_skip_dev; } /* Get supported formats */ jtmp = (*jni_env)->GetObjectField(jni_env, jdev_info, jobjs.cam_info.f_sup_fmt); if (jtmp) { jintArray jiarray = (jintArray*)jtmp; jint *fmts; jsize cnt, j; pj_bool_t has_i420 = PJ_FALSE; cnt = (*jni_env)->GetArrayLength(jni_env, jiarray); fmts = (*jni_env)->GetIntArrayElements(jni_env, jiarray, 0); for (j = 0; j < cnt; j++) { int k; pjmedia_format_id fmt = and_fmt_to_pj((pj_uint32_t)fmts[j]); /* Check for any duplicate */ for (k = 0; k < vdi->fmt_cnt; k++) { if (fmt == 0 || fmt == vdi->fmt[k].id) { fmt = 0; break; } } /* Make sure we recognize this format */ if (fmt == 0) continue; /* Check formats for I420 conversion */ if (fmt == PJMEDIA_FORMAT_I420) has_i420 = PJ_TRUE; else if (fmt == PJMEDIA_FORMAT_YV12) adi->has_yv12 = PJ_TRUE; else if (fmt == PJMEDIA_FORMAT_NV21) adi->has_nv21 = PJ_TRUE; for (k = 0; k < adi->sup_size_cnt && vdi->fmt_cnt < max_fmt_cnt-1; k++) { /* Landscape video */ pjmedia_format_init_video(&vdi->fmt[vdi->fmt_cnt++], fmt, adi->sup_size[k].w, adi->sup_size[k].h, DEFAULT_FPS, 1); /* Portrait video */ pjmedia_format_init_video(&vdi->fmt[vdi->fmt_cnt++], fmt, adi->sup_size[k].h, adi->sup_size[k].w, DEFAULT_FPS, 1); } } (*jni_env)->ReleaseIntArrayElements(jni_env, jiarray, fmts, JNI_ABORT); (*jni_env)->DeleteLocalRef(jni_env, jtmp); /* Pretend to support I420/IYUV, only if we support YV12/NV21 */ if (!has_i420 && (adi->has_yv12 || adi->has_nv21) && vdi->fmt_cnt < PJ_ARRAY_SIZE(vdi->fmt)) { int k; adi->forced_i420 = PJ_TRUE; for (k = 0; k < adi->sup_size_cnt && vdi->fmt_cnt < max_fmt_cnt-1; k++) { pjmedia_format_init_video(&vdi->fmt[vdi->fmt_cnt++], PJMEDIA_FORMAT_I420, adi->sup_size[k].w, adi->sup_size[k].h, DEFAULT_FPS, 1); pjmedia_format_init_video(&vdi->fmt[vdi->fmt_cnt++], PJMEDIA_FORMAT_I420, adi->sup_size[k].h, adi->sup_size[k].w, DEFAULT_FPS, 1); } } } else { goto on_skip_dev; } /* If this is front camera, set it as first/default (if not yet) */ if (facing == 1) { if (!found_front && f->dev_count > 0) { /* Swap this front cam info with one whose idx==0 */ and_dev_info tmp_adi; pj_memcpy(&tmp_adi, &f->dev_info[0], sizeof(tmp_adi)); pj_memcpy(&f->dev_info[0], adi, sizeof(tmp_adi)); pj_memcpy(adi, &tmp_adi, sizeof(tmp_adi)); f->dev_info[0].info.id = 0; f->dev_info[f->dev_count].info.id = f->dev_count; } found_front = PJ_TRUE; } f->dev_count++; on_skip_dev: (*jni_env)->DeleteLocalRef(jni_env, jdev_info); } PJ_LOG(4, (THIS_FILE, "Android video capture initialized with %d device(s):", f->dev_count)); for (i = 0; i < f->dev_count; i++) { and_dev_info *adi = &f->dev_info[i]; char tmp_str[2048], *p; int j, plen, slen; PJ_LOG(4, (THIS_FILE, "%2d: %s", i, f->dev_info[i].info.name)); /* Print supported formats */ p = tmp_str; plen = sizeof(tmp_str); for (j = 0; j < adi->info.fmt_cnt; j++) { char tmp_str2[5]; const pjmedia_video_format_detail *vfd = pjmedia_format_get_video_format_detail(&adi->info.fmt[j], 0); pjmedia_fourcc_name(adi->info.fmt[j].id, tmp_str2); slen = pj_ansi_snprintf(p, plen, "%s/%dx%d ", tmp_str2, vfd->size.w, vfd->size.h); if (slen < 0 || slen >= plen) break; plen -= slen; p += slen; } PJ_LOG(4, (THIS_FILE, " supported format = %s", tmp_str)); } on_return: jni_detach_env(with_attach); return status; }
/* * Add new buddy. */ PJ_DEF(pj_status_t) pjsua_buddy_add( const pjsua_buddy_config *cfg, pjsua_buddy_id *p_buddy_id) { pjsip_name_addr *url; pjsua_buddy *buddy; pjsip_sip_uri *sip_uri; int index; pj_str_t tmp; PJ_ASSERT_RETURN(pjsua_var.buddy_cnt <= PJ_ARRAY_SIZE(pjsua_var.buddy), PJ_ETOOMANY); PJSUA_LOCK(); /* Find empty slot */ for (index=0; index<(int)PJ_ARRAY_SIZE(pjsua_var.buddy); ++index) { if (pjsua_var.buddy[index].uri.slen == 0) break; } /* Expect to find an empty slot */ if (index == PJ_ARRAY_SIZE(pjsua_var.buddy)) { PJSUA_UNLOCK(); /* This shouldn't happen */ pj_assert(!"index < PJ_ARRAY_SIZE(pjsua_var.buddy)"); return PJ_ETOOMANY; } buddy = &pjsua_var.buddy[index]; /* Create pool for this buddy */ if (buddy->pool) { pj_pool_reset(buddy->pool); } else { char name[PJ_MAX_OBJ_NAME]; pj_ansi_snprintf(name, sizeof(name), "buddy%03d", index); buddy->pool = pjsua_pool_create(name, 512, 256); } /* Init buffers for presence subscription status */ buddy->term_reason.ptr = (char*) pj_pool_alloc(buddy->pool, PJSUA_BUDDY_SUB_TERM_REASON_LEN); /* Get name and display name for buddy */ pj_strdup_with_null(buddy->pool, &tmp, &cfg->uri); url = (pjsip_name_addr*)pjsip_parse_uri(buddy->pool, tmp.ptr, tmp.slen, PJSIP_PARSE_URI_AS_NAMEADDR); if (url == NULL) { pjsua_perror(THIS_FILE, "Unable to add buddy", PJSIP_EINVALIDURI); pj_pool_release(buddy->pool); buddy->pool = NULL; PJSUA_UNLOCK(); return PJSIP_EINVALIDURI; } /* Only support SIP schemes */ if (!PJSIP_URI_SCHEME_IS_SIP(url) && !PJSIP_URI_SCHEME_IS_SIPS(url)) { pj_pool_release(buddy->pool); buddy->pool = NULL; PJSUA_UNLOCK(); return PJSIP_EINVALIDSCHEME; } /* Reset buddy, to make sure everything is cleared with default * values */ reset_buddy(index); /* Save URI */ pjsua_var.buddy[index].uri = tmp; sip_uri = (pjsip_sip_uri*) pjsip_uri_get_uri(url->uri); pjsua_var.buddy[index].name = sip_uri->user; pjsua_var.buddy[index].display = url->display; pjsua_var.buddy[index].host = sip_uri->host; pjsua_var.buddy[index].port = sip_uri->port; pjsua_var.buddy[index].monitor = cfg->subscribe; if (pjsua_var.buddy[index].port == 0) pjsua_var.buddy[index].port = 5060; /* Save user data */ pjsua_var.buddy[index].user_data = (void*)cfg->user_data; if (p_buddy_id) *p_buddy_id = index; pjsua_var.buddy_cnt++; PJSUA_UNLOCK(); pjsua_buddy_subscribe_pres(index, cfg->subscribe); return PJ_SUCCESS; }