/*peek data from the master socket to see where it comes from, and dispatch to matching channel. * If the channel does not exist, create it */ static int on_udp_data(belle_sip_udp_listening_point_t *lp, unsigned int events){ int err; unsigned char buf[4096]; sockaddr_x addr; socklen_t addrlen=sizeof(sockaddr_x); if (events & BELLE_SIP_EVENT_READ){ belle_sip_debug("udp_listening_point: data to read."); err=Xrecvfrom(lp->sock,(char*)buf,sizeof(buf),MSG_PEEK,(struct sockaddr*)&addr,&addrlen); if (err==-1){ char *tmp=belle_sip_object_to_string((belle_sip_object_t*) ((belle_sip_listening_point_t*)lp)->listening_uri); belle_sip_error("udp_listening_point: recvfrom() failed on [%s], : [%s] reopening server socket" ,tmp ,belle_sip_get_socket_error_string()); belle_sip_free(tmp); belle_sip_udp_listening_point_uninit(lp); /*clean all udp channels that are actually sharing the server socket with the listening points*/ belle_sip_listening_point_clean_channels((belle_sip_listening_point_t*)lp); belle_sip_udp_listening_point_init_socket(lp); }else{ belle_sip_channel_t *chan; struct addrinfo ai={0}; belle_sip_address_remove_v4_mapping((struct sockaddr*)&addr,(struct sockaddr*)&addr,&addrlen); ai.ai_family=((struct sockaddr*)&addr)->sa_family; ai.ai_addr=(struct sockaddr*)&addr; ai.ai_addrlen=addrlen; chan=_belle_sip_listening_point_get_channel((belle_sip_listening_point_t*)lp,NULL,&ai); if (chan==NULL){ /*TODO: should rather create the channel with real local ip and port and not just 0.0.0.0"*/ chan=belle_sip_channel_new_udp_with_addr(lp->base.stack ,lp->sock ,belle_sip_uri_get_host(lp->base.listening_uri) ,belle_sip_uri_get_port(lp->base.listening_uri) ,&ai); if (chan!=NULL){ belle_sip_message("udp_listening_point: new channel created to %s:%i",chan->peer_name,chan->peer_port); chan->lp=(belle_sip_listening_point_t*)lp; /*FIXME, exactly the same code as for channel creation from provider. might be good to factorize*/ belle_sip_listening_point_add_channel((belle_sip_listening_point_t*)lp,chan); } } if (chan){ /*notify the channel*/ belle_sip_debug("Notifying udp channel, local [%s:%i] remote [%s:%i]" ,chan->local_ip ,chan->local_port ,chan->peer_name ,chan->peer_port); belle_sip_channel_process_data(chan,events); } } } return BELLE_SIP_CONTINUE; }
void belle_sip_channel_parse_stream(belle_sip_channel_t *obj, int end_of_stream){ int offset; size_t read_size=0; int num; while ((num=(obj->input_stream.write_ptr-obj->input_stream.read_ptr))>0){ if (obj->input_stream.state == WAITING_MESSAGE_START) { int i; /*first, make sure there is \r\n in the buffer, otherwise, micro parser cannot conclude, because we need a complete request or response line somewhere*/ for (i=0;i<num-1;i++) { if ((obj->input_stream.read_ptr[i]=='\r' && obj->input_stream.read_ptr[i+1]=='\n') || belle_sip_channel_input_stream_get_buff_length(&obj->input_stream) <= 1 /*1 because null terminated*/ /*if buffer full try to parse in any case*/) { /*good, now we can start searching for request/response*/ if ((offset=get_message_start_pos(obj->input_stream.read_ptr,num)) >=0 ) { /*message found !*/ if (offset>0) { belle_sip_warning("trashing [%i] bytes in front of sip message on channel [%p]",offset,obj); obj->input_stream.read_ptr+=offset; } obj->input_stream.state=MESSAGE_AQUISITION; } else { belle_sip_debug("Unexpected [%s] received on channel [%p], trashing",obj->input_stream.read_ptr,obj); obj->input_stream.read_ptr=obj->input_stream.write_ptr; belle_sip_channel_input_stream_reset(&obj->input_stream); continue; } break; } } if (i >= num-1) { belle_sip_debug("[%s] received on channel [%p], cannot determine if expected or not, waiting for new data",obj->input_stream.read_ptr,obj); break; } } if (obj->input_stream.state==MESSAGE_AQUISITION) { /*search for \r\n\r\n*/ char* end_of_message=NULL; if ((end_of_message=strstr(obj->input_stream.read_ptr,"\r\n\r\n"))){ int bytes_to_parse; char tmp; /*end of message found*/ end_of_message+=4;/*add \r\n\r\n*/ bytes_to_parse=end_of_message-obj->input_stream.read_ptr; tmp=*end_of_message; *end_of_message='\0';/*this is in order for the following log to print the message only to its end.*/ /*belle_sip_message("channel [%p] read message of [%i] bytes:\n%.40s...",obj, bytes_to_parse, obj->input_stream.read_ptr);*/ obj->input_stream.msg=belle_sip_message_parse_raw(obj->input_stream.read_ptr ,bytes_to_parse ,&read_size); *end_of_message=tmp; obj->input_stream.read_ptr+=read_size; if (obj->input_stream.msg && read_size > 0){ belle_sip_message("channel [%p] [%i] bytes parsed",obj,(int)read_size); belle_sip_object_ref(obj->input_stream.msg); if (belle_sip_message_is_request(obj->input_stream.msg)) fix_incoming_via(BELLE_SIP_REQUEST(obj->input_stream.msg),obj->current_peer); /*check for body*/ if (check_body(obj)){ obj->input_stream.state=BODY_AQUISITION; } else { /*no body*/ belle_sip_channel_message_ready(obj); continue; } }else{ belle_sip_error("Could not parse [%s], on channel [%p] skipping to [%s]",obj->input_stream.read_ptr ,obj ,end_of_message); obj->input_stream.read_ptr=end_of_message; obj->input_stream.state=WAITING_MESSAGE_START; continue; } }else break; /*The message isn't finished to be receive, we need more data*/ } if (obj->input_stream.state==BODY_AQUISITION) { if (acquire_body(obj,end_of_stream)==BELLE_SIP_STOP) break; } } }
void belle_sip_main_loop_iterate(belle_sip_main_loop_t *ml){ size_t pfd_size = ml->nsources * sizeof(belle_sip_pollfd_t); belle_sip_pollfd_t *pfd=(belle_sip_pollfd_t*)belle_sip_malloc0(pfd_size); int i=0; belle_sip_source_t *s; belle_sip_list_t *elem,*next; uint64_t min_time_ms=(uint64_t)-1; int duration=-1; int ret; uint64_t cur; belle_sip_list_t *to_be_notified=NULL; int can_clean=belle_sip_object_pool_cleanable(ml->pool); /*iterate might not be called by the thread that created the main loop*/ belle_sip_object_pool_t *tmp_pool=NULL; if (!can_clean){ /*Push a temporary pool for the time of the iterate loop*/ tmp_pool=belle_sip_object_pool_push(); } /*Step 1: prepare the pollfd table and get the next timeout value */ for(elem=ml->sources;elem!=NULL;elem=next){ next=elem->next; s=(belle_sip_source_t*)elem->data; if (!s->cancelled){ if (s->fd!=(belle_sip_fd_t)-1){ belle_sip_source_to_poll(s,pfd,i); ++i; } if (s->timeout>=0){ if (min_time_ms>s->expire_ms){ min_time_ms=s->expire_ms; } } } } if (min_time_ms!=(uint64_t)-1 ){ int64_t diff; /* compute the amount of time to wait for shortest timeout*/ cur=belle_sip_time_ms(); diff=min_time_ms-cur; if (diff>0) duration=(int)diff; else duration=0; } /* do the poll */ ret=belle_sip_poll(pfd,i,duration); if (ret==-1){ goto end; } /* Step 2: examine poll results and determine the list of source to be notified */ cur=belle_sip_time_ms(); for(elem=ml->sources;elem!=NULL;elem=elem->next){ unsigned revents=0; s=(belle_sip_source_t*)elem->data; if (!s->cancelled){ if (s->fd!=(belle_sip_fd_t)-1){ if (s->notify_required) { /*for testing purpose to force channel to read*/ revents=BELLE_SIP_EVENT_READ; s->notify_required=0; /*reset*/ } else { revents=belle_sip_source_get_revents(s,pfd); } s->revents=revents; } if (revents!=0 || (s->timeout>=0 && cur>=s->expire_ms)){ to_be_notified=belle_sip_list_append(to_be_notified,belle_sip_object_ref(s)); s->expired=TRUE; if (s->revents==0) s->revents=BELLE_SIP_EVENT_TIMEOUT; } }else to_be_notified=belle_sip_list_append(to_be_notified,belle_sip_object_ref(s)); } /* Step 3: notify those to be notified */ for(elem=to_be_notified;elem!=NULL;){ s=(belle_sip_source_t*)elem->data; next=elem->next; if (!s->cancelled){ char *objdesc=belle_sip_object_to_string((belle_sip_object_t*)s); if (s->timeout>0)/*to avoid too many traces*/ belle_sip_debug("source %s notified revents=%u, timeout=%i",objdesc,revents,s->timeout); belle_sip_free(objdesc); ret=s->notify(s->data,s->revents); if (ret==BELLE_SIP_STOP || s->oneshot){ /*this source needs to be removed*/ belle_sip_main_loop_remove_source(ml,s); }else if (s->revents==BELLE_SIP_EVENT_TIMEOUT){ /*timeout needs to be started again */ s->expire_ms+=s->timeout; s->expired=FALSE; } }else belle_sip_main_loop_remove_source(ml,s); belle_sip_object_unref(s); belle_sip_free(elem); /*free just the element*/ elem=next; } if (can_clean) belle_sip_object_pool_clean(ml->pool); else if (tmp_pool) belle_sip_object_unref(tmp_pool); end: belle_sip_free(pfd); }