diff --git a/serval.h b/serval.h index 96c4b3b6..5b17f588 100644 --- a/serval.h +++ b/serval.h @@ -1141,6 +1141,9 @@ typedef struct overlay_mdp_addrlist { #define MDP_VOMPEVENT 7 typedef struct overlay_mdp_vompevent { + /* Once a call has been established, this is how the MDP/VoMP server + and user-end process talk about the call. */ + unsigned int call_session_token; unsigned long long audio_sample_endtime; unsigned long long last_activity; #define VOMPEVENT_RINGING (1<<0) @@ -1153,12 +1156,23 @@ typedef struct overlay_mdp_vompevent { #define VOMPEVENT_DIAL (1<<6) #define VOMPEVENT_REGISTERINTEREST (1<<7) #define VOMPEVENT_WITHDRAWINTEREST (1<<8) +#define VOMPEVENT_CALLCREATED (1<<9) unsigned int flags; unsigned short audio_sample_bytes; unsigned char local_state; unsigned char remote_state; unsigned char audio_sample_codec; - unsigned char audio_bytes[MDP_MTU-100]; + union { + struct { + /* Used to precisely define the call end points during call + setup. */ + unsigned char local_did[64]; + unsigned char remote_did[64]; + unsigned char local_sid[SID_SIZE]; + unsigned char remote_sid[SID_SIZE]; + }; + unsigned char audio_bytes[MDP_MTU-100]; + }; } overlay_mdp_vompevent; typedef struct overlay_mdp_frame { @@ -1220,6 +1234,7 @@ void _serval_debug_free(void *p,char *file,const char *func,int line); typedef struct vomp_call_half { unsigned char sid[SID_SIZE]; + unsigned char did[64]; unsigned char state; unsigned char codec; unsigned int session; diff --git a/vomp.c b/vomp.c index 9bc60a57..61c1be40 100644 --- a/vomp.c +++ b/vomp.c @@ -18,7 +18,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* - VoMP works using a 5-state model of a phone call, and relies on MDP for + VoMP works using a 6-state model of a phone call, and relies on MDP for auth-cryption of frames. VoMP provides it's own replay protection. */ @@ -30,6 +30,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. the ejection of newly allocated session numbers before the caller has had a chance to progress the call to a further state. */ int vomp_call_count=0; +int vomp_active_call=-1; #define VOMP_MAX_CALLS 16 vomp_call_state vomp_call_states[VOMP_MAX_CALLS]; @@ -40,6 +41,15 @@ struct sockaddr_un *vomp_interested_usocks[VOMP_MAX_INTERESTED]; int vomp_interested_usock_lengths[VOMP_MAX_INTERESTED]; unsigned long long vomp_interested_expiries[VOMP_MAX_INTERESTED]; +vomp_call_state *vomp_find_call_by_session(int session_token) +{ + int i; + for(i=0;i=VOMP_MAX_CALLS) + return overlay_mdp_reply_error + (mdp_named_socket,recvaddr,recvaddrlen,4004, + "All call slots in use"); + int slot=vomp_call_count++; + vomp_call_state *call=&vomp_call_states[slot]; + bzero(call,sizeof(vomp_call_state)); + bcopy(mdp->vompevent.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->local.state=1; + call->remote.state=0; /* far end has yet to agree that a call is happening */ + /* 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_socket,recvaddr,recvaddrlen,4005, + "Insufficient entropy"); + int i; + for(i=0;ilocal.session==vomp_call_states[i].local.session) break; + /* reject duplicate call session numbers */ + if (i>=vomp_call_count) call->local.session=0; + } + call->local.session&=VOMP_SESSION_MASK; + call->last_activity=overlay_gettime_ms(); + + /* send status update to remote, thus causing call to be created + (hopefully) at far end. */ + return vomp_send_status(call,VOMP_TELLREMOTE|VOMP_TELLINTERESTED); + } + break; case VOMPEVENT_CALLREJECT: /* hangup is the same */ + { + vomp_call_state *call + =vomp_find_call_by_session(mdp->vompevent.call_session_token); + if (!call) + return overlay_mdp_reply_error + (mdp_named_socket,recvaddr,recvaddrlen,4006, + "No such call"); + if (call->local.state==VOMP_STATE_INCALL) vomp_call_stop_audio(call); + call->local.state=VOMP_STATE_CALLENDED; + return vomp_send_status(call,VOMP_TELLREMOTE|VOMP_TELLINTERESTED); + } case VOMPEVENT_AUDIOSTREAMING: /* user supplying audio */ + WHY("Handling of in-call audio not yet implemented"); + break; default: /* didn't understand it, so respond with an error */ return overlay_mdp_reply_error(mdp_named_socket, @@ -304,7 +372,7 @@ int vomp_mdp_received(overlay_mdp_frame *mdp) /* We have a session number. Send a status update back to sender */ call->last_activity=overlay_gettime_ms(); - return vomp_send_status(call); + return vomp_send_status(call,VOMP_TELLREMOTE); } else { /* A VoMP packet for a call apparently already in progress */ call=vomp_find_or_create_call(mdp->in.src.sid,mdp->in.dst.sid, @@ -500,7 +568,7 @@ int vomp_mdp_received(overlay_mdp_frame *mdp) /* touch call timer if the current state has not vetoed by returning */ call->last_activity=overlay_gettime_ms(); /* and then send an update to the call status */ - vomp_send_status(call); + vomp_send_status(call,VOMP_TELLREMOTE|VOMP_TELLINTERESTED); } } break;