void belle_sip_multipart_body_handler_progress_cb(belle_sip_body_handler_t *obj, belle_sip_message_t *msg, void *user_data, size_t transfered, size_t expected_total) { if (transfered == expected_total) { /* The full multipart body has been received, we can now parse it and split the different parts, * creating a belle_sip_memory_body_handler for each part and adding them to the belle_sip_multipart_body_handler * parts list. */ belle_sip_multipart_body_handler_t *obj_multipart = (belle_sip_multipart_body_handler_t *)obj; belle_sip_memory_body_handler_t *memorypart; belle_sip_header_t *header; uint8_t *end_part_cursor; uint8_t *end_headers_cursor; uint8_t *end_header_cursor; uint8_t *cursor = obj_multipart->buffer; char *boundary = belle_sip_strdup_printf("--%s", obj_multipart->boundary); if (strncmp((char *)cursor, boundary, strlen(boundary))) { belle_sip_warning("belle_sip_multipart_body_handler [%p]: body not starting by specified boundary '%s'", obj_multipart, obj_multipart->boundary); belle_sip_free(boundary); return; } cursor += strlen(boundary); do { if (strncmp((char *)cursor, "\r\n", 2)) { belle_sip_warning("belle_sip_multipart_body_handler [%p]: no new-line after boundary", obj_multipart); return; } cursor += 2; end_part_cursor = (uint8_t *)strstr((char *)cursor, boundary); if (end_part_cursor == NULL) { belle_sip_warning("belle_sip_multipart_body_handler [%p]: cannot find next boundary", obj_multipart); return; } else { *end_part_cursor = 0; end_headers_cursor = (uint8_t *)strstr((char *)cursor, "\r\n\r\n"); if (end_headers_cursor == NULL) { memorypart = belle_sip_memory_body_handler_new_copy_from_buffer(cursor, strlen((char *)cursor), NULL, NULL); } else { uint8_t *begin_body_cursor = end_headers_cursor + 4; memorypart = belle_sip_memory_body_handler_new_copy_from_buffer(begin_body_cursor, strlen((char *)begin_body_cursor), NULL, NULL); do { end_header_cursor = (uint8_t *)strstr((char *)cursor, "\r\n"); *end_header_cursor = 0; header = belle_sip_header_parse((char *)cursor); if (header != NULL) { belle_sip_body_handler_add_header(BELLE_SIP_BODY_HANDLER(memorypart), header); } cursor = end_header_cursor + 2; } while (end_header_cursor != end_headers_cursor); } belle_sip_multipart_body_handler_add_part(obj_multipart, BELLE_SIP_BODY_HANDLER(memorypart)); cursor = end_part_cursor + strlen(boundary); } } while (strcmp((char *)cursor, "--\r\n")); belle_sip_free(boundary); } }
static void register_tcp_test_ipv6_to_ipv6_with_ipv6(void){ if (!belle_sip_tester_ipv6_available()){ belle_sip_warning("Test skipped, IPv6 connectivity not available."); return; } register_test_with_interfaces("tcp","::0","::0",AF_INET6); }
static int register_test_with_random_port(const char *transport, const char *client_ip, const char *server_ip, int connection_family) { int ret=0; belle_sip_listener_callbacks_t client_callbacks; belle_sip_listener_callbacks_t server_callbacks; endpoint_t* client,*server; memset(&client_callbacks,0,sizeof(belle_sip_listener_callbacks_t)); memset(&server_callbacks,0,sizeof(belle_sip_listener_callbacks_t)); client_callbacks.process_response_event=client_process_response_event; client_callbacks.process_auth_requested=client_process_auth_requested; server_callbacks.process_request_event=server_process_request_event; client = create_endpoint(client_ip,-1,transport,&client_callbacks); client->connection_family=connection_family; client->register_count=1; server = create_endpoint(server_ip,6788,transport,&server_callbacks); server->expire_in_contact=client->expire_in_contact=0; server->auth=none; if (client->lp==NULL || server->lp==NULL){ belle_sip_warning("Cannot check ipv6 because host has no ipv6 support."); ret=-1; }else register_base(client,server); destroy_endpoint(client); destroy_endpoint(server); return ret; }
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END static void fix_incoming_via(belle_sip_request_t *msg, const struct addrinfo* origin){ char received[NI_MAXHOST]; char rport[NI_MAXSERV]; belle_sip_header_via_t *via; int err; struct sockaddr_storage saddr; socklen_t slen=sizeof(saddr); if (!origin) { belle_sip_warning("cannot fix via for message [%p], probably a test",msg); return; } belle_sip_address_remove_v4_mapping(origin->ai_addr, (struct sockaddr*)&saddr, &slen); err=getnameinfo((struct sockaddr*)&saddr,slen,received,sizeof(received), rport,sizeof(rport),NI_NUMERICHOST|NI_NUMERICSERV); if (err!=0){ belle_sip_error("fix_via: getnameinfo() failed: %s",gai_strerror(errno)); return; } via=BELLE_SIP_HEADER_VIA(belle_sip_message_get_header((belle_sip_message_t*)msg,"via")); if (via){ const char* host = belle_sip_header_via_get_host(via); if (strcmp(host,received)!=0) belle_sip_header_via_set_received(via,received); if (belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(via),"rport")){ int port = belle_sip_header_via_get_listening_port(via); int rport_int=atoi(rport); if (rport_int!=port) belle_sip_header_via_set_rport(via,atoi(rport)); } } }
static void ipv4_and_ipv6_dns_server(void) { struct addrinfo *ai; int timeout; endpoint_t *client; const char *nameservers[]={ "8.8.8.8", "2a01:e00::2", NULL }; if (!belle_sip_tester_ipv6_available()){ belle_sip_warning("Test skipped, IPv6 connectivity not available."); return; } client = create_endpoint(); CU_ASSERT_PTR_NOT_NULL_FATAL(client); timeout = belle_sip_stack_get_dns_timeout(client->stack); set_custom_resolv_conf(client->stack,nameservers); client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, IPV4_SIP_DOMAIN, SIP_PORT, AF_INET, a_resolve_done, client); CU_ASSERT_NOT_EQUAL(client->resolver_ctx, NULL); CU_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout)); CU_ASSERT_PTR_NOT_EQUAL(client->ai_list, NULL); if (client->ai_list) { struct sockaddr_in *sock_in = (struct sockaddr_in *)client->ai_list->ai_addr; CU_ASSERT_EQUAL(ntohs(sock_in->sin_port), SIP_PORT); ai = belle_sip_ip_address_to_addrinfo(AF_INET, IPV4_SIP_IP, SIP_PORT); if (ai) { CU_ASSERT_EQUAL(sock_in->sin_addr.s_addr, ((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr); belle_sip_freeaddrinfo(ai); } } destroy_endpoint(client); }
static void test_certificate_fingerprint(void) { char *fingerprint; belle_sip_certificates_chain_t *cert; /* check underlying bctoolbox function availability */ if (bctoolbox_x509_certificate_get_fingerprint(NULL, NULL, 0, 0) == BCTOOLBOX_ERROR_UNAVAILABLE_FUNCTION) { belle_sip_warning("Test skipped, certificate fingerprint generation not available."); return; } /* parse certificate defined in belle_sip_register_tester.c */ cert = belle_sip_certificates_chain_parse(belle_sip_tester_client_cert,strlen(belle_sip_tester_client_cert),BELLE_SIP_CERTIFICATE_RAW_FORMAT_PEM); /* generate fingerprint */ fingerprint = belle_sip_certificates_chain_get_fingerprint(cert); BC_ASSERT_TRUE_FATAL(fingerprint!=NULL); BC_ASSERT_STRING_EQUAL(fingerprint, belle_sip_tester_client_cert_fingerprint); belle_sip_free(fingerprint); belle_sip_object_unref(cert); /* parse certificate defined above, signing algo is sha256 */ cert = belle_sip_certificates_chain_parse(belle_sip_tester_fingerprint256_cert,strlen(belle_sip_tester_fingerprint256_cert),BELLE_SIP_CERTIFICATE_RAW_FORMAT_PEM); /* generate fingerprint */ fingerprint = belle_sip_certificates_chain_get_fingerprint(cert); BC_ASSERT_TRUE_FATAL(fingerprint!=NULL); BC_ASSERT_STRING_EQUAL(fingerprint, belle_sip_tester_fingerprint256_cert_fingerprint); belle_sip_free(fingerprint); belle_sip_object_unref(cert); }
static void http_channel_context_handle_io_error(belle_http_channel_context_t *ctx, belle_sip_channel_t *chan){ belle_http_request_t *req=NULL; belle_sip_io_error_event_t ev={0}; belle_sip_list_t *elem; /*if the error happens before attempting to send the message, the pending_requests is empty*/ if (ctx->pending_requests==NULL) elem=chan->outgoing_messages; else elem=ctx->pending_requests; /*pop the requests for which this error is reported*/ for(;elem!=NULL;elem=elem->next){ req=(belle_http_request_t *)elem->data; /*else notify the app about the response received*/ /*TODO: would be nice to put the message in the event*/ ev.source=(belle_sip_object_t*)ctx->provider; ev.host=chan->peer_cname; ev.port=chan->peer_port; ev.transport=belle_sip_channel_get_transport_name(chan); BELLE_HTTP_REQUEST_INVOKE_LISTENER(req,process_io_error,&ev); if( req->background_task_id ){ belle_sip_warning("IO Error on HTTP request: ending bg task id=[%x]", req->background_task_id); belle_sip_end_background_task(req->background_task_id); req->background_task_id = 0; } } }
static void register_tcp_test_ipv6_random_port(void){ if (!belle_sip_tester_ipv6_available()){ belle_sip_warning("Test skipped, IPv6 connectivity not available."); return; } register_test_with_random_port("tcp","::0","0.0.0.0",AF_INET); }
static int set_expires_from_trans(belle_sip_refresher_t* refresher) { belle_sip_transaction_t* transaction = BELLE_SIP_TRANSACTION(refresher->transaction); belle_sip_response_t*response=transaction->last_response; belle_sip_request_t*request=belle_sip_transaction_get_request(transaction); belle_sip_header_expires_t* expires_header=belle_sip_message_get_header_by_type(request,belle_sip_header_expires_t); belle_sip_header_contact_t* contact_header; refresher->obtained_expires=-1; if (strcmp("REGISTER",belle_sip_request_get_method(request))==0 || expires_header /*if request has an expire header, refresher can always work*/) { if (expires_header) refresher->target_expires = belle_sip_header_expires_get_expires(expires_header); /*An "expires" parameter on the "Contact" header has no semantics for * SUBSCRIBE and is explicitly not equivalent to an "Expires" header in * a SUBSCRIBE request or response. */ if (strcmp("REGISTER",belle_sip_request_get_method(request))==0){ if (!expires_header && (contact_header=belle_sip_message_get_header_by_type((belle_sip_message_t*)request,belle_sip_header_contact_t))){ int ct_expires=belle_sip_header_contact_get_expires(BELLE_SIP_HEADER_CONTACT(contact_header)); if (ct_expires!=-1) refresher->target_expires=ct_expires; } /*check in response also to get the obtained expires*/ if ((contact_header=belle_sip_refresher_get_contact(refresher))!=NULL){ /*matching contact, check for its possible expires param*/ refresher->obtained_expires=belle_sip_header_contact_get_expires(BELLE_SIP_HEADER_CONTACT(contact_header)); } } if (refresher->obtained_expires==-1){ /*no contact with expire or not relevant, looking for Expires header*/ if (response && (expires_header=(belle_sip_header_expires_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_EXPIRES))) { refresher->obtained_expires = belle_sip_header_expires_get_expires(expires_header); } } if (refresher->obtained_expires==-1) { belle_sip_message("Neither Expires header nor corresponding Contact header found, checking from original request"); refresher->obtained_expires=refresher->target_expires; }else if (refresher->target_expires>0 && refresher->obtained_expires==0){ const char* reason = response ? belle_sip_response_get_reason_phrase(response) : NULL; /*check this case because otherwise we are going to loop fast in sending refresh requests.*/ /*"Test account created" is a special reason given by testers when we create temporary account. Since this is a bit of hack, we can ignore logging in that case*/ if (reason && strcmp(reason, "Test account created") != 0) { belle_sip_warning("Server replied with 0 expires, what does that mean?"); } /*suppose it's a server bug and assume our target_expires is understood.*/ refresher->obtained_expires=refresher->target_expires; } } else if (strcmp("INVITE",belle_sip_request_get_method(request))==0) { belle_sip_error("Refresher does not support INVITE yet"); return -1; } else { belle_sip_error("Refresher does not support [%s] yet",belle_sip_request_get_method(request)); return -1; } return 0; }
static void belle_http_end_background_task(void* data) { belle_http_request_t *req = BELLE_HTTP_REQUEST(data); belle_sip_warning("Ending unfinished HTTP transfer background task id=[%x]", req->background_task_id); if( req->background_task_id ){ belle_sip_end_background_task(req->background_task_id); req->background_task_id = 0; } }
static void check_route_set(belle_sip_list_t *rs){ if (rs){ belle_sip_header_route_t *r=(belle_sip_header_route_t*)rs->data; if (!belle_sip_uri_has_lr_param(belle_sip_header_address_get_uri((belle_sip_header_address_t*)r))){ belle_sip_warning("top uri of route set does not contain 'lr', not really supported."); } } }
static int belle_sip_user_body_handler_send_chunk(belle_sip_body_handler_t *base, belle_sip_message_t *msg, size_t offset, uint8_t *buf, size_t *size){ belle_sip_user_body_handler_t *obj=(belle_sip_user_body_handler_t*)base; if (obj->send_cb) return obj->send_cb((belle_sip_user_body_handler_t*)base, msg, base->user_data, offset, buf, size); else belle_sip_warning("belle_sip_user_body_handler_t ignoring send chunk."); *size=0; return BELLE_SIP_STOP; }
int belle_sip_socket_enable_dual_stack(belle_sip_socket_t sock){ int value=0; int err=setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&value, sizeof(value)); if (err==-1){ belle_sip_warning("belle_sip_socket_enable_dual_stack: setsockopt(IPV6_ONLY) failed: %s",belle_sip_get_socket_error_string()); } return err; }
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END static belle_sip_socket_t create_udp_socket(const char *addr, int *port, int *family){ struct addrinfo hints={0}; struct addrinfo *res=NULL; int err; belle_sip_socket_t sock; char portnum[10]; int optval=1; if (*port==-1) *port=0; /*random port for bind()*/ snprintf(portnum,sizeof(portnum),"%i",*port); hints.ai_family=AF_UNSPEC; hints.ai_socktype=SOCK_DGRAM; hints.ai_protocol=IPPROTO_UDP; hints.ai_flags=AI_NUMERICSERV; err=getaddrinfo(addr,portnum,&hints,&res); if (err!=0){ belle_sip_error("getaddrinfo() failed for %s port %i: %s",addr,*port,gai_strerror(err)); return -1; } *family=res->ai_family; sock=socket(res->ai_family,res->ai_socktype,res->ai_protocol); if (sock==-1){ belle_sip_error("Cannot create UDP socket: %s",belle_sip_get_socket_error_string()); freeaddrinfo(res); return -1; } err = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&optval, sizeof (optval)); if (err == -1){ belle_sip_warning ("Fail to set SIP/UDP address reusable: %s.", belle_sip_get_socket_error_string()); } err=bind(sock,res->ai_addr,res->ai_addrlen); if (err==-1){ belle_sip_error("udp bind() failed for %s port %i: %s",addr,*port,belle_sip_get_socket_error_string()); close_socket(sock); freeaddrinfo(res); return -1; } freeaddrinfo(res); if (*port==0){ struct sockaddr_storage saddr; socklen_t saddr_len=sizeof(saddr); err=getsockname(sock,(struct sockaddr*)&saddr,&saddr_len); if (err==0){ err=getnameinfo((struct sockaddr*)&saddr,saddr_len,NULL,0,portnum,sizeof(portnum),NI_NUMERICSERV|NI_NUMERICHOST); if (err==0){ *port=atoi(portnum); belle_sip_message("Random UDP port is %i",*port); }else belle_sip_error("udp bind failed, getnameinfo(): %s",gai_strerror(err)); }else belle_sip_error("udp bind failed, getsockname(): %s",belle_sip_get_socket_error_string()); } return sock; }
/* Successful IPv6 AAAA query */ static void ipv6_aaaa_query(void) { struct addrinfo *ai; int timeout; endpoint_t *client; if (!belle_sip_tester_ipv6_available()){ belle_sip_warning("Test skipped, IPv6 connectivity not available."); return; } client = create_endpoint(); if (!BC_ASSERT_PTR_NOT_NULL(client)) return; timeout = belle_sip_stack_get_dns_timeout(client->stack); client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, IPV6_SIP_DOMAIN, SIP_PORT, AF_INET6, a_resolve_done, client); BC_ASSERT_PTR_NOT_NULL(client->resolver_ctx); BC_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout)); BC_ASSERT_PTR_NOT_EQUAL(client->ai_list, NULL); if (client->ai_list) { struct addrinfo *next; struct sockaddr_in6 *sock_in6 = (struct sockaddr_in6 *)client->ai_list->ai_addr; int ntohsi = ntohs(sock_in6->sin6_port); BC_ASSERT_EQUAL(ntohsi, SIP_PORT, int, "%d"); /*the IPv6 address shall return first, and must be a real ipv6 address*/ BC_ASSERT_EQUAL(client->ai_list->ai_family,AF_INET6,int,"%d"); BC_ASSERT_FALSE(IN6_IS_ADDR_V4MAPPED(&sock_in6->sin6_addr)); ai = bctbx_ip_address_to_addrinfo(AF_INET6, SOCK_STREAM, IPV6_SIP_IP, SIP_PORT); BC_ASSERT_PTR_NOT_NULL(ai); if (ai) { struct in6_addr *ipv6_address = &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr; int i; for (i = 0; i < 8; i++) { BC_ASSERT_EQUAL(sock_in6->sin6_addr.s6_addr[i], ipv6_address->s6_addr[i], int, "%d"); } bctbx_freeaddrinfo(ai); } next=client->ai_list->ai_next; BC_ASSERT_PTR_NOT_NULL(next); if (next){ int ntohsi = ntohs(sock_in6->sin6_port); sock_in6 = (struct sockaddr_in6 *)next->ai_addr; BC_ASSERT_EQUAL(next->ai_family,AF_INET6,int,"%d"); BC_ASSERT_TRUE(IN6_IS_ADDR_V4MAPPED(&sock_in6->sin6_addr)); BC_ASSERT_EQUAL(ntohsi, SIP_PORT, int, "%d"); ai = bctbx_ip_address_to_addrinfo(AF_INET6, SOCK_STREAM, IPV6_SIP_IPV4, SIP_PORT); BC_ASSERT_PTR_NOT_NULL(ai); if (ai) { struct in6_addr *ipv6_address = &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr; int i; for (i = 0; i < 8; i++) { BC_ASSERT_EQUAL(sock_in6->sin6_addr.s6_addr[i], ipv6_address->s6_addr[i], int, "%d"); } bctbx_freeaddrinfo(ai); } } } destroy_endpoint(client); }
belle_sip_list_t* _belle_sip_list_remove(belle_sip_list_t* first, void *data, int warn_if_not_found){ belle_sip_list_t* it; it=belle_sip_list_find(first,data); if (it) return belle_sip_list_delete_link(first,it); else if (warn_if_not_found){ belle_sip_warning("belle_sip_list_remove: no element with %p data was in the list", data); } return first; }
int belle_sip_dialog_check_incoming_request_ordering(belle_sip_dialog_t *obj, belle_sip_request_t *req){ belle_sip_header_cseq_t *cseqh=belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t); unsigned int cseq=belle_sip_header_cseq_get_seq_number(cseqh); if (obj->remote_cseq==0){ obj->remote_cseq=cseq; }else if (cseq>obj->remote_cseq){ return 0; } belle_sip_warning("Ignoring request because cseq is inconsistent."); return -1; }
void belle_sip_dialog_delete(belle_sip_dialog_t *obj){ int dropped_transactions; belle_sip_dialog_stop_200Ok_retrans(obj); /*if any*/ set_state(obj,BELLE_SIP_DIALOG_TERMINATED); dropped_transactions=belle_sip_list_size(obj->queued_ct); if (dropped_transactions>0) belle_sip_warning("dialog [%p]: leaves %i queued transaction aborted.",obj,dropped_transactions); belle_sip_list_for_each(obj->queued_ct,(void(*)(void*))belle_sip_transaction_terminate); obj->queued_ct=belle_sip_list_free_with_data(obj->queued_ct,belle_sip_object_unref); belle_sip_provider_remove_dialog(obj->provider,obj); }
void belle_sip_main_loop_run(belle_sip_main_loop_t *ml){ if (ml->in_loop){ belle_sip_warning("belle_sip_main_loop_run(): reentrancy detected, doing nothing"); return; } ml->run = TRUE; ml->in_loop = TRUE; while(ml->run){ belle_sip_main_loop_iterate(ml); } ml->in_loop = FALSE; }
static void process_dialog_terminated(belle_sip_listener_t *user_ctx, const belle_sip_dialog_terminated_event_t *event){ belle_sip_refresher_t* refresher=(belle_sip_refresher_t*)user_ctx; belle_sip_dialog_t *dialog =belle_sip_dialog_terminated_event_get_dialog(event); if (refresher && refresher->transaction && dialog != belle_sip_transaction_get_dialog(BELLE_SIP_TRANSACTION(refresher->transaction))) return; /*not for me*/ if (refresher->state == started) { belle_sip_warning("Refresher [%p] still started but receiving unexpected dialog deleted event on [%p], retrying",refresher,dialog); retry_later_on_io_error(refresher); if (refresher->listener) refresher->listener(refresher,refresher->user_data,481, "dialod terminated"); } }
void belle_sip_transaction_notify_timeout(belle_sip_transaction_t *t){ /*report the channel as possibly dead. If an alternate IP can be tryied, the channel will notify us with the RETRY state. * Otherwise it will report the error. * We limit this dead channel reporting to REGISTER transactions, who are unlikely to be unresponded. **/ belle_sip_warning("Transaction [%p] reporting timeout, reporting to channel.",t); if (strcmp(belle_sip_request_get_method(t->request),"REGISTER")==0 && belle_sip_channel_notify_timeout(t->channel)==TRUE){ t->timed_out=TRUE; }else { notify_timeout(t); belle_sip_transaction_terminate(t); } }
static int tls_process_data(belle_sip_channel_t *obj,unsigned int revents){ belle_sip_tls_channel_t* channel=(belle_sip_tls_channel_t*)obj; if (obj->state == BELLE_SIP_CHANNEL_CONNECTING ) { if (!channel->socket_connected) { channel->socklen=sizeof(channel->ss); if (finalize_stream_connection((belle_sip_stream_channel_t*)obj,revents,(struct sockaddr*)&channel->ss,&channel->socklen)) { goto process_error; } belle_sip_message("Channel [%p]: Connected at TCP level, now doing TLS handshake",obj); channel->socket_connected=1; belle_sip_source_set_events((belle_sip_source_t*)channel,BELLE_SIP_EVENT_READ|BELLE_SIP_EVENT_ERROR); belle_sip_source_set_timeout((belle_sip_source_t*)obj,belle_sip_stack_get_transport_timeout(obj->stack)); if (tls_process_handshake(obj)==-1) goto process_error; }else{ if (revents & BELLE_SIP_EVENT_READ){ if (tls_process_handshake(obj)==-1) goto process_error; }else if (revents==BELLE_SIP_EVENT_TIMEOUT){ belle_sip_error("channel [%p]: SSL handshake took too much time.",obj); goto process_error; }else{ belle_sip_warning("channeEHHCXCCCl [%p]: unexpected event [%i] during TLS handshake.",obj,revents); } } } else if ( obj->state == BELLE_SIP_CHANNEL_READY) { return belle_sip_channel_process_data(obj,revents); } else { belle_sip_warning("Unexpected event [%i], for channel [%p]",revents,channel); return BELLE_SIP_STOP; } return BELLE_SIP_CONTINUE; process_error: belle_sip_error("Cannot connect to [%s://%s:%i]",belle_sip_channel_get_transport_name(obj),obj->peer_name,obj->peer_port); channel_set_state(obj,BELLE_SIP_CHANNEL_ERROR); return BELLE_SIP_STOP; }
static void http_channel_context_handle_response(belle_http_channel_context_t *ctx , belle_sip_channel_t *chan, belle_http_response_t *response){ belle_http_request_t *req=NULL; belle_http_response_event_t ev={0}; int code; belle_sip_header_t *connection; /*pop the request matching this response*/ ctx->pending_requests=belle_sip_list_pop_front(ctx->pending_requests,(void**)&req); if (req==NULL){ belle_sip_error("Receiving http response not matching any request."); return; } if (belle_http_request_is_cancelled(req)) { belle_sip_warning("Receiving http response for a cancelled request."); return; } connection=belle_sip_message_get_header((belle_sip_message_t *)response,"Connection"); if (connection && strstr(belle_sip_header_get_unparsed_value(connection),"close")!=NULL) chan->about_to_be_closed=TRUE; belle_http_request_set_response(req,response); code=belle_http_response_get_status_code(response); if ((code==401 || code==407) && http_channel_context_handle_authentication(ctx,req)==0 ){ /*nothing to do, the request has been resubmitted with authentication*/ }else{ /*else notify the app about the response received*/ ev.source=(belle_sip_object_t*)ctx->provider; ev.request=req; ev.response=response; BELLE_HTTP_REQUEST_INVOKE_LISTENER(req,process_response,&ev); if( req->background_task_id ){ belle_sip_warning("HTTP request finished: ending bg task id=[%x]", req->background_task_id); belle_sip_end_background_task(req->background_task_id); req->background_task_id = 0; } } belle_sip_object_unref(req); }
static void test_generate_and_parse_certificates(void) { belle_sip_certificates_chain_t *certificate, *parsed_certificate; belle_sip_signing_key_t *key, *parsed_key; char *pem_certificate, *pem_parsed_certificate, *pem_key, *pem_parsed_key; int ret = 0; char *belle_sip_certificate_temporary_dir = bc_tester_file(TEMPORARY_CERTIFICATE_DIR); /* create 2 certificates in the temporary certificate directory (TODO : set the directory in a absolute path?? where?)*/ ret = belle_sip_generate_self_signed_certificate(belle_sip_certificate_temporary_dir, "test_certificate1", &certificate, &key); if (ret == BCTOOLBOX_ERROR_UNAVAILABLE_FUNCTION) { belle_sip_warning("Test skipped, self signed certificate generation not available."); return; } BC_ASSERT_EQUAL_FATAL(0, ret, int, "%d"); belle_sip_object_unref(certificate); belle_sip_object_unref(key); ret = belle_sip_generate_self_signed_certificate(belle_sip_certificate_temporary_dir, "test_certificate2", &certificate, &key); BC_ASSERT_EQUAL_FATAL(0, ret, int, "%d"); /* parse directory to get the certificate2 */ ret = belle_sip_get_certificate_and_pkey_in_dir(belle_sip_certificate_temporary_dir, "test_certificate2", &parsed_certificate, &parsed_key, BELLE_SIP_CERTIFICATE_RAW_FORMAT_PEM); free(belle_sip_certificate_temporary_dir); BC_ASSERT_EQUAL_FATAL(0, ret, int, "%d"); /* get pem version of generated and parsed certificate and compare them */ pem_certificate = belle_sip_certificates_chain_get_pem(certificate); BC_ASSERT_TRUE_FATAL(pem_certificate!=NULL); pem_parsed_certificate = belle_sip_certificates_chain_get_pem(parsed_certificate); BC_ASSERT_TRUE_FATAL(pem_parsed_certificate!=NULL); BC_ASSERT_STRING_EQUAL(pem_certificate, pem_parsed_certificate); /* get pem version of generated and parsed key and compare them */ pem_key = belle_sip_signing_key_get_pem(key); BC_ASSERT_TRUE_FATAL(pem_key!=NULL); pem_parsed_key = belle_sip_signing_key_get_pem(parsed_key); BC_ASSERT_TRUE_FATAL(pem_parsed_key!=NULL); BC_ASSERT_STRING_EQUAL(pem_key, pem_parsed_key); belle_sip_free(pem_certificate); belle_sip_free(pem_parsed_certificate); belle_sip_free(pem_key); belle_sip_free(pem_parsed_key); belle_sip_object_unref(certificate); belle_sip_object_unref(parsed_certificate); belle_sip_object_unref(key); belle_sip_object_unref(parsed_key); }
static void callee_process_request_event(void *user_ctx, const belle_sip_request_event_t *event) { belle_sip_dialog_t* dialog; belle_sip_response_t* ringing_response; belle_sip_header_content_type_t* content_type ; belle_sip_header_content_length_t* content_length; belle_sip_server_transaction_t* server_transaction = belle_sip_request_event_get_server_transaction(event); belle_sip_header_to_t* to=belle_sip_message_get_header_by_type(belle_sip_request_event_get_request(event),belle_sip_header_to_t); const char* method; if (!belle_sip_uri_equals(BELLE_SIP_URI(user_ctx),belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(to)))) { belle_sip_message("Message [%p] not for callee, skipping",belle_sip_request_event_get_request(event)); return; /*not for the callee*/ } method = belle_sip_request_get_method(belle_sip_request_event_get_request(event)); if (!server_transaction && strcmp(method,"ACK")!=0) { server_transaction= belle_sip_provider_create_server_transaction(prov,belle_sip_request_event_get_request(event)); } belle_sip_message("callee_process_request_event received [%s] message",method); dialog = belle_sip_request_event_get_dialog(event); if (!dialog ) { BC_ASSERT_STRING_EQUAL_FATAL("INVITE",method); dialog=belle_sip_provider_create_dialog(prov,BELLE_SIP_TRANSACTION(server_transaction)); callee_dialog=dialog; inserv_transaction=server_transaction; } if (belle_sip_dialog_get_state(dialog) == BELLE_SIP_DIALOG_NULL) { ringing_response = belle_sip_response_create_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(server_transaction)),180); /*prepare 200ok*/ ok_response = belle_sip_response_create_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(server_transaction)),200); content_length= belle_sip_header_content_length_create(strlen(sdp)); content_type = belle_sip_header_content_type_create("application","sdp"); belle_sip_message_add_header(BELLE_SIP_MESSAGE(ok_response),BELLE_SIP_HEADER(content_type)); belle_sip_message_add_header(BELLE_SIP_MESSAGE(ok_response),BELLE_SIP_HEADER(content_length)); belle_sip_message_set_body(BELLE_SIP_MESSAGE(ok_response),sdp,strlen(sdp)); belle_sip_object_ref(ok_response); /*only send ringing*/ belle_sip_server_transaction_send_response(server_transaction,ringing_response); } else if (belle_sip_dialog_get_state(dialog) == BELLE_SIP_DIALOG_CONFIRMED) { /*time to send bye*/ belle_sip_client_transaction_t* client_transaction = belle_sip_provider_create_client_transaction(prov,belle_sip_dialog_create_request(dialog,"BYE")); belle_sip_client_transaction_send_request(client_transaction); } else { belle_sip_warning("Unexpected state [%s] for dialog [%p]",belle_sip_dialog_state_to_string(belle_sip_dialog_get_state(dialog)),dialog ); } }
static void cleanup_pool_stack(void *data){ belle_sip_list_t **pool_stack=(belle_sip_list_t**)data; if (*pool_stack){ /* * We would expect the pool_stack to be empty when the thread terminates. * Otherwise that means the management of object pool is not properly done by the application. * Since the object pools might be still referenced by the application, we can't destroy them. * Instead, we mark them as detached, so that when the thread that will attempt to destroy them will do it, * we'll accept (since anyway these object pool are no longer needed. */ belle_sip_warning("There were still [%i] object pools for thread [%lu] while the thread exited. ", belle_sip_list_size(*pool_stack),belle_sip_thread_self_id()); belle_sip_list_free_with_data(*pool_stack,(void (*)(void*)) belle_sip_object_pool_detach_from_thread); } *pool_stack=NULL; belle_sip_free(pool_stack); }
static void ipv4_a_query_with_v4mapped_results(void) { int timeout; endpoint_t *client; if (!belle_sip_tester_ipv6_available()){ belle_sip_warning("Test skipped, IPv6 connectivity not available."); return; } client = create_endpoint(); CU_ASSERT_PTR_NOT_NULL_FATAL(client); timeout = belle_sip_stack_get_dns_timeout(client->stack); client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, IPV4_SIP_DOMAIN, SIP_PORT, AF_INET6, a_resolve_done, client); CU_ASSERT_NOT_EQUAL(client->resolver_ctx, NULL); CU_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout)); CU_ASSERT_PTR_NOT_NULL(client->ai_list); destroy_endpoint(client); }
static belle_sip_socket_t create_udp_socket(const char *addr, int port, int *family){ struct addrinfo hints={0}; struct addrinfo *res=NULL; int err; belle_sip_socket_t sock; char portnum[10]; int optval=1; snprintf(portnum,sizeof(portnum),"%i",port); hints.ai_family=AF_UNSPEC; hints.ai_socktype=SOCK_DGRAM; hints.ai_protocol=IPPROTO_UDP; hints.ai_flags=AI_NUMERICSERV; err=getaddrinfo(addr,portnum,&hints,&res); if (err!=0){ belle_sip_error("getaddrinfo() failed for %s port %i: %s",addr,port,gai_strerror(err)); return -1; } *family=res->ai_family; sock=socket(res->ai_family,res->ai_socktype,res->ai_protocol); if (sock==-1){ belle_sip_error("Cannot create UDP socket: %s",belle_sip_get_socket_error_string()); freeaddrinfo(res); return -1; } err = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&optval, sizeof (optval)); if (err == -1){ belle_sip_warning ("Fail to set SIP/UDP address reusable: %s.", belle_sip_get_socket_error_string()); } err=bind(sock,res->ai_addr,res->ai_addrlen); if (err==-1){ belle_sip_error("udp bind() failed for %s port %i: %s",addr,port,belle_sip_get_socket_error_string()); close_socket(sock); freeaddrinfo(res); return -1; } freeaddrinfo(res); return sock; }
void belle_sip_server_transaction_on_request(belle_sip_server_transaction_t *t, belle_sip_request_t *req){ const char *method=belle_sip_request_get_method(req); if (strcmp(method,"ACK")==0){ /*this must be for an INVITE server transaction */ if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_ist_t)){ belle_sip_ist_t *ist=(belle_sip_ist_t*)t; if (belle_sip_ist_process_ack(ist,(belle_sip_message_t*)req)==0){ belle_sip_dialog_t *dialog=t->base.dialog; if (dialog && belle_sip_dialog_handle_ack(dialog,req)==0) server_transaction_notify(t,req,dialog); /*else nothing to do because retransmission of ACK*/ } }else{ belle_sip_warning("ACK received for non-invite server transaction ?"); } }else if (strcmp(method,"CANCEL")==0){ server_transaction_notify(t,req,t->base.dialog); }else BELLE_SIP_OBJECT_VPTR(t,belle_sip_server_transaction_t)->on_request_retransmission(t); }
static void http_channel_context_handle_response_headers(belle_http_channel_context_t *ctx , belle_sip_channel_t *chan, belle_http_response_t *response){ belle_http_request_t *req=ctx->pending_requests ? (belle_http_request_t*) ctx->pending_requests->data : NULL; belle_http_response_event_t ev={0}; int code; if (req==NULL){ belle_sip_error("Receiving http response headers not matching any request."); return; } if (belle_http_request_is_cancelled(req)) { belle_sip_warning("Receiving http response headers for a cancelled request."); return; } code=belle_http_response_get_status_code(response); if (code!=401 && code!=407){ /*else notify the app about the response headers received*/ ev.source=(belle_sip_object_t*)ctx->provider; ev.request=req; ev.response=response; BELLE_HTTP_REQUEST_INVOKE_LISTENER(req,process_response_headers,&ev); } }