From 3d39e92628626c694ec60954bc5b5162fbf3a392 Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Tue, 3 Jul 2012 15:13:39 +0930 Subject: [PATCH] Setup scheduled alarm per vomp call and send keep alives --- fdqueue.c | 1 - monitor.c | 31 +----- overlay.c | 3 - serval.h | 9 +- vomp.c | 325 +++++++++++++++++++++++++----------------------------- 5 files changed, 160 insertions(+), 209 deletions(-) diff --git a/fdqueue.c b/fdqueue.c index 8a97f673..91903caa 100644 --- a/fdqueue.c +++ b/fdqueue.c @@ -50,7 +50,6 @@ void list_alarms(){ // simply populate .alarm with the absolute time, and .function with the method to call. // on calling .poll.revents will be zero. int schedule(struct sched_ent *alarm){ - long long now=overlay_gettime_ms(); struct sched_ent *node = next_alarm, *last = NULL; while(node!=NULL){ if (node->alarm > alarm->alarm) diff --git a/monitor.c b/monitor.c index c57723a4..8a533d5e 100644 --- a/monitor.c +++ b/monitor.c @@ -35,9 +35,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define MONITOR_DATA_SIZE MAX_AUDIO_BYTES struct monitor_context { struct sched_ent alarm; -#define MONITOR_VOMP (1<<0) -#define MONITOR_RHIZOME (1<<1) -#define MONITOR_PEERS (1<<2) int flags; char line[MONITOR_LINE_LENGTH]; int line_length; @@ -54,7 +51,6 @@ struct monitor_context { #define MAX_MONITOR_SOCKETS 8 int monitor_socket_count=0; struct monitor_context monitor_sockets[MAX_MONITOR_SOCKETS]; -long long monitor_last_update_time=0; int monitor_process_command(struct monitor_context *c); int monitor_process_data(struct monitor_context *c); @@ -134,34 +130,11 @@ int monitor_setup_sockets() void monitor_poll(struct sched_ent *alarm) { - int s,i,m; + int s; unsigned char buffer[1024]; - char msg[1024]; struct sockaddr *ignored_address=(struct sockaddr *)&buffer[0]; socklen_t ignored_length=sizeof(ignored_address); - /* tell all monitor clients about status of all calls periodically */ - long long now = overlay_gettime_ms(); - if (monitor_last_update_time > (now + 1000)) { - INFO("Fixed run away monitor_last_update_time"); - monitor_last_update_time = now + 1000; - } - - if (now > (monitor_last_update_time + 1000)) { - // DEBUG("Send keep alives"); - monitor_last_update_time = now; - for(i = 0; i < vomp_call_count; i++) { - /* Push out any undelivered status changes */ - monitor_call_status(&vomp_call_states[i]); - INFOF("Sending keepalives for call #%d",i); - - /* And let far-end know that call is still alive */ - snprintf(msg,sizeof(msg) -1,"\nKEEPALIVE:%06x\n", vomp_call_states[i].local.session); - for(m = 0;m < monitor_socket_count; m++) - WRITE_STR(monitor_sockets[m].alarm.poll.fd,msg); - } - } - /* Check for new connections */ /* We don't care about the peer's address */ ignored_length = 0; @@ -285,10 +258,10 @@ static void monitor_new_client(int s) { #ifdef linux struct ucred ucred; socklen_t len; + int res; #else gid_t othergid; #endif - int res; uid_t otheruid; struct monitor_context *c; diff --git a/overlay.c b/overlay.c index d416c5a9..751c2103 100644 --- a/overlay.c +++ b/overlay.c @@ -148,9 +148,6 @@ schedule(&_sched_##X); /* Periodically update route table. */ SCHEDULE(overlay_route_tick, 100); - /* Keep an eye on VoMP calls so that we can expire stale ones etc */ - SCHEDULE(vomp_tick, 1000); - /* Show CPU usage stats periodically */ SCHEDULE(fd_periodicstats, 3000); diff --git a/serval.h b/serval.h index ce3ad820..ae7e2786 100755 --- a/serval.h +++ b/serval.h @@ -1097,6 +1097,12 @@ int overlay_saw_mdp_containing_frame(overlay_frame *f,long long now); #define DEBUG_PACKETCONSTRUCTION (1 << 23) #define DEBUG_MANIFESTS (1 << 24) +/* bitmask values for monitor_tell_clients */ +#define MONITOR_VOMP (1<<0) +#define MONITOR_RHIZOME (1<<1) +#define MONITOR_PEERS (1<<2) + + int serval_packetvisualise(FILE *f,char *message,unsigned char *packet,int plen); int overlay_broadcast_drop_check(unsigned char *a); @@ -1377,6 +1383,7 @@ typedef struct vomp_sample_block { #define VOMP_MAX_RECENT_SAMPLES 2 typedef struct vomp_call_state { + struct sched_ent alarm; vomp_call_half local; vomp_call_half remote; int ringing; @@ -1384,7 +1391,6 @@ typedef struct vomp_call_state { unsigned long long create_time; unsigned long long last_activity; unsigned long long audio_clock; - long long next_status_time; int audio_started; int last_sent_status; unsigned char remote_codec_list[256]; @@ -1563,7 +1569,6 @@ void rhizome_enqueue_suggestions(struct sched_ent *alarm); void server_shutdown_check(struct sched_ent *alarm); void overlay_mdp_poll(struct sched_ent *alarm); void fd_periodicstats(struct sched_ent *alarm); -void vomp_tick(struct sched_ent *alarm); void rhizome_check_connections(struct sched_ent *alarm); void monitor_client_poll(struct sched_ent *alarm); diff --git a/vomp.c b/vomp.c index 74e230df..28e44807 100644 --- a/vomp.c +++ b/vomp.c @@ -32,7 +32,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. int vomp_call_count=0; int vomp_active_call=-1; vomp_call_state vomp_call_states[VOMP_MAX_CALLS]; +struct profile_total vomp_stats; + int dump_vomp_status(); +void vomp_process_tick(struct sched_ent *alarm); /* which codecs we support (set by registered listener) */ unsigned char vomp_local_codec_list[256]; @@ -53,111 +56,119 @@ vomp_call_state *vomp_find_call_by_session(int session_token) return NULL; } +int vomp_generate_session_id(){ + int session_id=0; + while (!session_id) + { + if (urandombytes((unsigned char *)&session_id,sizeof(int))) + return WHY("Insufficient entropy"); + session_id&=VOMP_SESSION_MASK; + DEBUGF("session=0x%08x\n",session_id); + int i; + /* reject duplicate call session numbers */ + for(i=0;ilocal.sid,SID_SIZE); + bcopy(remote_sid,call->remote.sid,SID_SIZE); + call->local.session=local_session; + call->remote.session=remote_session; + call->local.state=local_state; + call->remote.state=remote_state; + call->create_time=overlay_gettime_ms(); + call->last_activity=call->create_time; + call->alarm.alarm = call->create_time+VOMP_CALL_STATUS_INTERVAL; + call->alarm.function = vomp_process_tick; + vomp_stats.name="vomp_process_tick"; + call->alarm.stats=&vomp_stats; + schedule(&call->alarm); + WHYF("Returning new call #%d",local_session); + monitor_call_status(call); + return call; +} + vomp_call_state *vomp_find_or_create_call(unsigned char *remote_sid, unsigned char *local_sid, unsigned int sender_session, unsigned int recvr_session, - int sender_state,int recvr_state) + int sender_state, + int recvr_state) { - int expired_slot=-1; int i; + vomp_call_state *call; + if (0) printf("%d calls already in progress.\n",vomp_call_count); for(i=0;iremote.session, + call->local.session); int checked=0; - if (vomp_call_states[i].remote.session&&sender_session) { + if (call->remote.session&&sender_session) { checked++; - if(sender_session!=vomp_call_states[i].remote.session) + if(sender_session!=call->remote.session) continue; } - if (vomp_call_states[i].local.session&&recvr_session) { + if (call->local.session&&recvr_session) { checked++; - if(recvr_session!=vomp_call_states[i].local.session) + if(recvr_session!=call->local.session) continue; } if (!checked) continue; - if (memcmp(remote_sid,vomp_call_states[i].remote.sid,SID_SIZE)) continue; - if (memcmp(local_sid,vomp_call_states[i].local.sid,SID_SIZE)) continue; + if (memcmp(remote_sid,call->remote.sid,SID_SIZE)) continue; + if (memcmp(local_sid,call->local.sid,SID_SIZE)) continue; - /* it matches. but has it expired (no activity in 120 seconds)? - NOTE: as these time calculations are unsigned, we must add to - the last activity time rather than subtract from the current time - when calculating the timeout. - */ - if (vomp_call_states[i].last_activity+VOMP_CALL_TIMEOUT<(overlay_gettime_ms())) - { - WHYF("slot %d has expired.",i); - WHYF(" last_activity=%lld, now=%lld", - vomp_call_states[i].last_activity,overlay_gettime_ms()); - expired_slot=i; - continue; - } + /* it matches. */ /* Record session number if required */ - if (!vomp_call_states[i].remote.session) - vomp_call_states[i].remote.session=sender_session; + if (!call->remote.session) + call->remote.session=sender_session; if (0) { WHYF("Returning existing call #%d",i); fprintf(stderr,"%06x:%06x matches call #%d %06x:%06x\n", sender_session,recvr_session,i, - vomp_call_states[i].remote.session, - vomp_call_states[i].local.session); + call->remote.session, + call->local.session); } - return &vomp_call_states[i]; + return call; } /* not in the list. So allocate a slot, but only if the call is in progress. */ if (recvr_state==VOMP_STATE_CALLENDED&&sender_state==VOMP_STATE_CALLENDED) return NULL; - - if (expired_slot>-1) i=expired_slot; - else if ((i=VOMP_MAX_CALLS) return WHY("supplied call handle looks invalid"); - - if (i==vomp_call_count-1) - vomp_call_count--; - else - { - bcopy(&vomp_call_states[vomp_call_count-1], - &vomp_call_states[i], - sizeof(vomp_call_state)); - vomp_call_count--; - } + int i = (call - vomp_call_states); + unschedule(&call->alarm); + + vomp_call_count--; + if (i!=vomp_call_count){ + unschedule(&vomp_call_states[vomp_call_count].alarm); + bcopy(&vomp_call_states[vomp_call_count], + call, + sizeof(vomp_call_state)); + schedule(&call->alarm); + } return 0; } @@ -576,14 +584,12 @@ int vomp_mdp_event(overlay_mdp_frame *mdp, /* and provide a quick summary of all calls in progress */ int i; - for(i=0;ivompevent.local_sid,call->local.sid,SID_SIZE); - bcopy(mdp->vompevent.remote_sid,call->remote.sid,SID_SIZE); - bcopy(mdp->vompevent.local_did,call->local.did,64); - bcopy(mdp->vompevent.remote_did,call->remote.did,64); - call->create_time=overlay_gettime_ms(); - call->local.state=VOMP_STATE_CALLPREP; - call->remote.state=VOMP_STATE_NOCALL; /* far end has yet to agree that a call is happening */ - monitor_call_status(call); - + /* allocate unique call session token, which is how the client will - refer to this call during its life */ - while (!call->local.session) - { - if (urandombytes((unsigned char *)&call->local.session,sizeof(int))) - return overlay_mdp_reply_error - (mdp_named.poll.fd,recvaddr,recvaddrlen,4005, - "Insufficient entropy"); - call->local.session&=VOMP_SESSION_MASK; - DEBUGF("session=0x%08x\n",call->local.session); - int i; - for(i=0;ilocal.session==vomp_call_states[i].local.session) break; - /* reject duplicate call session numbers */ - if (ilocal.session=0; - } - call->local.session&=VOMP_SESSION_MASK; - call->last_activity=overlay_gettime_ms(); - + refer to this call during its life */ + vomp_call_state *call=vomp_create_call( + mdp->vompevent.remote_sid, + mdp->vompevent.local_sid, + 0, + 0, + VOMP_STATE_NOCALL, + VOMP_STATE_CALLPREP + ); + /* send status update to remote, thus causing call to be created (hopefully) at far end. */ vomp_send_status(call,VOMP_TELLREMOTE|VOMP_TELLINTERESTED,NULL); - WHY("sending MDP reply back"); - dump("recvaddr",(unsigned char *)recvaddr,recvaddrlen); int result= overlay_mdp_reply_error (mdp_named.poll.fd,recvaddr,recvaddrlen,0, "Success"); if (result) WHY("Failed to send MDP reply"); @@ -1458,59 +1442,52 @@ int app_vomp_monitor(int argc, const char *const *argv, struct command_line_opti return overlay_mdp_client_done(); } -void vomp_tick(struct sched_ent *alarm) -{ - /* Send any reminder packets for call state, and also process any audio. */ - unsigned long long now=overlay_gettime_ms(); - int i; - - for(i=0;ivomp_call_states[i].next_status_time) - { - vomp_send_status(&vomp_call_states[i],VOMP_FORCETELLREMOTE,NULL); - vomp_call_states[i].next_status_time=now+VOMP_CALL_STATUS_INTERVAL; - } - /* See if any calls need to begin expiring - (current timeout is set at 2 minutes) */ - if (vomp_call_states[i].local.statealarm = overlay_gettime_ms()+1000; +void vomp_process_tick(struct sched_ent *alarm){ + char msg[32]; + int len; + unsigned long long now = overlay_gettime_ms(); + + vomp_call_state *call = (vomp_call_state *)alarm; + + /* Push out any undelivered status changes */ + monitor_call_status(call); + + /* tell the other party we are still here */ + vomp_send_status(call,VOMP_FORCETELLREMOTE,NULL); + + /* tell local monitor clients the call is still alive */ + len = snprintf(msg,sizeof(msg) -1,"\nKEEPALIVE:%06x\n", call->local.session); + monitor_tell_clients(msg, len, MONITOR_VOMP); + + /* See if any calls need to begin expiring + (current timeout is set at 2 minutes) */ + if (call->local.statecreate_time+VOMP_CALL_TIMEOUT)last_activity+VOMP_CALL_TIMEOUTlocal.state) + { + case VOMP_STATE_INCALL: + /* Timeout while call in progress, so end call. + Keep call structure hanging around for a bit so that we can + synchonrise with the far end if possible. */ + call->local.state=VOMP_STATE_CALLENDED; + monitor_call_status(call); + vomp_send_status(call, VOMP_TELLREMOTE|VOMP_TELLINTERESTED,NULL); + call->last_activity=now; + vomp_call_stop_audio(call); + break; + default: + /* Call timed out while not actually in progress, so just immmediately + tear the call down */ + vomp_call_destroy(call); + return; + } + alarm->alarm = overlay_gettime_ms() + VOMP_CALL_STATUS_INTERVAL; schedule(alarm); - return; } -