From 5463e1b62a39ce417b610584e3d34a8bc30ac15e Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sun, 15 Jan 2012 09:42:35 +0100 Subject: [PATCH 1/1] Added bridgin support for GSM and SIP The dependency on mISDN (loopback interface) is completely removed from GSM and SIP interfaces. The built in bridge of LCR now forwards audio data between these interface instances or between these instances and other instances. Additionally both GSM BS and SIP support direct forwarding of RTP traffic between other SIP endpoint and OpenBSC, so no traffic is forwarded by the LCR itself. This is done by forwarding RTP peer informations between these interface instances. --- action.cpp | 6 + apppbx.cpp | 258 +++++++++------- apppbx.h | 6 +- default/interface.conf | 23 +- default/options.conf | 3 +- dss1.cpp | 6 +- gsm.cpp | 549 +++++++++++++++++----------------- gsm.h | 49 ++-- gsm_bs.cpp | 344 ++++++++++------------ gsm_bs.h | 8 +- gsm_ms.cpp | 259 ++++++---------- gsm_ms.h | 13 +- interface.c | 142 ++++----- interface.h | 17 +- lcradmin.c | 5 +- mISDN.cpp | 16 - mISDN.h | 7 - message.h | 12 +- mncc.h | 11 + port.cpp | 8 +- port.h | 24 +- sip.cpp | 778 ++++++++++++++++++++++++------------------------- sip.h | 70 ++--- socket_server.c | 14 + ss5.cpp | 4 +- 25 files changed, 1277 insertions(+), 1355 deletions(-) diff --git a/action.cpp b/action.cpp index 514c016..e0a884d 100644 --- a/action.cpp +++ b/action.cpp @@ -74,6 +74,7 @@ void EndpointAppPBX::action_dialing_internal(void) struct capa_info capainfo; struct caller_info callerinfo; struct redir_info redirinfo; + struct rtp_info rtpinfo; struct dialing_info dialinginfo; struct port_list *portlist = ea_endpoint->ep_portlist; struct lcr_msg *message; @@ -91,6 +92,7 @@ void EndpointAppPBX::action_dialing_internal(void) memcpy(&capainfo, &e_capainfo, sizeof(capainfo)); memcpy(&callerinfo, &e_callerinfo, sizeof(callerinfo)); memcpy(&redirinfo, &e_redirinfo, sizeof(redirinfo)); + memcpy(&rtpinfo, &e_rtpinfo, sizeof(rtpinfo)); memset(&dialinginfo, 0, sizeof(dialinginfo)); dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION; SCPY(dialinginfo.id, e_dialinginfo.id); @@ -164,6 +166,7 @@ void EndpointAppPBX::action_dialing_internal(void) memcpy(&message->param.setup.redirinfo, &redirinfo, sizeof(struct redir_info)); memcpy(&message->param.setup.callerinfo, &callerinfo, sizeof(struct caller_info)); memcpy(&message->param.setup.capainfo, &capainfo, sizeof(struct capa_info)); + memcpy(&message->param.setup.rtpinfo, &rtpinfo, sizeof(struct rtp_info)); message_put(message); } @@ -174,6 +177,7 @@ void EndpointAppPBX::action_dialing_external(void) struct capa_info capainfo; struct caller_info callerinfo; struct redir_info redirinfo; + struct rtp_info rtpinfo; struct dialing_info dialinginfo; char *p; struct port_list *portlist = ea_endpoint->ep_portlist; @@ -206,6 +210,7 @@ void EndpointAppPBX::action_dialing_external(void) memcpy(&capainfo, &e_capainfo, sizeof(capainfo)); memcpy(&callerinfo, &e_callerinfo, sizeof(callerinfo)); memcpy(&redirinfo, &e_redirinfo, sizeof(redirinfo)); + memcpy(&rtpinfo, &e_rtpinfo, sizeof(rtpinfo)); memset(&dialinginfo, 0, sizeof(dialinginfo)); dialinginfo.itype = INFO_ITYPE_ISDN; // dialinginfo.sending_complete = 0; @@ -321,6 +326,7 @@ void EndpointAppPBX::action_dialing_external(void) memcpy(&message->param.setup.redirinfo, &redirinfo, sizeof(struct redir_info)); memcpy(&message->param.setup.callerinfo, &callerinfo, sizeof(struct caller_info)); memcpy(&message->param.setup.capainfo, &capainfo, sizeof(struct capa_info)); + memcpy(&message->param.setup.rtpinfo, &rtpinfo, sizeof(struct rtp_info)); message_put(message); } diff --git a/apppbx.cpp b/apppbx.cpp index 1b119b2..bf7988b 100644 --- a/apppbx.cpp +++ b/apppbx.cpp @@ -72,6 +72,7 @@ EndpointAppPBX::EndpointAppPBX(class Endpoint *epoint, int origin) : EndpointApp memset(&e_connectinfo, 0, sizeof(struct connect_info)); memset(&e_redirinfo, 0, sizeof(struct redir_info)); memset(&e_capainfo, 0, sizeof(struct capa_info)); + memset(&e_rtpinfo, 0, sizeof(struct rtp_info)); e_start = e_stop = 0; e_origin = origin; e_ruleset = ruleset_main; @@ -573,6 +574,53 @@ void EndpointAppPBX::set_tone(struct port_list *portlist, const char *tone) } } +/* hunts for the given interface + * it does not need to have an mISDNport instance */ +struct interface *EndpointAppPBX::hunt_interface(char *ifname) +{ + struct interface *interface; + int there_is_an_external = 0; + + interface = interface_first; + + /* first find the given interface or, if not given, one with no extension */ + checknext: + if (!interface) { + if (!there_is_an_external && !(ifname && ifname[0])) { + trace_header("CHANNEL SELECTION (no external interface specified)", DIRECTION_NONE); + add_trace("info", NULL, "Add 'extern' parameter to interface.conf."); + end_trace(); + } + return(NULL); + } + + /* check for given interface */ + if (ifname && ifname[0]) { + if (!strcasecmp(interface->name, ifname)) { + /* found explicit interface */ + trace_header("CHANNEL SELECTION (found given interface)", DIRECTION_NONE); + add_trace("interface", NULL, "%s", ifname); + end_trace(); + goto foundif; + } + } else { + if (interface->external) { + there_is_an_external = 1; + /* found non extension */ + trace_header("CHANNEL SELECTION (found external interface)", DIRECTION_NONE); + add_trace("interface", NULL, "%s", interface->name); + end_trace(); + goto foundif; + } + } + + interface = interface->next; + goto checknext; +foundif: + + return interface; +} + /* * hunts an mISDNport that is available for an outgoing call @@ -839,6 +887,7 @@ void EndpointAppPBX::out_setup(int cfnr) int cause = CAUSE_RESSOURCEUNAVAIL; const char *p; char cfp[64]; + struct interface *interface; struct mISDNport *mISDNport; char portname[32]; char *dirname; @@ -963,54 +1012,67 @@ void EndpointAppPBX::out_setup(int cfnr) SCCAT(ifname, *p++); if (*p == ',') p++; - /* found interface */ - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to interface %s\n", ea_endpoint->ep_serial, ifname); - /* hunt for mISDNport and create Port */ - mISDNport = hunt_port(ifname, &channel); - if (!mISDNport) { - trace_header("INTERFACE (not found or busy)", DIRECTION_NONE); + /* search interface */ + interface = hunt_interface(ifname); + if (!interface) { + trace_header("INTERFACE (not found)", DIRECTION_NONE); add_trace("interface", NULL, "%s", ifname); end_trace(); continue; } - /* creating INTERNAL port */ - SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum); -#ifdef WITH_SS5 - if (mISDNport->ss5) - port = ss5_hunt_line(mISDNport); - else -#endif + /* found interface */ + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to interface %s\n", ea_endpoint->ep_serial, ifname); #ifdef WITH_GSM_BS - if (mISDNport->gsm_bs) - port = new Pgsm_bs(PORT_TYPE_GSM_BS_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode); - else + if (interface->gsm_bs) { + SPRINT(portname, "%s-%d-out", interface->name, 0); + port = new Pgsm_bs(PORT_TYPE_GSM_BS_OUT, portname, &port_settings, interface); + } else #endif #ifdef WITH_GSM_MS - if (mISDNport->gsm_ms) - port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode); - else + if (interface->gsm_ms) { + SPRINT(portname, "%s-%d-out", interface->name, 0); + port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, portname, &port_settings, interface); + } else #endif -#ifdef WITH_SIP - if (mISDNport->ifport->interface->sip) - port = new Psip(PORT_TYPE_SIP_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, mISDNport->ifport->interface); - else +#ifdef WITH_GSM_MS + if (interface->sip) { + SPRINT(portname, "%s-%d-out", interface->name, 0); + port = new Psip(PORT_TYPE_SIP_OUT, portname, &port_settings, interface); + } else #endif - if (mISDNport->ifport->remote) { - admin = admin_first; - while(admin) { - if (admin->remote_name[0] && !strcmp(admin->remote_name, mISDNport->ifport->remote_app)) - break; - admin = admin->next; - } - if (!admin) { - trace_header("INTERFACE (remote not connected)", DIRECTION_NONE); - add_trace("application", NULL, "%s", mISDNport->ifport->remote_app); + { + /* hunt for mISDNport and create Port */ + mISDNport = hunt_port(ifname, &channel); + if (!mISDNport) { + trace_header("INTERFACE (busy)", DIRECTION_NONE); + add_trace("interface", NULL, "%s", ifname); end_trace(); continue; } - port = new Premote(PORT_TYPE_REMOTE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, admin->sock); - } else - port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode); + + SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum); +#ifdef WITH_SS5 + if (mISDNport->ss5) + port = ss5_hunt_line(mISDNport); + else +#endif + if (mISDNport->ifport->remote) { + admin = admin_first; + while(admin) { + if (admin->remote_name[0] && !strcmp(admin->remote_name, mISDNport->ifport->remote_app)) + break; + admin = admin->next; + } + if (!admin) { + trace_header("INTERFACE (remote not connected)", DIRECTION_NONE); + add_trace("application", NULL, "%s", mISDNport->ifport->remote_app); + end_trace(); + continue; + } + port = new Premote(PORT_TYPE_REMOTE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, admin->sock); + } else + port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode); + } if (!port) FATAL("Failed to create Port instance\n"); PDEBUG(DEBUG_EPOINT, "EPOINT(%d) got port %s\n", ea_endpoint->ep_serial, port->p_name); @@ -1019,7 +1081,7 @@ void EndpointAppPBX::out_setup(int cfnr) dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION; dialinginfo.ntype = e_dialinginfo.ntype; /* create port_list relation */ - portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->earlyb); + portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, interface->is_earlyb == IS_YES); if (!portlist) { PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial); delete port; @@ -1039,6 +1101,7 @@ void EndpointAppPBX::out_setup(int cfnr) memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info)); memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info)); memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info)); + memcpy(&message->param.setup.rtpinfo, &e_rtpinfo, sizeof(struct rtp_info)); //terminal SCPY(message->param.setup.from_terminal, e_ext.number); //terminal if (e_dialinginfo.id) //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id); @@ -1203,56 +1266,69 @@ void EndpointAppPBX::out_setup(int cfnr) p++; /* found number */ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to number '%s' interface '%s'\n", ea_endpoint->ep_serial, number, e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface"); - /* hunt for mISDNport and create Port */ - /* hunt for mISDNport and create Port */ - mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel); - if (!mISDNport) { - trace_header("INTERFACE (too busy)", DIRECTION_NONE); - add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface"); + /* search interface */ + interface = hunt_interface(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL); + if (!interface) { + trace_header("INTERFACE (not found)", DIRECTION_NONE); + add_trace("interface", NULL, "%s", ifname); end_trace(); goto check_anycall_extern; } - /* creating EXTERNAL port*/ - SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum); -#ifdef WITH_SS5 - if (mISDNport->ss5) - port = ss5_hunt_line(mISDNport); - else -#endif + /* found interface */ #ifdef WITH_GSM_BS - if (mISDNport->gsm_bs) - port = new Pgsm_bs(PORT_TYPE_GSM_BS_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode); - else + if (interface->gsm_bs) { + SPRINT(portname, "%s-%d-out", interface->name, 0); + port = new Pgsm_bs(PORT_TYPE_GSM_BS_OUT, portname, &port_settings, interface); + } else #endif #ifdef WITH_GSM_MS - if (mISDNport->gsm_ms) - port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode); - else + if (interface->gsm_ms) { + SPRINT(portname, "%s-%d-out", interface->name, 0); + port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, portname, &port_settings, interface); + } else #endif -#ifdef WITH_SIP - if (mISDNport->ifport->interface->sip) - port = new Psip(PORT_TYPE_SIP_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, mISDNport->ifport->interface); - else +#ifdef WITH_GSM_MS + if (interface->sip) { + SPRINT(portname, "%s-%d-out", interface->name, 0); + port = new Psip(PORT_TYPE_SIP_OUT, portname, &port_settings, interface); + } else #endif - if (mISDNport->ifport->remote) { - admin = admin_first; - while(admin) { - if (admin->remote_name[0] && !strcmp(admin->remote_name, mISDNport->ifport->remote_app)) - break; - admin = admin->next; - } - if (!admin) { - trace_header("INTERFACE (remote not connected)", DIRECTION_NONE); - add_trace("application", NULL, "%s", mISDNport->ifport->remote_app); + { + /* hunt for mISDNport and create Port */ + mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel); + if (!mISDNport) { + trace_header("INTERFACE (too busy)", DIRECTION_NONE); + add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface"); end_trace(); - continue; + goto check_anycall_extern; } - port = new Premote(PORT_TYPE_REMOTE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, admin->sock); - } else - port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode); + /* creating EXTERNAL port*/ + SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum); +#ifdef WITH_SS5 + if (mISDNport->ss5) + port = ss5_hunt_line(mISDNport); + else +#endif + if (mISDNport->ifport->remote) { + admin = admin_first; + while(admin) { + if (admin->remote_name[0] && !strcmp(admin->remote_name, mISDNport->ifport->remote_app)) + break; + admin = admin->next; + } + if (!admin) { + trace_header("INTERFACE (remote not connected)", DIRECTION_NONE); + add_trace("application", NULL, "%s", mISDNport->ifport->remote_app); + end_trace(); + continue; + } + port = new Premote(PORT_TYPE_REMOTE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, admin->sock); + } else + port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode); + } if (!port) FATAL("No memory for Port instance\n"); - earlyb = mISDNport->earlyb; + earlyb = (interface->is_earlyb == IS_YES); PDEBUG(DEBUG_EPOINT, "EPOINT(%d) created port %s\n", ea_endpoint->ep_serial, port->p_name); memset(&dialinginfo, 0, sizeof(dialinginfo)); if (e_dialinginfo.keypad[0]) @@ -1262,7 +1338,7 @@ void EndpointAppPBX::out_setup(int cfnr) dialinginfo.itype = INFO_ITYPE_ISDN; dialinginfo.ntype = e_dialinginfo.ntype; dialinginfo.sending_complete = e_dialinginfo.sending_complete; - portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->earlyb); + portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb); if (!portlist) { PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial); delete port; @@ -1274,6 +1350,7 @@ void EndpointAppPBX::out_setup(int cfnr) memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info)); memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info)); memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info)); + memcpy(&message->param.setup.rtpinfo, &e_rtpinfo, sizeof(struct rtp_info)); //terminal SCPY(message->param.setup.from_terminal, e_ext.number); //terminal if (e_dialinginfo.id) //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id); @@ -1506,7 +1583,6 @@ void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, un char buffer[256]; int writeext; /* flags need to write extension after modification */ class Port *port; - struct interface *interface; logmessage(message_type, param, portlist->port_id, DIRECTION_IN); @@ -1515,6 +1591,7 @@ void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, un memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo)); memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo)); memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo)); + memcpy(&e_rtpinfo, ¶m->setup.rtpinfo, sizeof(e_rtpinfo)); /* convert (inter-)national number type */ SCPY(e_dialinginfo.id, numberrize_callerinfo(e_dialinginfo.id, e_dialinginfo.ntype, options.national, options.international)); @@ -1522,16 +1599,9 @@ void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, un // e_dtmf = param->setup.dtmf; /* screen incoming caller id */ - interface = interface_first; - while(interface) { - if (!strcmp(e_callerinfo.interface, interface->name)) { - break; - } - interface = interface->next; - } - if (interface) { - do_screen(0, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present, interface); - do_screen(0, e_callerinfo.id2, sizeof(e_callerinfo.id2), &e_callerinfo.ntype2, &e_callerinfo.present2, interface); + if (e_callerinfo.interface[0]) { + do_screen(0, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present, e_callerinfo.interface); + do_screen(0, e_callerinfo.id2, sizeof(e_callerinfo.id2), &e_callerinfo.ntype2, &e_callerinfo.present2, e_callerinfo.interface); } /* process extension */ @@ -2007,7 +2077,6 @@ void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, unsigned int port_id = portlist->port_id; struct port_list *tportlist; class Port *port; - struct interface *interface; time_t now; logmessage(message_type, param, portlist->port_id, DIRECTION_IN); @@ -2035,16 +2104,8 @@ void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, time(&now); e_start = now; - /* screen incoming connected id */ - interface = interface_first; - while(interface) { - if (!strcmp(e_connectinfo.interface, interface->name)) { - break; - } - interface = interface->next; - } - if (interface) - do_screen(0, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present, interface); + if (e_callerinfo.interface[0]) + do_screen(0, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present, e_connectinfo.interface); /* screen connected name */ if (e_ext.name[0]) @@ -3196,6 +3257,7 @@ void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, un memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo)); memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo)); memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo)); + memcpy(&e_rtpinfo, ¶m->setup.rtpinfo, sizeof(e_rtpinfo)); /* process (voice over) data calls */ if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO) { diff --git a/apppbx.h b/apppbx.h index 552e7ca..a37fc44 100644 --- a/apppbx.h +++ b/apppbx.h @@ -73,8 +73,9 @@ class EndpointAppPBX : public EndpointApp struct caller_info e_callerinfo; /* information about the caller */ struct dialing_info e_dialinginfo; /* information about dialing */ struct connect_info e_connectinfo; /* information about connected line */ - struct redir_info e_redirinfo; /* info on redirection (to the calling user) */ - struct capa_info e_capainfo; /* info on l3,l2 capacity */ + struct redir_info e_redirinfo; /* info about redirection (to the calling user) */ + struct capa_info e_capainfo; /* info about l3,l2 capacity */ + struct rtp_info e_rtpinfo; /* info about rtp port forwarding and payload type */ time_t e_start, e_stop; /* time */ int e_origin; /* origin of call 0=incoming 1=outgoing */ struct route_ruleset *e_ruleset; /* current ruleset pointer (NULL=no ruleset) */ @@ -234,6 +235,7 @@ class EndpointAppPBX : public EndpointApp void set_tone(struct port_list *portlist, const char *tone); void out_setup(int cfnr); struct mISDNport *hunt_port(char *ifname, int *channel); + struct interface *hunt_interface(char *ifname); char *apply_callerid_display(const char *id, int itype, int ntype, int present, int screen, const char *extension, const char *name); void auth(int job, int bit_num); diff --git a/default/interface.conf b/default/interface.conf index f89c50c..449c7ec 100644 --- a/default/interface.conf +++ b/default/interface.conf @@ -157,37 +157,22 @@ # A special case for GSM Network interface. -# Don't remove/change the settings, they will cause undefined behaviour -# of LCR. It uses the loopback interface as defined in options.conf. # You may add 'extension' and 'msn' keywords to turn all your subscribers # in you GSM network to internal 'extensions'. # The MSN numbers will equal the subscriber number. #[GSM] #gsm-bs -#nt -#layer1hold no -#layer2hold no #tones yes #earlyb no -#channel-in free -#channel-out any -#nodtmf # A special case for GSM Mobile Station interface. # give "gsm-ms ". -# Don't remove/change the settings, they will cause undefined behaviour -# of LCR. It uses the loopback interface as defined in options.conf. # You may add 'extern' to make this interface the external line by default. #[GSM] #gsm-ms 1 -#layer1hold no -#layer2hold no #tones no #earlyb yes -#channel-in free -#channel-out any -#nodtmf ##extern @@ -205,6 +190,14 @@ #tones yes +# Use Sofia-SIP as SIP point-to-point interface +#[sip] +#sip +#sip 10.0.0.12 10.0.0.34 +#earlyb no +#tones no + + # Hint: Enter "lcr interface" for quick help on interface options. diff --git a/default/options.conf b/default/options.conf index 3c222d2..6e5ba13 100644 --- a/default/options.conf +++ b/default/options.conf @@ -14,12 +14,13 @@ #define DEBUG_GSM 0x0120 #define DEBUG_SS5 0x0140 #define DEBUG_VBOX 0x0180 +#define DEBUG_SIP 0x10000 #define DEBUG_EPOINT 0x0200 #define DEBUG_JOIN 0x0400 #define DEBUG_CRYPT 0x1000 #define DEBUG_ROUTE 0x2000 #define DEBUG_IDLETIME 0x4000 -#define DEBUG_LOG 0x7fff +#define DEBUG_LOG 0x7fffff #debug 0x0000 diff --git a/dss1.cpp b/dss1.cpp index 2a336d8..f0834af 100644 --- a/dss1.cpp +++ b/dss1.cpp @@ -1972,8 +1972,8 @@ void Pdss1::message_setup(unsigned int epoint_id, int message_id, union paramete memcpy(&p_capainfo, ¶m->setup.capainfo, sizeof(p_capainfo)); memcpy(&p_redirinfo, ¶m->setup.redirinfo, sizeof(p_redirinfo)); /* screen outgoing caller id */ - do_screen(1, p_callerinfo.id, sizeof(p_callerinfo.id), &p_callerinfo.ntype, &p_callerinfo.present, p_m_mISDNport->ifport->interface); - do_screen(1, p_callerinfo.id2, sizeof(p_callerinfo.id2), &p_callerinfo.ntype2, &p_callerinfo.present2, p_m_mISDNport->ifport->interface); + do_screen(1, p_callerinfo.id, sizeof(p_callerinfo.id), &p_callerinfo.ntype, &p_callerinfo.present, p_m_mISDNport->ifport->interface->name); + do_screen(1, p_callerinfo.id2, sizeof(p_callerinfo.id2), &p_callerinfo.ntype2, &p_callerinfo.present2, p_m_mISDNport->ifport->interface->name); /* only display at connect state: this case happens if endpoint is in connected mode */ if (p_state==PORT_STATE_CONNECT) { @@ -2487,7 +2487,7 @@ void Pdss1::message_connect(unsigned int epoint_id, int message_id, union parame /* copy connected information */ memcpy(&p_connectinfo, ¶m->connectinfo, sizeof(p_connectinfo)); /* screen outgoing caller id */ - do_screen(1, p_connectinfo.id, sizeof(p_connectinfo.id), &p_connectinfo.ntype, &p_connectinfo.present, p_m_mISDNport->ifport->interface); + do_screen(1, p_connectinfo.id, sizeof(p_connectinfo.id), &p_connectinfo.ntype, &p_connectinfo.present, p_m_mISDNport->ifport->interface->name); /* only display at connect state */ if (p_state == PORT_STATE_CONNECT) diff --git a/gsm.cpp b/gsm.cpp index e6806c3..3f778b4 100644 --- a/gsm.cpp +++ b/gsm.cpp @@ -34,6 +34,7 @@ static const struct _value_string { int msg_type; const char *name; } mncc_names[] = { + { 0, "New call ref" }, { MNCC_SETUP_REQ, "MNCC_SETUP_REQ" }, { MNCC_SETUP_IND, "MNCC_SETUP_IND" }, { MNCC_SETUP_RSP, "MNCC_SETUP_RSP" }, @@ -127,26 +128,38 @@ static int delete_event(struct lcr_work *work, void *instance, int index); /* * constructor */ -Pgsm::Pgsm(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode) : PmISDN(type, mISDNport, portname, settings, channel, exclusive, mode) +Pgsm::Pgsm(int type, char *portname, struct port_settings *settings, struct interface *interface) : Port(type, portname, settings) { - p_callerinfo.itype = (mISDNport->ifport->interface->extension)?INFO_ITYPE_ISDN_EXTENSION:INFO_ITYPE_ISDN; - memset(&p_m_g_delete, 0, sizeof(p_m_g_delete)); - add_work(&p_m_g_delete, delete_event, this, 0); - p_m_g_lcr_gsm = NULL; - p_m_g_callref = 0; - p_m_g_mode = 0; - p_m_g_gsm_b_sock = -1; - p_m_g_gsm_b_index = -1; - p_m_g_gsm_b_active = 0; - p_m_g_notify_pending = NULL; - p_m_g_decoder = gsm_audio_create(); - p_m_g_encoder = gsm_audio_create(); - if (!p_m_g_encoder || !p_m_g_decoder) { + p_g_tones = 0; + if (interface->is_tones == IS_YES) + p_g_tones = 1; + p_g_earlyb = 0; + if (interface->is_earlyb == IS_YES) + p_g_earlyb = 1; + p_g_rtp_bridge = 0; + if (interface->rtp_bridge) + p_g_rtp_bridge = 1; + SCPY(p_g_interface_name, interface->name); + p_callerinfo.itype = (interface->extension)?INFO_ITYPE_ISDN_EXTENSION:INFO_ITYPE_ISDN; + memset(&p_g_delete, 0, sizeof(p_g_delete)); + add_work(&p_g_delete, delete_event, this, 0); + p_g_lcr_gsm = NULL; + p_g_callref = 0; + p_g_mode = 0; + p_g_gsm_b_sock = -1; + p_g_gsm_b_index = -1; + p_g_gsm_b_active = 0; + p_g_notify_pending = NULL; + p_g_setup_pending = NULL; + p_g_connect_pending = NULL; + p_g_decoder = gsm_audio_create(); + p_g_encoder = gsm_audio_create(); + if (!p_g_encoder || !p_g_decoder) { PERROR("Failed to create GSM audio codec instance\n"); - trigger_work(&p_m_g_delete); + trigger_work(&p_g_delete); } - p_m_g_rxpos = 0; - p_m_g_tch_connected = 0; + p_g_rxpos = 0; + p_g_tch_connected = 0; PDEBUG(DEBUG_GSM, "Created new GSMPort(%s).\n", portname); } @@ -158,131 +171,74 @@ Pgsm::~Pgsm() { PDEBUG(DEBUG_GSM, "Destroyed GSM process(%s).\n", p_name); - del_work(&p_m_g_delete); + del_work(&p_g_delete); /* remove queued message */ - if (p_m_g_notify_pending) - message_free(p_m_g_notify_pending); - - /* close audio transfer socket */ - if (p_m_g_gsm_b_sock > -1) - bchannel_close(); + if (p_g_notify_pending) + message_free(p_g_notify_pending); + if (p_g_setup_pending) + message_free(p_g_setup_pending); + if (p_g_connect_pending) + message_free(p_g_connect_pending); /* close codec */ - if (p_m_g_encoder) - gsm_audio_destroy(p_m_g_encoder); - if (p_m_g_decoder) - gsm_audio_destroy(p_m_g_decoder); + if (p_g_encoder) + gsm_audio_destroy(p_g_encoder); + if (p_g_decoder) + gsm_audio_destroy(p_g_decoder); } -/* close bsc side bchannel */ -void Pgsm::bchannel_close(void) -{ - if (p_m_g_gsm_b_sock > -1) { - unregister_fd(&p_m_g_gsm_b_fd); - close(p_m_g_gsm_b_sock); - } - p_m_g_gsm_b_sock = -1; - p_m_g_gsm_b_index = -1; - p_m_g_gsm_b_active = 0; -} - -static int b_handler(struct lcr_fd *fd, unsigned int what, void *instance, int index); - -/* open external side bchannel */ -int Pgsm::bchannel_open(int index) +/* receive encoded frame from gsm */ +void Pgsm::frame_receive(void *arg) { - int ret; - struct sockaddr_mISDN addr; - struct mISDNhead act; + struct gsm_data_frame *frame = (struct gsm_data_frame *)arg; + signed short samples[160]; + unsigned char data[160]; + int i; - if (p_m_g_gsm_b_sock > -1) { - PERROR("Socket already created for index %d\n", index); - return(-EIO); - } + if (!p_g_decoder) + return; - /* open socket */ - ret = p_m_g_gsm_b_sock = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_B_RAW); - if (ret < 0) { - PERROR("Failed to open bchannel-socket for index %d\n", index); - bchannel_close(); - return(ret); - } - memset(&p_m_g_gsm_b_fd, 0, sizeof(p_m_g_gsm_b_fd)); - p_m_g_gsm_b_fd.fd = p_m_g_gsm_b_sock; - register_fd(&p_m_g_gsm_b_fd, LCR_FD_READ, b_handler, this, 0); - - - /* bind socket to bchannel */ - addr.family = AF_ISDN; - addr.dev = mISDNloop.port; - addr.channel = index+1+(index>15); - ret = bind(p_m_g_gsm_b_sock, (struct sockaddr *)&addr, sizeof(addr)); - if (ret < 0) { - PERROR("Failed to bind bchannel-socket for index %d\n", index); - bchannel_close(); - return(ret); - } - /* activate bchannel */ - PDEBUG(DEBUG_GSM, "Activating GSM side channel index %i.\n", index); - act.prim = PH_ACTIVATE_REQ; - act.id = 0; - ret = sendto(p_m_g_gsm_b_sock, &act, MISDN_HEADER_LEN, 0, NULL, 0); - if (ret < 0) { - PERROR("Failed to activate index %d\n", index); - bchannel_close(); - return(ret); + if ((frame->data[0]>>4) != 0xd) + PERROR("received GSM frame with wrong magig 0x%x\n", frame->data[0]>>4); + + /* decode */ + gsm_audio_decode(p_g_decoder, frame->data, samples); + for (i = 0; i < 160; i++) { + data[i] = audio_s16_to_law[samples[i] & 0xffff]; } - p_m_g_gsm_b_index = index; - - return(0); + /* send to remote*/ + bridge_tx(data, 160); } -/* receive from bchannel */ -void Pgsm::bchannel_receive(struct mISDNhead *hh, unsigned char *data, int len) +/* send traffic to gsm */ +int Pgsm::bridge_rx(unsigned char *data, int len) { unsigned char frame[33]; /* encoder init failed */ - if (!p_m_g_encoder) - return; + if (!p_g_encoder) + return -EINVAL; /* (currently) not connected, so don't flood tch! */ - if (!p_m_g_tch_connected) - return; + if (!p_g_tch_connected) + return -EINVAL; /* write to rx buffer */ while(len--) { - p_m_g_rxdata[p_m_g_rxpos++] = audio_law_to_s32[*data++]; - if (p_m_g_rxpos == 160) { - p_m_g_rxpos = 0; + p_g_rxdata[p_g_rxpos++] = audio_law_to_s32[*data++]; + if (p_g_rxpos == 160) { + p_g_rxpos = 0; /* encode data */ - gsm_audio_encode(p_m_g_encoder, p_m_g_rxdata, frame); + gsm_audio_encode(p_g_encoder, p_g_rxdata, frame); frame_send(frame); } } -} - -/* transmit to bchannel */ -void Pgsm::bchannel_send(unsigned int prim, unsigned int id, unsigned char *data, int len) -{ - unsigned char buf[MISDN_HEADER_LEN+len]; - struct mISDNhead *hh = (struct mISDNhead *)buf; - int ret; - - if (!p_m_g_gsm_b_active) - return; - /* make and send frame */ - hh->prim = PH_DATA_REQ; - hh->id = 0; - memcpy(buf+MISDN_HEADER_LEN, data, len); - ret = sendto(p_m_g_gsm_b_sock, buf, MISDN_HEADER_LEN+len, 0, NULL, 0); - if (ret <= 0) - PERROR("Failed to send to socket index %d\n", p_m_g_gsm_b_index); + return 0; } void Pgsm::frame_send(void *_frame) @@ -291,45 +247,29 @@ void Pgsm::frame_send(void *_frame) struct gsm_data_frame *frame = (struct gsm_data_frame *)buffer; frame->msg_type = GSM_TCHF_FRAME; - frame->callref = p_m_g_callref; + frame->callref = p_g_callref; memcpy(frame->data, _frame, 33); - if (p_m_g_lcr_gsm) { - mncc_send(p_m_g_lcr_gsm, frame->msg_type, frame); - } -} - - -void Pgsm::frame_receive(void *arg) -{ - struct gsm_data_frame *frame = (struct gsm_data_frame *)arg; - signed short samples[160]; - unsigned char data[160]; - int i; - - if (!p_m_g_decoder) - return; - - if ((frame->data[0]>>4) != 0xd) - PERROR("received GSM frame with wrong magig 0x%x\n", frame->data[0]>>4); - - /* decode */ - gsm_audio_decode(p_m_g_decoder, frame->data, samples); - for (i = 0; i < 160; i++) { - data[i] = audio_s16_to_law[samples[i] & 0xffff]; + if (p_g_lcr_gsm) { + mncc_send(p_g_lcr_gsm, frame->msg_type, frame); } - - /* send */ - bchannel_send(PH_DATA_REQ, 0, data, 160); } - /* * create trace */ -void gsm_trace_header(struct mISDNport *mISDNport, class PmISDN *port, unsigned int msg_type, int direction) +void gsm_trace_header(const char *interface_name, class Pgsm *port, unsigned int msg_type, int direction) { char msgtext[64]; + struct interface *interface = interface_first; + + while (interface) { + if (!strcmp(interface->name, interface_name)) + break; + interface = interface->next; + } + if (!interface) + return; /* select message and primitive text */ SCPY(msgtext, mncc_name(msg_type)); @@ -350,8 +290,8 @@ void gsm_trace_header(struct mISDNport *mISDNport, class PmISDN *port, unsigned SCAT(msgtext, " ----"); /* init trace with given values */ - start_trace(mISDNport?mISDNport->portnum:-1, - mISDNport?(mISDNport->ifport?mISDNport->ifport->interface:NULL):NULL, + start_trace(0, + interface, port?numberrize_callerinfo(port->p_callerinfo.id, port->p_callerinfo.ntype, options.national, options.international):NULL, port?port->p_dialinginfo.id:NULL, direction, @@ -360,18 +300,12 @@ void gsm_trace_header(struct mISDNport *mISDNport, class PmISDN *port, unsigned msgtext); } -/* select free bchannel from loopback interface */ -int Pgsm::hunt_bchannel(void) -{ - return loop_hunt_bchannel(this, p_m_mISDNport); -} - /* PROCEEDING INDICATION */ void Pgsm::call_conf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc) { struct gsm_mncc *mode; - gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN); + gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN); if (mncc->fields & MNCC_F_CAUSE) { add_trace("cause", "coding", "%d", mncc->cause.coding); add_trace("cause", "location", "%", mncc->cause.location); @@ -380,13 +314,13 @@ void Pgsm::call_conf_ind(unsigned int msg_type, unsigned int callref, struct gsm end_trace(); /* modify lchan to GSM codec V1 */ - gsm_trace_header(p_m_mISDNport, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT); - mode = create_mncc(MNCC_LCHAN_MODIFY, p_m_g_callref); + gsm_trace_header(p_g_interface_name, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT); + mode = create_mncc(MNCC_LCHAN_MODIFY, p_g_callref); mode->lchan_mode = 0x01; /* GSM V1 */ mode->lchan_type = 0x02; add_trace("mode", NULL, "0x%02x", mode->lchan_mode); end_trace(); - send_and_free_mncc(p_m_g_lcr_gsm, mode->msg_type, mode); + send_and_free_mncc(p_g_lcr_gsm, mode->msg_type, mode); } @@ -396,7 +330,7 @@ void Pgsm::call_proc_ind(unsigned int msg_type, unsigned int callref, struct gsm struct lcr_msg *message; struct gsm_mncc *frame; - gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN); + gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN); end_trace(); message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROCEEDING); @@ -404,12 +338,12 @@ void Pgsm::call_proc_ind(unsigned int msg_type, unsigned int callref, struct gsm new_state(PORT_STATE_OUT_PROCEEDING); - if (p_m_mISDNport->earlyb && !p_m_g_tch_connected) { /* only if ... */ - gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT); + if (p_g_earlyb && !p_g_tch_connected) { /* only if ... */ + gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT); end_trace(); - frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref); - send_and_free_mncc(p_m_g_lcr_gsm, frame->msg_type, frame); - p_m_g_tch_connected = 1; + frame = create_mncc(MNCC_FRAME_RECV, p_g_callref); + send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame); + p_g_tch_connected = 1; } } @@ -419,7 +353,7 @@ void Pgsm::alert_ind(unsigned int msg_type, unsigned int callref, struct gsm_mnc struct lcr_msg *message; struct gsm_mncc *frame; - gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN); + gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN); end_trace(); message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ALERTING); @@ -427,12 +361,12 @@ void Pgsm::alert_ind(unsigned int msg_type, unsigned int callref, struct gsm_mnc new_state(PORT_STATE_OUT_ALERTING); - if (p_m_mISDNport->earlyb && !p_m_g_tch_connected) { /* only if ... */ - gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT); + if (p_g_earlyb && !p_g_tch_connected) { /* only if ... */ + gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT); end_trace(); - frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref); - send_and_free_mncc(p_m_g_lcr_gsm, frame->msg_type, frame); - p_m_g_tch_connected = 1; + frame = create_mncc(MNCC_FRAME_RECV, p_g_callref); + send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame); + p_g_tch_connected = 1; } } @@ -447,10 +381,9 @@ void Pgsm::setup_cnf(unsigned int msg_type, unsigned int callref, struct gsm_mnc p_connectinfo.present = INFO_PRESENT_ALLOWED; p_connectinfo.screen = INFO_SCREEN_NETWORK; p_connectinfo.ntype = INFO_NTYPE_UNKNOWN; - p_connectinfo.isdn_port = p_m_portnum; - SCPY(p_connectinfo.interface, p_m_mISDNport->ifport->interface->name); + SCPY(p_connectinfo.interface, p_g_interface_name); - gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN); + gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN); if (p_connectinfo.id[0]) add_trace("connect", "number", "%s", p_connectinfo.id); else if (mncc->imsi[0]) @@ -460,24 +393,34 @@ void Pgsm::setup_cnf(unsigned int msg_type, unsigned int callref, struct gsm_mnc end_trace(); /* send resp */ - gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_COMPL_REQ, DIRECTION_OUT); - resp = create_mncc(MNCC_SETUP_COMPL_REQ, p_m_g_callref); + gsm_trace_header(p_g_interface_name, this, MNCC_SETUP_COMPL_REQ, DIRECTION_OUT); + resp = create_mncc(MNCC_SETUP_COMPL_REQ, p_g_callref); end_trace(); - send_and_free_mncc(p_m_g_lcr_gsm, resp->msg_type, resp); - - message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_CONNECT); - memcpy(&message->param.connectinfo, &p_connectinfo, sizeof(struct connect_info)); - message_put(message); + send_and_free_mncc(p_g_lcr_gsm, resp->msg_type, resp); new_state(PORT_STATE_CONNECT); - if (!p_m_g_tch_connected) { /* only if ... */ - gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT); + if (!p_g_tch_connected) { /* only if ... */ + gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT); end_trace(); - frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref); - send_and_free_mncc(p_m_g_lcr_gsm, frame->msg_type, frame); - p_m_g_tch_connected = 1; + frame = create_mncc(MNCC_FRAME_RECV, p_g_callref); + send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame); + p_g_tch_connected = 1; } + + message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_CONNECT); + memcpy(&message->param.connectinfo, &p_connectinfo, sizeof(struct connect_info)); + message->param.connectinfo.rtpinfo.payload_type = 3; /* FIXME: receive payload type from peer */ + + if (p_g_rtp_bridge) { + struct gsm_mncc_rtp *rtp; + + PDEBUG(DEBUG_GSM, "Request RTP peer info, before forwarding connect msg\n"); + p_g_connect_pending = message; + rtp = (struct gsm_mncc_rtp *) create_mncc(MNCC_RTP_CREATE, p_g_callref); + send_and_free_mncc(p_g_lcr_gsm, rtp->msg_type, rtp); + } else + message_put(message); } /* CONNECT ACK INDICATION */ @@ -485,17 +428,17 @@ void Pgsm::setup_compl_ind(unsigned int msg_type, unsigned int callref, struct g { struct gsm_mncc *frame; - gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN); + gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN); end_trace(); new_state(PORT_STATE_CONNECT); - if (!p_m_g_tch_connected) { /* only if ... */ - gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT); + if (!p_g_tch_connected) { /* only if ... */ + gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT); end_trace(); - frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref); - send_and_free_mncc(p_m_g_lcr_gsm, frame->msg_type, frame); - p_m_g_tch_connected = 1; + frame = create_mncc(MNCC_FRAME_RECV, p_g_callref); + send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame); + p_g_tch_connected = 1; } } @@ -506,7 +449,7 @@ void Pgsm::disc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc int cause = 16, location = 0; struct gsm_mncc *resp; - gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN); + gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN); if (mncc->fields & MNCC_F_CAUSE) { location = mncc->cause.location; cause = mncc->cause.value; @@ -517,8 +460,8 @@ void Pgsm::disc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc end_trace(); /* send release */ - resp = create_mncc(MNCC_REL_REQ, p_m_g_callref); - gsm_trace_header(p_m_mISDNport, this, MNCC_REL_REQ, DIRECTION_OUT); + resp = create_mncc(MNCC_REL_REQ, p_g_callref); + gsm_trace_header(p_g_interface_name, this, MNCC_REL_REQ, DIRECTION_OUT); #if 0 resp->fields |= MNCC_F_CAUSE; resp->cause.coding = 3; @@ -529,7 +472,7 @@ void Pgsm::disc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc add_trace("cause", "value", "%d", resp->cause.value); #endif end_trace(); - send_and_free_mncc(p_m_g_lcr_gsm, resp->msg_type, resp); + send_and_free_mncc(p_g_lcr_gsm, resp->msg_type, resp); /* sending release to endpoint */ while(p_epointlist) { @@ -541,7 +484,7 @@ void Pgsm::disc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc free_epointlist(p_epointlist); } new_state(PORT_STATE_RELEASE); - trigger_work(&p_m_g_delete); + trigger_work(&p_g_delete); } /* CC_RELEASE INDICATION */ @@ -550,7 +493,7 @@ void Pgsm::rel_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc int location = 0, cause = 16; struct lcr_msg *message; - gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN); + gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN); if (mncc->fields & MNCC_F_CAUSE) { location = mncc->cause.location; cause = mncc->cause.value; @@ -570,7 +513,7 @@ void Pgsm::rel_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc free_epointlist(p_epointlist); } new_state(PORT_STATE_RELEASE); - trigger_work(&p_m_g_delete); + trigger_work(&p_g_delete); } /* NOTIFY INDICATION */ @@ -578,7 +521,7 @@ void Pgsm::notify_ind(unsigned int msg_type, unsigned int callref, struct gsm_mn { struct lcr_msg *message; - gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN); + gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN); add_trace("notify", NULL, "%d", mncc->notify); end_trace(); @@ -598,31 +541,93 @@ void Pgsm::message_notify(unsigned int epoint_id, int message_id, union paramete notify = param->notifyinfo.notify & 0x7f; if (p_state!=PORT_STATE_CONNECT /*&& p_state!=PORT_STATE_IN_PROCEEDING*/ && p_state!=PORT_STATE_IN_ALERTING) { /* queue notification */ - if (p_m_g_notify_pending) - message_free(p_m_g_notify_pending); - p_m_g_notify_pending = message_create(ACTIVE_EPOINT(p_epointlist), p_serial, EPOINT_TO_PORT, message_id); - memcpy(&p_m_g_notify_pending->param, param, sizeof(union parameter)); + if (p_g_notify_pending) + message_free(p_g_notify_pending); + p_g_notify_pending = message_create(ACTIVE_EPOINT(p_epointlist), p_serial, EPOINT_TO_PORT, message_id); + memcpy(&p_g_notify_pending->param, param, sizeof(union parameter)); } else { /* sending notification */ - gsm_trace_header(p_m_mISDNport, this, MNCC_NOTIFY_REQ, DIRECTION_OUT); + gsm_trace_header(p_g_interface_name, this, MNCC_NOTIFY_REQ, DIRECTION_OUT); add_trace("notify", NULL, "%d", notify); end_trace(); - mncc = create_mncc(MNCC_NOTIFY_REQ, p_m_g_callref); + mncc = create_mncc(MNCC_NOTIFY_REQ, p_g_callref); mncc->notify = notify; - send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc); + send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc); } } } +/* RTP create indication */ +void Pgsm::rtp_create_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc) +{ + struct gsm_mncc_rtp *rtp = (struct gsm_mncc_rtp *) mncc; + + /* send queued setup, as we received remote RTP info */ + if (p_g_setup_pending) { + struct lcr_msg *message; + + message = p_g_setup_pending; + PDEBUG(DEBUG_GSM, "Got RTP peer info (%08x,%d) forwarding setup\n", rtp->ip, rtp->port); + message->param.setup.rtpinfo.ip = rtp->ip; + message->param.setup.rtpinfo.port = rtp->port; + message_put(message); + p_g_setup_pending = NULL; + } + if (p_g_connect_pending) { + struct gsm_mncc_rtp *nrtp; + + PDEBUG(DEBUG_GSM, "Got RTP peer info (%08x,%d) connecting RTP... \n", rtp->ip, rtp->port); + nrtp = (struct gsm_mncc_rtp *) create_mncc(MNCC_RTP_CONNECT, p_g_callref); + nrtp->ip = p_g_rtp_ip_remote; + nrtp->port = p_g_rtp_port_remote; + send_and_free_mncc(p_g_lcr_gsm, nrtp->msg_type, nrtp); + } +} + +/* RTP connect indication */ +void Pgsm::rtp_connect_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc) +{ + struct lcr_msg *message; + struct gsm_mncc_rtp *rtp = (struct gsm_mncc_rtp *) mncc; + + if (p_g_connect_pending) { + message = p_g_connect_pending; + PDEBUG(DEBUG_GSM, "Got RTP peer info (%08x,%d) forwarding connect\n", rtp->ip, rtp->port); + message->param.connectinfo.rtpinfo.ip = rtp->ip; + message->param.connectinfo.rtpinfo.port = rtp->port; + message_put(message); + p_g_connect_pending = NULL; + } +} + +/* MESSAGE_PROGRESS */ +void Pgsm::message_progress(unsigned int epoint_id, int message_id, union parameter *param) +{ + if (param->progressinfo.progress == 8) { + PDEBUG(DEBUG_GSM, "Remote provides tones for us\n"); + p_g_tones = 1; + } + + if (param->progressinfo.rtpinfo.port) { + struct gsm_mncc_rtp *rtp; + + PDEBUG(DEBUG_GSM, "CONNECT with RTP peer info, sent to BSC (%08x,%d)\n", param->progressinfo.rtpinfo.ip, param->progressinfo.rtpinfo.port); + rtp = (struct gsm_mncc_rtp *) create_mncc(MNCC_RTP_CONNECT, p_g_callref); + rtp->ip = param->progressinfo.rtpinfo.ip; + rtp->port = param->progressinfo.rtpinfo.port; + send_and_free_mncc(p_g_lcr_gsm, rtp->msg_type, rtp); + } +} + /* MESSAGE_ALERTING */ void Pgsm::message_alerting(unsigned int epoint_id, int message_id, union parameter *param) { struct gsm_mncc *mncc; /* send alert */ - gsm_trace_header(p_m_mISDNport, this, MNCC_ALERT_REQ, DIRECTION_OUT); - mncc = create_mncc(MNCC_ALERT_REQ, p_m_g_callref); - if (p_m_mISDNport->tones) { + gsm_trace_header(p_g_interface_name, this, MNCC_ALERT_REQ, DIRECTION_OUT); + mncc = create_mncc(MNCC_ALERT_REQ, p_g_callref); + if (p_g_tones) { mncc->fields |= MNCC_F_PROGRESS; mncc->progress.coding = 3; /* GSM */ mncc->progress.location = 1; @@ -632,16 +637,16 @@ void Pgsm::message_alerting(unsigned int epoint_id, int message_id, union parame add_trace("progress", "descr", "%d", mncc->progress.descr); } end_trace(); - send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc); + send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc); new_state(PORT_STATE_IN_ALERTING); - if (p_m_mISDNport->tones && !p_m_g_tch_connected) { /* only if ... */ - gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT); + if (p_g_tones && !p_g_tch_connected) { /* only if ... */ + gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT); end_trace(); - mncc = create_mncc(MNCC_FRAME_RECV, p_m_g_callref); - send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc); - p_m_g_tch_connected = 1; + mncc = create_mncc(MNCC_FRAME_RECV, p_g_callref); + send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc); + p_g_tch_connected = 1; } } @@ -653,11 +658,11 @@ void Pgsm::message_connect(unsigned int epoint_id, int message_id, union paramet /* copy connected information */ memcpy(&p_connectinfo, ¶m->connectinfo, sizeof(p_connectinfo)); /* screen outgoing caller id */ - do_screen(1, p_connectinfo.id, sizeof(p_connectinfo.id), &p_connectinfo.ntype, &p_connectinfo.present, p_m_mISDNport->ifport->interface); + do_screen(1, p_connectinfo.id, sizeof(p_connectinfo.id), &p_connectinfo.ntype, &p_connectinfo.present, p_g_interface_name); /* send connect */ - mncc = create_mncc(MNCC_SETUP_RSP, p_m_g_callref); - gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_RSP, DIRECTION_OUT); + mncc = create_mncc(MNCC_SETUP_RSP, p_g_callref); + gsm_trace_header(p_g_interface_name, this, MNCC_SETUP_RSP, DIRECTION_OUT); /* caller information */ mncc->fields |= MNCC_F_CONNECTED; mncc->connected.plan = 1; @@ -706,9 +711,20 @@ void Pgsm::message_connect(unsigned int epoint_id, int message_id, union paramet add_trace("connected", "number", "%s", mncc->connected.number); } end_trace(); - send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc); + send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc); new_state(PORT_STATE_CONNECT_WAITING); + + if (param->connectinfo.rtpinfo.port) { + struct gsm_mncc_rtp *rtp; + + PDEBUG(DEBUG_GSM, "CONNECT with RTP peer info, sent to BSC (%08x,%d)\n", param->connectinfo.rtpinfo.ip, param->connectinfo.rtpinfo.port); + rtp = (struct gsm_mncc_rtp *) create_mncc(MNCC_RTP_CONNECT, p_g_callref); + rtp->ip = param->connectinfo.rtpinfo.ip; + rtp->port = param->connectinfo.rtpinfo.port; + send_and_free_mncc(p_g_lcr_gsm, rtp->msg_type, rtp); + } + } /* MESSAGE_DISCONNECT */ @@ -717,9 +733,9 @@ void Pgsm::message_disconnect(unsigned int epoint_id, int message_id, union para struct gsm_mncc *mncc; /* send disconnect */ - mncc = create_mncc(MNCC_DISC_REQ, p_m_g_callref); - gsm_trace_header(p_m_mISDNport, this, MNCC_DISC_REQ, DIRECTION_OUT); - if (p_m_mISDNport->tones) { + mncc = create_mncc(MNCC_DISC_REQ, p_g_callref); + gsm_trace_header(p_g_interface_name, this, MNCC_DISC_REQ, DIRECTION_OUT); + if (p_g_tones) { mncc->fields |= MNCC_F_PROGRESS; mncc->progress.coding = 3; /* GSM */ mncc->progress.location = 1; @@ -736,16 +752,16 @@ void Pgsm::message_disconnect(unsigned int epoint_id, int message_id, union para add_trace("cause", "location", "%d", mncc->cause.location); add_trace("cause", "value", "%d", mncc->cause.value); end_trace(); - send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc); + send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc); new_state(PORT_STATE_OUT_DISCONNECT); - if (p_m_mISDNport->tones && !p_m_g_tch_connected) { /* only if ... */ - gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT); + if (p_g_tones && !p_g_tch_connected) { /* only if ... */ + gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT); end_trace(); - mncc = create_mncc(MNCC_FRAME_RECV, p_m_g_callref); - send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc); - p_m_g_tch_connected = 1; + mncc = create_mncc(MNCC_FRAME_RECV, p_g_callref); + send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc); + p_g_tch_connected = 1; } } @@ -756,8 +772,8 @@ void Pgsm::message_release(unsigned int epoint_id, int message_id, union paramet struct gsm_mncc *mncc; /* send release */ - mncc = create_mncc(MNCC_REL_REQ, p_m_g_callref); - gsm_trace_header(p_m_mISDNport, this, MNCC_REL_REQ, DIRECTION_OUT); + mncc = create_mncc(MNCC_REL_REQ, p_g_callref); + gsm_trace_header(p_g_interface_name, this, MNCC_REL_REQ, DIRECTION_OUT); mncc->fields |= MNCC_F_CAUSE; mncc->cause.coding = 3; mncc->cause.location = param->disconnectinfo.location; @@ -766,10 +782,10 @@ void Pgsm::message_release(unsigned int epoint_id, int message_id, union paramet add_trace("cause", "location", "%d", mncc->cause.location); add_trace("cause", "value", "%d", mncc->cause.value); end_trace(); - send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc); + send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc); new_state(PORT_STATE_RELEASE); - trigger_work(&p_m_g_delete); + trigger_work(&p_g_delete); return; } @@ -778,11 +794,14 @@ void Pgsm::message_release(unsigned int epoint_id, int message_id, union paramet */ int Pgsm::message_epoint(unsigned int epoint_id, int message_id, union parameter *param) { - if (PmISDN::message_epoint(epoint_id, message_id, param)) - return(1); + int ret = 0; + + if (Port::message_epoint(epoint_id, message_id, param)) + return 1; switch(message_id) { case MESSAGE_NOTIFY: /* display and notifications */ + ret = 1; message_notify(epoint_id, message_id, param); break; @@ -791,34 +810,43 @@ int Pgsm::message_epoint(unsigned int epoint_id, int message_id, union parameter // break; case MESSAGE_PROCEEDING: /* message not handles */ + ret = 1; + break; + + case MESSAGE_PROGRESS: + ret = 1; + message_progress(epoint_id, message_id, param); break; case MESSAGE_ALERTING: /* call of endpoint is ringing */ + ret = 1; if (p_state!=PORT_STATE_IN_PROCEEDING) break; message_alerting(epoint_id, message_id, param); - if (p_m_g_notify_pending) { + if (p_g_notify_pending) { /* send pending notify message during connect */ - message_notify(ACTIVE_EPOINT(p_epointlist), p_m_g_notify_pending->type, &p_m_g_notify_pending->param); - message_free(p_m_g_notify_pending); - p_m_g_notify_pending = NULL; + message_notify(ACTIVE_EPOINT(p_epointlist), p_g_notify_pending->type, &p_g_notify_pending->param); + message_free(p_g_notify_pending); + p_g_notify_pending = NULL; } break; case MESSAGE_CONNECT: /* call of endpoint is connected */ + ret = 1; if (p_state!=PORT_STATE_IN_PROCEEDING && p_state!=PORT_STATE_IN_ALERTING) break; message_connect(epoint_id, message_id, param); - if (p_m_g_notify_pending) { + if (p_g_notify_pending) { /* send pending notify message during connect */ - message_notify(ACTIVE_EPOINT(p_epointlist), p_m_g_notify_pending->type, &p_m_g_notify_pending->param); - message_free(p_m_g_notify_pending); - p_m_g_notify_pending = NULL; + message_notify(ACTIVE_EPOINT(p_epointlist), p_g_notify_pending->type, &p_g_notify_pending->param); + message_free(p_g_notify_pending); + p_g_notify_pending = NULL; } break; case MESSAGE_DISCONNECT: /* call has been disconnected */ + ret = 1; if (p_state!=PORT_STATE_IN_PROCEEDING && p_state!=PORT_STATE_IN_ALERTING && p_state!=PORT_STATE_OUT_SETUP @@ -832,6 +860,7 @@ int Pgsm::message_epoint(unsigned int epoint_id, int message_id, union parameter break; case MESSAGE_RELEASE: /* release isdn port */ + ret = 1; if (p_state==PORT_STATE_RELEASE) break; message_release(epoint_id, message_id, param); @@ -839,7 +868,7 @@ int Pgsm::message_epoint(unsigned int epoint_id, int message_id, union parameter } - return(0); + return ret; } /* deletes only if l3id is release, otherwhise it will be triggered then */ @@ -852,44 +881,6 @@ static int delete_event(struct lcr_work *work, void *instance, int index) return 0; } -/* - * handler of bchannel events - */ -static int b_handler(struct lcr_fd *fd, unsigned int what, void *instance, int index) -{ - class Pgsm *gsmport = (class Pgsm *)instance; - int ret; - unsigned char buffer[2048+MISDN_HEADER_LEN]; - struct mISDNhead *hh = (struct mISDNhead *)buffer; - - /* handle message from bchannel */ - if (gsmport->p_m_g_gsm_b_sock > -1) { - ret = recv(gsmport->p_m_g_gsm_b_sock, buffer, sizeof(buffer), 0); - if (ret >= (int)MISDN_HEADER_LEN) { - switch(hh->prim) { - /* we don't care about confirms, we use rx data to sync tx */ - case PH_DATA_CNF: - break; - /* we receive audio data, we respond to it AND we send tones */ - case PH_DATA_IND: - gsmport->bchannel_receive(hh, buffer+MISDN_HEADER_LEN, ret-MISDN_HEADER_LEN); - break; - case PH_ACTIVATE_IND: - gsmport->p_m_g_gsm_b_active = 1; - break; - case PH_DEACTIVATE_IND: - gsmport->p_m_g_gsm_b_active = 0; - break; - } - } else { - if (ret < 0 && errno != EWOULDBLOCK) - PERROR("Read from GSM port, index %d failed with return code %d\n", ret); - } - } - - return 0; -} - int gsm_exit(int rc) { return(rc); @@ -985,13 +976,13 @@ static int mncc_fd_close(struct lcr_gsm *lcr_gsm, struct lcr_fd *lfd) while(port) { if ((port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_GSM) { pgsm = (class Pgsm *)port; - if (pgsm->p_m_g_lcr_gsm == lcr_gsm) { + if (pgsm->p_g_lcr_gsm == lcr_gsm) { message = message_create(pgsm->p_serial, ACTIVE_EPOINT(pgsm->p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE); message->param.disconnectinfo.cause = 27; // temp. unavail. message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; message_put(message); pgsm->new_state(PORT_STATE_RELEASE); - trigger_work(&pgsm->p_m_g_delete); + trigger_work(&pgsm->p_g_delete); } } port = port->next; diff --git a/gsm.h b/gsm.h index 3ecaf0d..254797e 100644 --- a/gsm.h +++ b/gsm.h @@ -15,6 +15,7 @@ enum { }; struct lcr_gsm { + struct interface *interface; /* interface this instance is associated to */ struct lcr_gsm *gsm_ms_next; /* list of MS instances, in case of MS */ char name[16]; /* name of MS instance, in case of MS */ int type; /* LCR_GSM_TYPE_*/ @@ -27,33 +28,38 @@ struct lcr_gsm { }; /* GSM port class */ -class Pgsm : public PmISDN +class Pgsm : public Port { public: - Pgsm(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode); + Pgsm(int type, char *portname, struct port_settings *settings, struct interface *interface); ~Pgsm(); - struct lcr_gsm *p_m_g_lcr_gsm; /* pointer to network/ms instance */ - unsigned int p_m_g_callref; /* ref by OpenBSC/Osmocom-BB */ - struct lcr_work p_m_g_delete; /* queue destruction of GSM port instance */ - unsigned int p_m_g_mode; /* data/transparent mode */ - int p_m_g_gsm_b_sock; /* gsm bchannel socket */ - struct lcr_fd p_m_g_gsm_b_fd; /* event node */ - int p_m_g_gsm_b_index; /* gsm bchannel socket index to use */ - int p_m_g_gsm_b_active; /* gsm bchannel socket is activated */ - struct lcr_msg *p_m_g_notify_pending; /* queue for NOTIFY if not connected */ - void *p_m_g_encoder, *p_m_g_decoder; /* gsm handle */ - signed short p_m_g_rxdata[160]; /* receive audio buffer */ - int p_m_g_rxpos; /* position in audio buffer 0..159 */ - int p_m_g_tch_connected; /* indicates if audio is connected */ + char p_g_interface_name[64]; + int p_g_tones; /* set, if tones are to be generated */ + int p_g_earlyb; /* set, if patterns are available */ + struct lcr_gsm *p_g_lcr_gsm; /* pointer to network/ms instance */ + unsigned int p_g_callref; /* ref by OpenBSC/Osmocom-BB */ + struct lcr_work p_g_delete; /* queue destruction of GSM port instance */ + unsigned int p_g_mode; /* data/transparent mode */ + int p_g_gsm_b_sock; /* gsm bchannel socket */ + struct lcr_fd p_g_gsm_b_fd; /* event node */ + int p_g_gsm_b_index; /* gsm bchannel socket index to use */ + int p_g_gsm_b_active; /* gsm bchannel socket is activated */ + struct lcr_msg *p_g_notify_pending; /* queue for NOTIFY if not connected */ + struct lcr_msg *p_g_setup_pending; /* queue SETUP until RTP is created */ + struct lcr_msg *p_g_connect_pending; /* queue CONNECT until RTP is created and connected */ + void *p_g_encoder, *p_g_decoder; /* gsm handle */ + signed short p_g_rxdata[160]; /* receive audio buffer */ + int p_g_rxpos; /* position in audio buffer 0..159 */ + int p_g_tch_connected; /* indicates if audio is connected */ - void bchannel_close(void); - int bchannel_open(int index); - void bchannel_receive(struct mISDNhead *hh, unsigned char *data, int len); - void bchannel_send(unsigned int prim, unsigned int id, unsigned char *data, int len); + int p_g_rtp_bridge; /* if we use a bridge */ + unsigned int p_g_rtp_ip_remote; /* stores ip */ + unsigned short p_g_rtp_port_remote; /* stores port */ void frame_send(void *_frame); void frame_receive(void *_frame); + int bridge_rx(unsigned char *data, int len); int hunt_bchannel(void); void call_conf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *gsm); @@ -64,7 +70,10 @@ class Pgsm : public PmISDN void disc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc); void rel_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc); void notify_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc); + void rtp_create_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc); + void rtp_connect_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc); void message_notify(unsigned int epoint_id, int message_id, union parameter *param); + void message_progress(unsigned int epoint_id, int message_id, union parameter *param); void message_alerting(unsigned int epoint_id, int message_id, union parameter *param); void message_connect(unsigned int epoint_id, int message_id, union parameter *param); void message_disconnect(unsigned int epoint_id, int message_id, union parameter *param); @@ -74,7 +83,7 @@ class Pgsm : public PmISDN struct gsm_mncc *create_mncc(int msg_type, unsigned int callref); int send_and_free_mncc(struct lcr_gsm *lcr_gsm, unsigned int msg_type, void *data); -void gsm_trace_header(struct mISDNport *mISDNport, class PmISDN *port, unsigned int msg_type, int direction); +void gsm_trace_header(const char *interface_name, class Pgsm *port, unsigned int msg_type, int direction); int gsm_conf(struct gsm_conf *gsm_conf, char *conf_error); int gsm_exit(int rc); int gsm_init(void); diff --git a/gsm_bs.cpp b/gsm_bs.cpp index d281bc9..902065b 100644 --- a/gsm_bs.cpp +++ b/gsm_bs.cpp @@ -45,11 +45,11 @@ void generate_dtmf(void) /* * constructor */ -Pgsm_bs::Pgsm_bs(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode) : Pgsm(type, mISDNport, portname, settings, channel, exclusive, mode) +Pgsm_bs::Pgsm_bs(int type, char *portname, struct port_settings *settings, struct interface *interface) : Pgsm(type, portname, settings, interface) { - p_m_g_lcr_gsm = gsm_bs; - p_m_g_dtmf = NULL; - p_m_g_dtmf_index = 0; + p_g_lcr_gsm = gsm_bs; + p_g_dtmf = NULL; + p_g_dtmf_index = 0; PDEBUG(DEBUG_GSM, "Created new GSMBSPort(%s).\n", portname); } @@ -65,74 +65,74 @@ Pgsm_bs::~Pgsm_bs() /* DTMF INDICATION */ void Pgsm_bs::start_dtmf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc) { -// struct lcr_msg *message; + struct lcr_msg *message; struct gsm_mncc *resp; - gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN); + gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN); add_trace("keypad", NULL, "%c", mncc->keypad); end_trace(); SPRINT(p_dialinginfo.id, "%c", mncc->keypad); p_dialinginfo.ntype = INFO_NTYPE_UNKNOWN; /* send resp */ - gsm_trace_header(p_m_mISDNport, this, MNCC_START_DTMF_RSP, DIRECTION_OUT); + gsm_trace_header(p_g_interface_name, this, MNCC_START_DTMF_RSP, DIRECTION_OUT); add_trace("keypad", NULL, "%c", mncc->keypad); end_trace(); - resp = create_mncc(MNCC_START_DTMF_RSP, p_m_g_callref); + resp = create_mncc(MNCC_START_DTMF_RSP, p_g_callref); resp->fields |= MNCC_F_KEYPAD; resp->keypad = mncc->keypad; - send_and_free_mncc(p_m_g_lcr_gsm, resp->msg_type, resp); - -#if 0 - /* send dialing information */ - message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_INFORMATION); - memcpy(&message->param.information, &p_dialinginfo, sizeof(struct dialing_info)); - message_put(message); -#endif + send_and_free_mncc(p_g_lcr_gsm, resp->msg_type, resp); - /* generate DTMF tones */ - switch (mncc->keypad) { - case '1': p_m_g_dtmf = dtmf_samples[0]; break; - case '2': p_m_g_dtmf = dtmf_samples[1]; break; - case '3': p_m_g_dtmf = dtmf_samples[2]; break; - case 'a': - case 'A': p_m_g_dtmf = dtmf_samples[3]; break; - case '4': p_m_g_dtmf = dtmf_samples[4]; break; - case '5': p_m_g_dtmf = dtmf_samples[5]; break; - case '6': p_m_g_dtmf = dtmf_samples[6]; break; - case 'b': - case 'B': p_m_g_dtmf = dtmf_samples[7]; break; - case '7': p_m_g_dtmf = dtmf_samples[8]; break; - case '8': p_m_g_dtmf = dtmf_samples[9]; break; - case '9': p_m_g_dtmf = dtmf_samples[10]; break; - case 'c': - case 'C': p_m_g_dtmf = dtmf_samples[11]; break; - case '*': p_m_g_dtmf = dtmf_samples[12]; break; - case '0': p_m_g_dtmf = dtmf_samples[13]; break; - case '#': p_m_g_dtmf = dtmf_samples[14]; break; - case 'd': - case 'D': p_m_g_dtmf = dtmf_samples[15]; break; + if (p_g_rtp_bridge) { + /* send dtmf information, because we bridge RTP directly */ + message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_DTMF); + message->param.dtmf = mncc->keypad; + message_put(message); + } else { + /* generate DTMF tones, since we do audio forwarding inside LCR */ + switch (mncc->keypad) { + case '1': p_g_dtmf = dtmf_samples[0]; break; + case '2': p_g_dtmf = dtmf_samples[1]; break; + case '3': p_g_dtmf = dtmf_samples[2]; break; + case 'a': + case 'A': p_g_dtmf = dtmf_samples[3]; break; + case '4': p_g_dtmf = dtmf_samples[4]; break; + case '5': p_g_dtmf = dtmf_samples[5]; break; + case '6': p_g_dtmf = dtmf_samples[6]; break; + case 'b': + case 'B': p_g_dtmf = dtmf_samples[7]; break; + case '7': p_g_dtmf = dtmf_samples[8]; break; + case '8': p_g_dtmf = dtmf_samples[9]; break; + case '9': p_g_dtmf = dtmf_samples[10]; break; + case 'c': + case 'C': p_g_dtmf = dtmf_samples[11]; break; + case '*': p_g_dtmf = dtmf_samples[12]; break; + case '0': p_g_dtmf = dtmf_samples[13]; break; + case '#': p_g_dtmf = dtmf_samples[14]; break; + case 'd': + case 'D': p_g_dtmf = dtmf_samples[15]; break; + } + p_g_dtmf_index = 0; } - p_m_g_dtmf_index = 0; } void Pgsm_bs::stop_dtmf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc) { struct gsm_mncc *resp; - gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN); + gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN); add_trace("keypad", NULL, "%c", mncc->keypad); end_trace(); /* send resp */ - gsm_trace_header(p_m_mISDNport, this, MNCC_STOP_DTMF_RSP, DIRECTION_OUT); + gsm_trace_header(p_g_interface_name, this, MNCC_STOP_DTMF_RSP, DIRECTION_OUT); add_trace("keypad", NULL, "%c", mncc->keypad); end_trace(); - resp = create_mncc(MNCC_STOP_DTMF_RSP, p_m_g_callref); + resp = create_mncc(MNCC_STOP_DTMF_RSP, p_g_callref); resp->keypad = mncc->keypad; - send_and_free_mncc(p_m_g_lcr_gsm, resp->msg_type, resp); + send_and_free_mncc(p_g_lcr_gsm, resp->msg_type, resp); /* stop DTMF */ - p_m_g_dtmf = NULL; + p_g_dtmf = NULL; } /* HOLD INDICATION */ @@ -141,7 +141,7 @@ void Pgsm_bs::hold_ind(unsigned int msg_type, unsigned int callref, struct gsm_m struct lcr_msg *message; struct gsm_mncc *resp, *frame; - gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN); + gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN); end_trace(); /* notify the hold of call */ @@ -151,18 +151,18 @@ void Pgsm_bs::hold_ind(unsigned int msg_type, unsigned int callref, struct gsm_m message_put(message); /* acknowledge hold */ - gsm_trace_header(p_m_mISDNport, this, MNCC_HOLD_CNF, DIRECTION_OUT); + gsm_trace_header(p_g_interface_name, this, MNCC_HOLD_CNF, DIRECTION_OUT); end_trace(); - resp = create_mncc(MNCC_HOLD_CNF, p_m_g_callref); - send_and_free_mncc(p_m_g_lcr_gsm, resp->msg_type, resp); + resp = create_mncc(MNCC_HOLD_CNF, p_g_callref); + send_and_free_mncc(p_g_lcr_gsm, resp->msg_type, resp); /* disable audio */ - if (p_m_g_tch_connected) { /* it should be true */ - gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_DROP, DIRECTION_OUT); + if (p_g_tch_connected) { /* it should be true */ + gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_DROP, DIRECTION_OUT); end_trace(); - frame = create_mncc(MNCC_FRAME_DROP, p_m_g_callref); - send_and_free_mncc(p_m_g_lcr_gsm, frame->msg_type, frame); - p_m_g_tch_connected = 0; + frame = create_mncc(MNCC_FRAME_DROP, p_g_callref); + send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame); + p_g_tch_connected = 0; } } @@ -173,7 +173,7 @@ void Pgsm_bs::retr_ind(unsigned int msg_type, unsigned int callref, struct gsm_m struct lcr_msg *message; struct gsm_mncc *resp, *frame; - gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN); + gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN); end_trace(); /* notify the retrieve of call */ @@ -183,18 +183,18 @@ void Pgsm_bs::retr_ind(unsigned int msg_type, unsigned int callref, struct gsm_m message_put(message); /* acknowledge retr */ - gsm_trace_header(p_m_mISDNport, this, MNCC_RETRIEVE_CNF, DIRECTION_OUT); + gsm_trace_header(p_g_interface_name, this, MNCC_RETRIEVE_CNF, DIRECTION_OUT); end_trace(); - resp = create_mncc(MNCC_RETRIEVE_CNF, p_m_g_callref); - send_and_free_mncc(p_m_g_lcr_gsm, resp->msg_type, resp); + resp = create_mncc(MNCC_RETRIEVE_CNF, p_g_callref); + send_and_free_mncc(p_g_lcr_gsm, resp->msg_type, resp); /* enable audio */ - if (!p_m_g_tch_connected) { /* it should be true */ - gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT); + if (!p_g_tch_connected) { /* it should be true */ + gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT); end_trace(); - frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref); - send_and_free_mncc(p_m_g_lcr_gsm, frame->msg_type, frame); - p_m_g_tch_connected = 1; + frame = create_mncc(MNCC_FRAME_RECV, p_g_callref); + send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame); + p_g_tch_connected = 1; } } @@ -204,21 +204,19 @@ void Pgsm_bs::retr_ind(unsigned int msg_type, unsigned int callref, struct gsm_m /* SETUP INDICATION */ void Pgsm_bs::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc) { - int ret; class Endpoint *epoint; struct lcr_msg *message; - int channel; struct gsm_mncc *mode, *proceeding, *frame; /* process given callref */ - l1l2l3_trace_header(p_m_mISDNport, this, L3_NEW_L3ID_IND, DIRECTION_IN); + gsm_trace_header(p_g_interface_name, this, 0, DIRECTION_IN); add_trace("callref", "new", "0x%x", callref); - if (p_m_g_callref) { + if (p_g_callref) { /* release in case the ID is already in use */ add_trace("error", NULL, "callref already in use"); end_trace(); mncc = create_mncc(MNCC_REJ_REQ, callref); - gsm_trace_header(p_m_mISDNport, this, MNCC_REJ_REQ, DIRECTION_OUT); + gsm_trace_header(p_g_interface_name, this, MNCC_REJ_REQ, DIRECTION_OUT); mncc->fields |= MNCC_F_CAUSE; mncc->cause.coding = 3; mncc->cause.location = 1; @@ -228,33 +226,14 @@ void Pgsm_bs::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_ add_trace("cause", "value", "%d", mncc->cause.value); add_trace("reason", NULL, "callref already in use"); end_trace(); - send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc); + send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc); new_state(PORT_STATE_RELEASE); - trigger_work(&p_m_g_delete); + trigger_work(&p_g_delete); return; } - p_m_g_callref = callref; + p_g_callref = callref; end_trace(); - /* if blocked, release call with MT_RELEASE_COMPLETE */ - if (p_m_mISDNport->ifport->block) { - mncc = create_mncc(MNCC_REJ_REQ, p_m_g_callref); - gsm_trace_header(p_m_mISDNport, this, MNCC_REJ_REQ, DIRECTION_OUT); - mncc->fields |= MNCC_F_CAUSE; - mncc->cause.coding = 3; - mncc->cause.location = 1; - mncc->cause.value = 27; - add_trace("cause", "coding", "%d", mncc->cause.coding); - add_trace("cause", "location", "%d", mncc->cause.location); - add_trace("cause", "value", "%d", mncc->cause.value); - add_trace("reason", NULL, "port is blocked"); - end_trace(); - send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc); - new_state(PORT_STATE_RELEASE); - trigger_work(&p_m_g_delete); - return; - } - /* caller info */ if (mncc->clir.inv) p_callerinfo.present = INFO_PRESENT_RESTRICTED; @@ -267,8 +246,7 @@ void Pgsm_bs::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_ SCPY(p_callerinfo.imsi, mncc->imsi); p_callerinfo.screen = INFO_SCREEN_NETWORK; p_callerinfo.ntype = INFO_NTYPE_UNKNOWN; - p_callerinfo.isdn_port = p_m_portnum; - SCPY(p_callerinfo.interface, p_m_mISDNport->ifport->interface->name); + SCPY(p_callerinfo.interface, p_g_interface_name); /* dialing information */ SCAT(p_dialinginfo.id, mncc->called.number); @@ -297,41 +275,12 @@ void Pgsm_bs::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_ p_capainfo.bearer_info1 = (options.law=='a')?3:2; p_capainfo.bearer_mode = INFO_BMODE_CIRCUIT; p_capainfo.source_mode = B_MODE_TRANSPARENT; - p_m_g_mode = p_capainfo.source_mode; + p_g_mode = p_capainfo.source_mode; /* useruser */ - /* hunt channel */ - ret = channel = hunt_bchannel(); - if (ret < 0) - goto no_channel; - - /* open channel */ - ret = seize_bchannel(channel, 1); - if (ret < 0) { - no_channel: - mncc = create_mncc(MNCC_REJ_REQ, p_m_g_callref); - gsm_trace_header(p_m_mISDNport, this, MNCC_REJ_REQ, DIRECTION_OUT); - mncc->fields |= MNCC_F_CAUSE; - mncc->cause.coding = 3; - mncc->cause.location = 1; - mncc->cause.value = 34; - add_trace("cause", "coding", "%d", mncc->cause.coding); - add_trace("cause", "location", "%d", mncc->cause.location); - add_trace("cause", "value", "%d", mncc->cause.value); - add_trace("reason", NULL, "no channel"); - end_trace(); - send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc); - new_state(PORT_STATE_RELEASE); - trigger_work(&p_m_g_delete); - return; - } - bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE); - if (bchannel_open(p_m_b_index)) - goto no_channel; - /* what infos did we got ... */ - gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN); + gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN); if (p_callerinfo.id[0]) add_trace("calling", "number", "%s", p_callerinfo.id); else @@ -350,18 +299,18 @@ void Pgsm_bs::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_ epointlist_new(epoint->ep_serial); /* modify lchan to GSM codec V1 */ - gsm_trace_header(p_m_mISDNport, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT); - mode = create_mncc(MNCC_LCHAN_MODIFY, p_m_g_callref); + gsm_trace_header(p_g_interface_name, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT); + mode = create_mncc(MNCC_LCHAN_MODIFY, p_g_callref); mode->lchan_mode = 0x01; /* GSM V1 */ mode->lchan_type = 0x02; add_trace("mode", NULL, "0x%02x", mode->lchan_mode); end_trace(); - send_and_free_mncc(p_m_g_lcr_gsm, mode->msg_type, mode); + send_and_free_mncc(p_g_lcr_gsm, mode->msg_type, mode); /* send call proceeding */ - gsm_trace_header(p_m_mISDNport, this, MNCC_CALL_PROC_REQ, DIRECTION_OUT); - proceeding = create_mncc(MNCC_CALL_PROC_REQ, p_m_g_callref); - if (p_m_mISDNport->tones) { + gsm_trace_header(p_g_interface_name, this, MNCC_CALL_PROC_REQ, DIRECTION_OUT); + proceeding = create_mncc(MNCC_CALL_PROC_REQ, p_g_callref); + if (p_g_tones) { proceeding->fields |= MNCC_F_PROGRESS; proceeding->progress.coding = 3; /* GSM */ proceeding->progress.location = 1; @@ -371,21 +320,20 @@ void Pgsm_bs::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_ add_trace("progress", "descr", "%d", proceeding->progress.descr); } end_trace(); - send_and_free_mncc(p_m_g_lcr_gsm, proceeding->msg_type, proceeding); + send_and_free_mncc(p_g_lcr_gsm, proceeding->msg_type, proceeding); new_state(PORT_STATE_IN_PROCEEDING); - if (p_m_mISDNport->tones && !p_m_g_tch_connected) { /* only if ... */ - gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT); + if (p_g_tones && !p_g_tch_connected) { /* only if ... */ + gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT); end_trace(); - frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref); - send_and_free_mncc(p_m_g_lcr_gsm, frame->msg_type, frame); - p_m_g_tch_connected = 1; + frame = create_mncc(MNCC_FRAME_RECV, p_g_callref); + send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame); + p_g_tch_connected = 1; } /* send setup message to endpoit */ message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_SETUP); - message->param.setup.isdn_port = p_m_portnum; message->param.setup.port_type = p_type; // message->param.setup.dtmf = 0; memcpy(&message->param.setup.dialinginfo, &p_dialinginfo, sizeof(struct dialing_info)); @@ -394,7 +342,18 @@ void Pgsm_bs::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_ SCPY((char *)message->param.setup.useruser.data, (char *)mncc->useruser.info); message->param.setup.useruser.len = strlen(mncc->useruser.info); message->param.setup.useruser.protocol = mncc->useruser.proto; - message_put(message); + message->param.setup.rtpinfo.payload_type = 3; /* FIXME: receive payload type from peer */ + + if (p_g_rtp_bridge) { + struct gsm_mncc_rtp *rtp; + + PDEBUG(DEBUG_GSM, "Request RTP peer info, before forwarding setup\n"); + p_g_setup_pending = message; + rtp = (struct gsm_mncc_rtp *) create_mncc(MNCC_RTP_CREATE, p_g_callref); + send_and_free_mncc(p_g_lcr_gsm, rtp->msg_type, rtp); + } else + message_put(message); + } /* @@ -402,12 +361,13 @@ void Pgsm_bs::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_ */ int message_bsc(struct lcr_gsm *lcr_gsm, int msg_type, void *arg) { + struct interface *interface = lcr_gsm->interface; struct gsm_mncc *mncc = (struct gsm_mncc *)arg; unsigned int callref = mncc->callref; class Port *port; class Pgsm_bs *pgsm_bs = NULL; char name[64]; - struct mISDNport *mISDNport; +// struct mISDNport *mISDNport; /* Special messages */ switch(msg_type) { @@ -419,7 +379,7 @@ int message_bsc(struct lcr_gsm *lcr_gsm, int msg_type, void *arg) while(port) { if ((port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_BS) { pgsm_bs = (class Pgsm_bs *)port; - if (pgsm_bs->p_m_g_callref == callref) { + if (pgsm_bs->p_g_callref == callref) { break; } } @@ -429,19 +389,28 @@ int message_bsc(struct lcr_gsm *lcr_gsm, int msg_type, void *arg) if (msg_type == GSM_TCHF_FRAME) { if (port) { /* inject DTMF, if enabled */ - if (pgsm_bs->p_m_g_dtmf) { + if (pgsm_bs->p_g_dtmf) { unsigned char data[160]; int i; for (i = 0; i < 160; i++) { - data[i] = pgsm_bs->p_m_g_dtmf[pgsm_bs->p_m_g_dtmf_index++]; - if (pgsm_bs->p_m_g_dtmf_index == 8000) - pgsm_bs->p_m_g_dtmf_index = 0; + data[i] = pgsm_bs->p_g_dtmf[pgsm_bs->p_g_dtmf_index++]; + if (pgsm_bs->p_g_dtmf_index == 8000) + pgsm_bs->p_g_dtmf_index = 0; } /* send */ - pgsm_bs->bchannel_send(PH_DATA_REQ, 0, data, 160); + pgsm_bs->bridge_tx(data, 160); } else pgsm_bs->frame_receive(arg); + /* if we do not bridge we need to inject audio, if available */ + if (!pgsm_bs->p_bridge) { + unsigned char data[160]; + int i; + + i = pgsm_bs->read_audio(data, 160); + if (i) + pgsm_bs->bridge_rx(data, i); + } } return 0; } @@ -449,6 +418,7 @@ int message_bsc(struct lcr_gsm *lcr_gsm, int msg_type, void *arg) if (!port) { if (msg_type != MNCC_SETUP_IND) return(0); +#if 0 /* find gsm port */ mISDNport = mISDNport_first; while(mISDNport) { @@ -472,10 +442,10 @@ int message_bsc(struct lcr_gsm *lcr_gsm, int msg_type, void *arg) send_and_free_mncc(lcr_gsm, rej->msg_type, rej); return 0; } +#endif /* creating port object, transparent until setup with hdlc */ - SPRINT(name, "%s-%d-in", mISDNport->ifport->interface->name, mISDNport->portnum); - if (!(pgsm_bs = new Pgsm_bs(PORT_TYPE_GSM_BS_IN, mISDNport, name, NULL, 0, 0, B_MODE_TRANSPARENT))) - + SPRINT(name, "%s-%d-in", interface->name, 0); + if (!(pgsm_bs = new Pgsm_bs(PORT_TYPE_GSM_BS_IN, name, NULL, interface))) FATAL("Cannot create Port instance.\n"); } @@ -484,6 +454,14 @@ int message_bsc(struct lcr_gsm *lcr_gsm, int msg_type, void *arg) pgsm_bs->setup_ind(msg_type, callref, mncc); break; + case MNCC_RTP_CREATE: + pgsm_bs->rtp_create_ind(msg_type, callref, mncc); + break; + + case MNCC_RTP_CONNECT: + pgsm_bs->rtp_connect_ind(msg_type, callref, mncc); + break; + case MNCC_START_DTMF_IND: pgsm_bs->start_dtmf_ind(msg_type, callref, mncc); break; @@ -540,10 +518,8 @@ int message_bsc(struct lcr_gsm *lcr_gsm, int msg_type, void *arg) void Pgsm_bs::message_setup(unsigned int epoint_id, int message_id, union parameter *param) { struct lcr_msg *message; - int ret; struct epoint_list *epointlist; struct gsm_mncc *mncc; - int channel; /* copy setup infos to port */ memcpy(&p_callerinfo, ¶m->setup.callerinfo, sizeof(p_callerinfo)); @@ -552,8 +528,8 @@ void Pgsm_bs::message_setup(unsigned int epoint_id, int message_id, union parame memcpy(&p_redirinfo, ¶m->setup.redirinfo, sizeof(p_redirinfo)); /* no GSM MNCC connection */ - if (p_m_g_lcr_gsm->mncc_lfd.fd < 0) { - gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT); + if (p_g_lcr_gsm->mncc_lfd.fd < 0) { + gsm_trace_header(p_g_interface_name, this, MNCC_SETUP_REQ, DIRECTION_OUT); add_trace("failure", NULL, "No MNCC connection."); end_trace(); message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE); @@ -561,13 +537,13 @@ void Pgsm_bs::message_setup(unsigned int epoint_id, int message_id, union parame message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; message_put(message); new_state(PORT_STATE_RELEASE); - trigger_work(&p_m_g_delete); + trigger_work(&p_g_delete); return; } /* no number */ if (!p_dialinginfo.id[0]) { - gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT); + gsm_trace_header(p_g_interface_name, this, MNCC_SETUP_REQ, DIRECTION_OUT); add_trace("failure", NULL, "No dialed subscriber given."); end_trace(); message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE); @@ -575,50 +551,13 @@ void Pgsm_bs::message_setup(unsigned int epoint_id, int message_id, union parame message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; message_put(message); new_state(PORT_STATE_RELEASE); - trigger_work(&p_m_g_delete); - return; - } - - /* release if port is blocked */ - if (p_m_mISDNport->ifport->block) { - gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT); - add_trace("failure", NULL, "Port blocked."); - end_trace(); - message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE); - message->param.disconnectinfo.cause = 27; // temp. unavail. - message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; - message_put(message); - new_state(PORT_STATE_RELEASE); - trigger_work(&p_m_g_delete); + trigger_work(&p_g_delete); return; } - /* hunt channel */ - ret = channel = hunt_bchannel(); - if (ret < 0) - goto no_channel; - /* open channel */ - ret = seize_bchannel(channel, 1); - if (ret < 0) { - no_channel: - gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT); - add_trace("failure", NULL, "No internal audio channel available."); - end_trace(); - message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE); - message->param.disconnectinfo.cause = 34; - message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; - message_put(message); - new_state(PORT_STATE_RELEASE); - trigger_work(&p_m_g_delete); - return; - } - bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE); - if (bchannel_open(p_m_b_index)) - goto no_channel; - // SCPY(&p_m_tones_dir, param->setup.ext.tones_dir); /* screen outgoing caller id */ - do_screen(1, p_callerinfo.id, sizeof(p_callerinfo.id), &p_callerinfo.ntype, &p_callerinfo.present, p_m_mISDNport->ifport->interface); + do_screen(1, p_callerinfo.id, sizeof(p_callerinfo.id), &p_callerinfo.ntype, &p_callerinfo.present, p_g_interface_name); /* attach only if not already */ epointlist = p_epointlist; @@ -631,13 +570,13 @@ void Pgsm_bs::message_setup(unsigned int epoint_id, int message_id, union parame epointlist_new(epoint_id); /* creating l3id */ - l1l2l3_trace_header(p_m_mISDNport, this, L3_NEW_L3ID_REQ, DIRECTION_OUT); - p_m_g_callref = new_callref++; - add_trace("callref", "new", "0x%x", p_m_g_callref); + gsm_trace_header(p_g_interface_name, this, 0, DIRECTION_OUT); + p_g_callref = new_callref++; + add_trace("callref", "new", "0x%x", p_g_callref); end_trace(); - gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT); - mncc = create_mncc(MNCC_SETUP_REQ, p_m_g_callref); + gsm_trace_header(p_g_interface_name, this, MNCC_SETUP_REQ, DIRECTION_OUT); + mncc = create_mncc(MNCC_SETUP_REQ, p_g_callref); /* caller information */ mncc->fields |= MNCC_F_CALLING; mncc->calling.plan = 1; @@ -749,7 +688,7 @@ void Pgsm_bs::message_setup(unsigned int epoint_id, int message_id, union parame //todo end_trace(); - send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc); + send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc); new_state(PORT_STATE_OUT_SETUP); @@ -757,6 +696,14 @@ void Pgsm_bs::message_setup(unsigned int epoint_id, int message_id, union parame message_put(message); new_state(PORT_STATE_OUT_PROCEEDING); + + /* RTP bridge */ + if (param->setup.rtpinfo.port) { + p_g_rtp_bridge = 1; + p_g_rtp_ip_remote = param->setup.rtpinfo.ip; + p_g_rtp_port_remote = param->setup.rtpinfo.port; + } else + p_g_rtp_bridge = 0; } /* @@ -799,11 +746,12 @@ int gsm_bs_exit(int rc) return(rc); } -int gsm_bs_init(void) +int gsm_bs_init(struct interface *interface) { /* create gsm instance */ gsm_bs = (struct lcr_gsm *)MALLOC(sizeof(struct lcr_gsm)); + gsm_bs->interface = interface; gsm_bs->type = LCR_GSM_TYPE_NETWORK; gsm_bs->sun.sun_family = AF_UNIX; SCPY(gsm_bs->sun.sun_path, "/tmp/bsc_mncc"); diff --git a/gsm_bs.h b/gsm_bs.h index a57b7c7..81e1f13 100644 --- a/gsm_bs.h +++ b/gsm_bs.h @@ -3,11 +3,11 @@ class Pgsm_bs : public Pgsm { public: - Pgsm_bs(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode); + Pgsm_bs(int type, char *portname, struct port_settings *settings, struct interface *interface); ~Pgsm_bs(); - unsigned char *p_m_g_dtmf; /* DTMF tone generation (MS only) */ - int p_m_g_dtmf_index; /* DTMF tone generation index */ + unsigned char *p_g_dtmf; /* DTMF tone generation (MS only) */ + int p_g_dtmf_index; /* DTMF tone generation index */ void setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc); void start_dtmf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc); @@ -20,6 +20,6 @@ class Pgsm_bs : public Pgsm int gsm_bs_conf(struct gsm_conf *gsm_conf, char *conf_error); int gsm_bs_exit(int rc); -int gsm_bs_init(void); +int gsm_bs_init(struct interface *interface); int message_bsc(struct lcr_gsm *lcr_gsm, int msg_type, void *arg); diff --git a/gsm_ms.cpp b/gsm_ms.cpp index b966ad8..dbd3351 100644 --- a/gsm_ms.cpp +++ b/gsm_ms.cpp @@ -26,28 +26,28 @@ static int dtmf_timeout(struct lcr_timer *timer, void *instance, int index); /* * constructor */ -Pgsm_ms::Pgsm_ms(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode) : Pgsm(type, mISDNport, portname, settings, channel, exclusive, mode) +Pgsm_ms::Pgsm_ms(int type, char *portname, struct port_settings *settings, struct interface *interface) : Pgsm(type, portname, settings, interface) { struct lcr_gsm *gsm_ms = gsm_ms_first; - char *ms_name = mISDNport->ifport->gsm_ms_name; - p_m_g_lcr_gsm = NULL; + p_g_lcr_gsm = NULL; + SCPY(p_g_ms_name, interface->gsm_ms_name); while (gsm_ms) { - if (gsm_ms->type == LCR_GSM_TYPE_MS && !strcmp(gsm_ms->name, ms_name)) { - p_m_g_lcr_gsm = gsm_ms; + if (gsm_ms->type == LCR_GSM_TYPE_MS && !strcmp(gsm_ms->name, p_g_ms_name)) { + p_g_lcr_gsm = gsm_ms; break; } gsm_ms = gsm_ms->gsm_ms_next; } - p_m_g_dtmf_state = DTMF_ST_IDLE; - p_m_g_dtmf_index = 0; - p_m_g_dtmf[0] = '\0'; - memset(&p_m_g_dtmf_timer, 0, sizeof(p_m_g_dtmf_timer)); - add_timer(&p_m_g_dtmf_timer, dtmf_timeout, this, 0); + p_g_dtmf_state = DTMF_ST_IDLE; + p_g_dtmf_index = 0; + p_g_dtmf[0] = '\0'; + memset(&p_g_dtmf_timer, 0, sizeof(p_g_dtmf_timer)); + add_timer(&p_g_dtmf_timer, dtmf_timeout, this, 0); - PDEBUG(DEBUG_GSM, "Created new GSMMSPort(%s %s).\n", portname, ms_name); + PDEBUG(DEBUG_GSM, "Created new GSMMSPort(%s %s).\n", portname, p_g_ms_name); } /* @@ -56,7 +56,7 @@ Pgsm_ms::Pgsm_ms(int type, struct mISDNport *mISDNport, char *portname, struct p Pgsm_ms::~Pgsm_ms() { PDEBUG(DEBUG_GSM, "Destroyed GSM MS process(%s).\n", p_name); - del_timer(&p_m_g_dtmf_timer); + del_timer(&p_g_dtmf_timer); } /* @@ -65,21 +65,19 @@ Pgsm_ms::~Pgsm_ms() /* SETUP INDICATION */ void Pgsm_ms::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc) { - int ret; class Endpoint *epoint; struct lcr_msg *message; - int channel; struct gsm_mncc *mode, *proceeding, *frame; /* process given callref */ - l1l2l3_trace_header(p_m_mISDNport, this, L3_NEW_L3ID_IND, DIRECTION_IN); + gsm_trace_header(p_g_interface_name, this, 0, DIRECTION_IN); add_trace("callref", "new", "0x%x", callref); - if (p_m_g_callref) { + if (p_g_callref) { /* release in case the ID is already in use */ add_trace("error", NULL, "callref already in use"); end_trace(); mncc = create_mncc(MNCC_REJ_REQ, callref); - gsm_trace_header(p_m_mISDNport, this, MNCC_REJ_REQ, DIRECTION_OUT); + gsm_trace_header(p_g_interface_name, this, MNCC_REJ_REQ, DIRECTION_OUT); mncc->fields |= MNCC_F_CAUSE; mncc->cause.coding = 3; mncc->cause.location = 1; @@ -89,34 +87,15 @@ void Pgsm_ms::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_ add_trace("cause", "value", "%d", mncc->cause.value); add_trace("reason", NULL, "callref already in use"); end_trace(); - send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc); + send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc); new_state(PORT_STATE_RELEASE); - trigger_work(&p_m_g_delete); + trigger_work(&p_g_delete); return; } - p_m_g_callref = callref; + p_g_callref = callref; end_trace(); - /* if blocked, release call with MT_RELEASE_COMPLETE */ - if (p_m_mISDNport->ifport->block) { - mncc = create_mncc(MNCC_REJ_REQ, p_m_g_callref); - gsm_trace_header(p_m_mISDNport, this, MNCC_REJ_REQ, DIRECTION_OUT); - mncc->fields |= MNCC_F_CAUSE; - mncc->cause.coding = 3; - mncc->cause.location = 1; - mncc->cause.value = 27; - add_trace("cause", "coding", "%d", mncc->cause.coding); - add_trace("cause", "location", "%d", mncc->cause.location); - add_trace("cause", "value", "%d", mncc->cause.value); - add_trace("reason", NULL, "port is blocked"); - end_trace(); - send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc); - new_state(PORT_STATE_RELEASE); - trigger_work(&p_m_g_delete); - return; - } - - gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_IND, DIRECTION_IN); + gsm_trace_header(p_g_interface_name, this, MNCC_SETUP_IND, DIRECTION_IN); /* caller information */ p_callerinfo.ntype = INFO_NTYPE_NOTPRESENT; if (mncc->fields & MNCC_F_CALLING) { @@ -169,8 +148,7 @@ void Pgsm_ms::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_ add_trace("calling", "screen", "%d", mncc->calling.screen); add_trace("calling", "number", "%s", mncc->calling.number); } - p_callerinfo.isdn_port = p_m_portnum; - SCPY(p_callerinfo.interface, p_m_mISDNport->ifport->interface->name); + SCPY(p_callerinfo.interface, p_g_interface_name); /* dialing information */ if (mncc->fields & MNCC_F_CALLED) { SCAT(p_dialinginfo.id, mncc->called.number); @@ -244,7 +222,6 @@ void Pgsm_ms::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_ add_trace("redir", "present", "%d", mncc->redirecting.present); add_trace("redir", "screen", "%d", mncc->redirecting.screen); add_trace("redir", "number", "%s", mncc->redirecting.number); - p_redirinfo.isdn_port = p_m_portnum; } /* bearer capability */ if (mncc->fields & MNCC_F_BEARER_CAP) { @@ -282,35 +259,6 @@ void Pgsm_ms::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_ end_trace(); - /* hunt channel */ - ret = channel = hunt_bchannel(); - if (ret < 0) - goto no_channel; - - /* open channel */ - ret = seize_bchannel(channel, 1); - if (ret < 0) { - no_channel: - mncc = create_mncc(MNCC_REJ_REQ, p_m_g_callref); - gsm_trace_header(p_m_mISDNport, this, MNCC_REJ_REQ, DIRECTION_OUT); - mncc->fields |= MNCC_F_CAUSE; - mncc->cause.coding = 3; - mncc->cause.location = 1; - mncc->cause.value = 34; - add_trace("cause", "coding", "%d", mncc->cause.coding); - add_trace("cause", "location", "%d", mncc->cause.location); - add_trace("cause", "value", "%d", mncc->cause.value); - add_trace("reason", NULL, "no channel"); - end_trace(); - send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc); - new_state(PORT_STATE_RELEASE); - trigger_work(&p_m_g_delete); - return; - } - bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE); - if (bchannel_open(p_m_b_index)) - goto no_channel; - /* create endpoint */ if (p_epointlist) FATAL("Incoming call but already got an endpoint.\n"); @@ -321,37 +269,36 @@ void Pgsm_ms::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_ epointlist_new(epoint->ep_serial); /* modify lchan to GSM codec V1 */ - gsm_trace_header(p_m_mISDNport, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT); - mode = create_mncc(MNCC_LCHAN_MODIFY, p_m_g_callref); + gsm_trace_header(p_g_interface_name, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT); + mode = create_mncc(MNCC_LCHAN_MODIFY, p_g_callref); mode->lchan_mode = 0x01; /* GSM V1 */ mode->lchan_type = 0x02; add_trace("mode", NULL, "0x%02x", mode->lchan_mode); end_trace(); - send_and_free_mncc(p_m_g_lcr_gsm, mode->msg_type, mode); + send_and_free_mncc(p_g_lcr_gsm, mode->msg_type, mode); /* send call proceeding */ - gsm_trace_header(p_m_mISDNport, this, MNCC_CALL_CONF_REQ, DIRECTION_OUT); - proceeding = create_mncc(MNCC_CALL_CONF_REQ, p_m_g_callref); + gsm_trace_header(p_g_interface_name, this, MNCC_CALL_CONF_REQ, DIRECTION_OUT); + proceeding = create_mncc(MNCC_CALL_CONF_REQ, p_g_callref); // FIXME: bearer /* DTMF supported */ proceeding->fields |= MNCC_F_CCCAP; proceeding->cccap.dtmf = 1; end_trace(); - send_and_free_mncc(p_m_g_lcr_gsm, proceeding->msg_type, proceeding); + send_and_free_mncc(p_g_lcr_gsm, proceeding->msg_type, proceeding); new_state(PORT_STATE_IN_PROCEEDING); - if (p_m_mISDNport->tones && !p_m_g_tch_connected) { /* only if ... */ - gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT); + if (p_g_tones && !p_g_tch_connected) { /* only if ... */ + gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT); end_trace(); - frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref); - send_and_free_mncc(p_m_g_lcr_gsm, frame->msg_type, frame); - p_m_g_tch_connected = 1; + frame = create_mncc(MNCC_FRAME_RECV, p_g_callref); + send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame); + p_g_tch_connected = 1; } /* send setup message to endpoit */ message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_SETUP); - message->param.setup.isdn_port = p_m_portnum; message->param.setup.port_type = p_type; // message->param.setup.dtmf = 0; memcpy(&message->param.setup.dialinginfo, &p_dialinginfo, sizeof(struct dialing_info)); @@ -368,12 +315,13 @@ void Pgsm_ms::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_ */ int message_ms(struct lcr_gsm *gsm_ms, int msg_type, void *arg) { + struct interface *interface = gsm_ms->interface; struct gsm_mncc *mncc = (struct gsm_mncc *)arg; unsigned int callref = mncc->callref; class Port *port; class Pgsm_ms *pgsm_ms = NULL; char name[64]; - struct mISDNport *mISDNport; +// struct mISDNport *mISDNport; /* Special messages */ switch (msg_type) { @@ -385,7 +333,7 @@ int message_ms(struct lcr_gsm *gsm_ms, int msg_type, void *arg) while(port) { if ((port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_MS) { pgsm_ms = (class Pgsm_ms *)port; - if (pgsm_ms->p_m_g_callref == callref) { + if (pgsm_ms->p_g_callref == callref) { break; } } @@ -401,6 +349,7 @@ int message_ms(struct lcr_gsm *gsm_ms, int msg_type, void *arg) if (!port) { if (msg_type != MNCC_SETUP_IND) return(0); +#if 0 /* find gsm ms port */ mISDNport = mISDNport_first; while(mISDNport) { @@ -424,10 +373,10 @@ int message_ms(struct lcr_gsm *gsm_ms, int msg_type, void *arg) send_and_free_mncc(gsm_ms, rej->msg_type, rej); return 0; } +#endif /* creating port object, transparent until setup with hdlc */ - SPRINT(name, "%s-%d-in", mISDNport->ifport->interface->name, mISDNport->portnum); - if (!(pgsm_ms = new Pgsm_ms(PORT_TYPE_GSM_MS_IN, mISDNport, name, NULL, 0, 0, B_MODE_TRANSPARENT))) - + SPRINT(name, "%s-%d-in", interface->name, 0); + if (!(pgsm_ms = new Pgsm_ms(PORT_TYPE_GSM_MS_IN, name, NULL, interface))) FATAL("Cannot create Port instance.\n"); } @@ -482,10 +431,8 @@ int message_ms(struct lcr_gsm *gsm_ms, int msg_type, void *arg) void Pgsm_ms::message_setup(unsigned int epoint_id, int message_id, union parameter *param) { struct lcr_msg *message; - int ret; struct epoint_list *epointlist; struct gsm_mncc *mncc; - int channel; /* copy setup infos to port */ memcpy(&p_callerinfo, ¶m->setup.callerinfo, sizeof(p_callerinfo)); @@ -494,22 +441,22 @@ void Pgsm_ms::message_setup(unsigned int epoint_id, int message_id, union parame memcpy(&p_redirinfo, ¶m->setup.redirinfo, sizeof(p_redirinfo)); /* no instance */ - if (!p_m_g_lcr_gsm || p_m_g_lcr_gsm->mncc_lfd.fd < 0) { - gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT); - add_trace("failure", NULL, "MS %s instance is unavailable", p_m_mISDNport->ifport->gsm_ms_name); + if (!p_g_lcr_gsm || p_g_lcr_gsm->mncc_lfd.fd < 0) { + gsm_trace_header(p_g_interface_name, this, MNCC_SETUP_REQ, DIRECTION_OUT); + add_trace("failure", NULL, "MS %s instance is unavailable", p_g_ms_name); end_trace(); message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE); message->param.disconnectinfo.cause = 41; message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; message_put(message); new_state(PORT_STATE_RELEASE); - trigger_work(&p_m_g_delete); + trigger_work(&p_g_delete); return; } /* no number */ if (!p_dialinginfo.id[0]) { - gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT); + gsm_trace_header(p_g_interface_name, this, MNCC_SETUP_REQ, DIRECTION_OUT); add_trace("failure", NULL, "No dialed subscriber given."); end_trace(); message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE); @@ -517,46 +464,9 @@ void Pgsm_ms::message_setup(unsigned int epoint_id, int message_id, union parame message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; message_put(message); new_state(PORT_STATE_RELEASE); - trigger_work(&p_m_g_delete); + trigger_work(&p_g_delete); return; } - - /* release if port is blocked */ - if (p_m_mISDNport->ifport->block) { - gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT); - add_trace("failure", NULL, "Port blocked."); - end_trace(); - message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE); - message->param.disconnectinfo.cause = 27; // temp. unavail. - message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; - message_put(message); - new_state(PORT_STATE_RELEASE); - trigger_work(&p_m_g_delete); - return; - } - - /* hunt channel */ - ret = channel = hunt_bchannel(); - if (ret < 0) - goto no_channel; - /* open channel */ - ret = seize_bchannel(channel, 1); - if (ret < 0) { - no_channel: - gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT); - add_trace("failure", NULL, "No internal audio channel available."); - end_trace(); - message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE); - message->param.disconnectinfo.cause = 34; - message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; - message_put(message); - new_state(PORT_STATE_RELEASE); - trigger_work(&p_m_g_delete); - return; - } - bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE); - if (bchannel_open(p_m_b_index)) - goto no_channel; /* attach only if not already */ epointlist = p_epointlist; @@ -569,13 +479,13 @@ void Pgsm_ms::message_setup(unsigned int epoint_id, int message_id, union parame epointlist_new(epoint_id); /* creating l3id */ - l1l2l3_trace_header(p_m_mISDNport, this, L3_NEW_L3ID_REQ, DIRECTION_OUT); - p_m_g_callref = new_callref++; - add_trace("callref", "new", "0x%x", p_m_g_callref); + gsm_trace_header(p_g_interface_name, this, 0, DIRECTION_OUT); + p_g_callref = new_callref++; + add_trace("callref", "new", "0x%x", p_g_callref); end_trace(); - gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT); - mncc = create_mncc(MNCC_SETUP_REQ, p_m_g_callref); + gsm_trace_header(p_g_interface_name, this, MNCC_SETUP_REQ, DIRECTION_OUT); + mncc = create_mncc(MNCC_SETUP_REQ, p_g_callref); if (!strncasecmp(p_dialinginfo.id, "emerg", 5)) { mncc->emergency = 1; } else { @@ -631,7 +541,7 @@ void Pgsm_ms::message_setup(unsigned int epoint_id, int message_id, union parame } end_trace(); - send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc); + send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc); new_state(PORT_STATE_OUT_SETUP); @@ -639,49 +549,51 @@ void Pgsm_ms::message_setup(unsigned int epoint_id, int message_id, union parame message_put(message); new_state(PORT_STATE_OUT_PROCEEDING); + + p_g_rtp_bridge = 0; } void Pgsm_ms::dtmf_statemachine(struct gsm_mncc *mncc) { struct gsm_mncc *dtmf; - switch (p_m_g_dtmf_state) { + switch (p_g_dtmf_state) { case DTMF_ST_SPACE: case DTMF_ST_IDLE: /* end of string */ - if (!p_m_g_dtmf[p_m_g_dtmf_index]) { + if (!p_g_dtmf[p_g_dtmf_index]) { PDEBUG(DEBUG_GSM, "done with DTMF\n"); - p_m_g_dtmf_state = DTMF_ST_IDLE; + p_g_dtmf_state = DTMF_ST_IDLE; return; } - gsm_trace_header(p_m_mISDNport, this, MNCC_START_DTMF_REQ, DIRECTION_OUT); - dtmf = create_mncc(MNCC_START_DTMF_REQ, p_m_g_callref); - dtmf->keypad = p_m_g_dtmf[p_m_g_dtmf_index++]; - p_m_g_dtmf_state = DTMF_ST_START; + gsm_trace_header(p_g_interface_name, this, MNCC_START_DTMF_REQ, DIRECTION_OUT); + dtmf = create_mncc(MNCC_START_DTMF_REQ, p_g_callref); + dtmf->keypad = p_g_dtmf[p_g_dtmf_index++]; + p_g_dtmf_state = DTMF_ST_START; PDEBUG(DEBUG_GSM, "start DTMF (keypad %c)\n", dtmf->keypad); end_trace(); - send_and_free_mncc(p_m_g_lcr_gsm, dtmf->msg_type, dtmf); + send_and_free_mncc(p_g_lcr_gsm, dtmf->msg_type, dtmf); return; case DTMF_ST_START: if (mncc->msg_type != MNCC_START_DTMF_RSP) { PDEBUG(DEBUG_GSM, "DTMF was rejected\n"); return; } - schedule_timer(&p_m_g_dtmf_timer, 0, 70 * 1000); - p_m_g_dtmf_state = DTMF_ST_MARK; + schedule_timer(&p_g_dtmf_timer, 0, 70 * 1000); + p_g_dtmf_state = DTMF_ST_MARK; PDEBUG(DEBUG_GSM, "DTMF is on\n"); break; case DTMF_ST_MARK: - gsm_trace_header(p_m_mISDNport, this, MNCC_STOP_DTMF_REQ, DIRECTION_OUT); - dtmf = create_mncc(MNCC_STOP_DTMF_REQ, p_m_g_callref); - p_m_g_dtmf_state = DTMF_ST_STOP; + gsm_trace_header(p_g_interface_name, this, MNCC_STOP_DTMF_REQ, DIRECTION_OUT); + dtmf = create_mncc(MNCC_STOP_DTMF_REQ, p_g_callref); + p_g_dtmf_state = DTMF_ST_STOP; end_trace(); - send_and_free_mncc(p_m_g_lcr_gsm, dtmf->msg_type, dtmf); + send_and_free_mncc(p_g_lcr_gsm, dtmf->msg_type, dtmf); return; case DTMF_ST_STOP: - schedule_timer(&p_m_g_dtmf_timer, 0, 120 * 1000); - p_m_g_dtmf_state = DTMF_ST_SPACE; + schedule_timer(&p_g_dtmf_timer, 0, 120 * 1000); + p_g_dtmf_state = DTMF_ST_SPACE; PDEBUG(DEBUG_GSM, "DTMF is off\n"); break; } @@ -708,12 +620,12 @@ void Pgsm_ms::message_dtmf(unsigned int epoint_id, int message_id, union paramet return; /* schedule */ - if (p_m_g_dtmf_state == DTMF_ST_IDLE) { - p_m_g_dtmf_index = 0; - p_m_g_dtmf[0] = '\0'; + if (p_g_dtmf_state == DTMF_ST_IDLE) { + p_g_dtmf_index = 0; + p_g_dtmf[0] = '\0'; } - SCCAT(p_m_g_dtmf, digit); - if (p_m_g_dtmf_state == DTMF_ST_IDLE) + SCCAT(p_g_dtmf, digit); + if (p_g_dtmf_state == DTMF_ST_IDLE) dtmf_statemachine(NULL); } @@ -731,12 +643,12 @@ void Pgsm_ms::message_information(unsigned int epoint_id, int message_id, union continue; /* schedule */ - if (p_m_g_dtmf_state == DTMF_ST_IDLE) { - p_m_g_dtmf_index = 0; - p_m_g_dtmf[0] = '\0'; + if (p_g_dtmf_state == DTMF_ST_IDLE) { + p_g_dtmf_index = 0; + p_g_dtmf[0] = '\0'; } - SCCAT(p_m_g_dtmf, digit); - if (p_m_g_dtmf_state == DTMF_ST_IDLE) + SCCAT(p_g_dtmf, digit); + if (p_g_dtmf_state == DTMF_ST_IDLE) dtmf_statemachine(NULL); } } @@ -794,7 +706,7 @@ int gsm_ms_init(void) } /* add a new GSM mobile instance */ -int gsm_ms_new(const char *name) +int gsm_ms_new(struct interface *interface) { struct lcr_gsm *gsm_ms = gsm_ms_first, **gsm_ms_p = &gsm_ms_first; @@ -803,15 +715,16 @@ int gsm_ms_new(const char *name) gsm_ms = gsm_ms->gsm_ms_next; } - PDEBUG(DEBUG_GSM, "GSM: interface for MS '%s' is created\n", name); + PDEBUG(DEBUG_GSM, "GSM: interface for MS '%s' is created\n", interface->gsm_ms_name); /* create gsm instance */ gsm_ms = (struct lcr_gsm *)MALLOC(sizeof(struct lcr_gsm)); + gsm_ms->interface = interface; gsm_ms->type = LCR_GSM_TYPE_MS; - SCPY(gsm_ms->name, name); + SCPY(gsm_ms->name, interface->gsm_ms_name); gsm_ms->sun.sun_family = AF_UNIX; - SPRINT(gsm_ms->sun.sun_path, "/tmp/ms_mncc_%s", name); + SPRINT(gsm_ms->sun.sun_path, "/tmp/ms_mncc_%s", gsm_ms->name); memset(&gsm_ms->socket_retry, 0, sizeof(gsm_ms->socket_retry)); add_timer(&gsm_ms->socket_retry, mncc_socket_retry_cb, gsm_ms, 0); @@ -851,10 +764,10 @@ int gsm_ms_delete(const char *name) while(port) { if ((port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_MS) { pgsm_ms = (class Pgsm_ms *)port; - if (pgsm_ms->p_m_g_lcr_gsm == gsm_ms && pgsm_ms->p_m_g_callref) { + if (pgsm_ms->p_g_lcr_gsm == gsm_ms && pgsm_ms->p_g_callref) { struct gsm_mncc *rej; - rej = create_mncc(MNCC_REL_REQ, pgsm_ms->p_m_g_callref); + rej = create_mncc(MNCC_REL_REQ, pgsm_ms->p_g_callref); rej->fields |= MNCC_F_CAUSE; rej->cause.coding = 3; rej->cause.location = 1; @@ -866,7 +779,7 @@ int gsm_ms_delete(const char *name) end_trace(); send_and_free_mncc(gsm_ms, rej->msg_type, rej); pgsm_ms->new_state(PORT_STATE_RELEASE); - trigger_work(&pgsm_ms->p_m_g_delete); + trigger_work(&pgsm_ms->p_g_delete); } } } diff --git a/gsm_ms.h b/gsm_ms.h index 70ea825..82202f5 100644 --- a/gsm_ms.h +++ b/gsm_ms.h @@ -3,13 +3,14 @@ class Pgsm_ms : public Pgsm { public: - Pgsm_ms(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode); + Pgsm_ms(int type, char *portname, struct port_settings *settings, struct interface *interface); ~Pgsm_ms(); - int p_m_g_dtmf_state; - int p_m_g_dtmf_index; - char p_m_g_dtmf[128]; - struct lcr_timer p_m_g_dtmf_timer; + char p_g_ms_name[32]; + int p_g_dtmf_state; + int p_g_dtmf_index; + char p_g_dtmf[128]; + struct lcr_timer p_g_dtmf_timer; void dtmf_statemachine(struct gsm_mncc *mncc); void setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc); @@ -22,7 +23,7 @@ class Pgsm_ms : public Pgsm int gsm_ms_conf(struct gsm_conf *gsm_conf, char *conf_error); int gsm_ms_exit(int rc); int gsm_ms_init(void); -int gsm_ms_new(const char *name); +int gsm_ms_new(struct interface *interface); int gsm_ms_delete(const char *name); int message_ms(struct lcr_gsm *lcr_gsm, int msg_type, void *arg); diff --git a/interface.c b/interface.c index 264f4f2..60e058f 100644 --- a/interface.c +++ b/interface.c @@ -894,31 +894,19 @@ static int inter_gsm_bs(struct interface *interface, char *filename, int line, c SPRINT(interface_error, "Error in %s (line %d): GSM BS side not compiled in.\n", filename, line); return(-1); #else - struct interface_port *ifport; struct interface *searchif; searchif = interface_newlist; while(searchif) { - ifport = searchif->ifport; - while(ifport) { - if (ifport->gsm_bs) { - SPRINT(interface_error, "Error in %s (line %d): port '%s' already uses gsm BS side.\n", filename, line, ifport->portname); - return(-1); - } - ifport = ifport->next; + if (searchif->gsm_bs) { + SPRINT(interface_error, "Error in %s (line %d): interface '%s' already uses gsm BS side.\n", filename, line, searchif->name); + return(-1); } searchif = searchif->next; } - /* set portname */ - if (inter_portname(interface, filename, line, (char *)"portname", options.loopback_lcr)) - return(-1); - /* goto end of chain again to set gsmflag */ - ifport = interface->ifport; - while(ifport->next) - ifport = ifport->next; - ifport->gsm_bs = 1; + interface->gsm_bs = 1; return(0); #endif @@ -929,37 +917,23 @@ static int inter_gsm_ms(struct interface *interface, char *filename, int line, c SPRINT(interface_error, "Error in %s (line %d): GSM MS side not compiled in.\n", filename, line); return(-1); #else - struct interface_port *ifport, *searchifport; struct interface *searchif; - /* set portname */ - if (inter_portname(interface, filename, line, (char *)"portname", options.loopback_lcr)) - return(-1); - - /* goto end of chain again to set gsmflag and socket */ - ifport = interface->ifport; - while(ifport->next) - ifport = ifport->next; - ifport->gsm_ms = 1; + interface->gsm_ms = 1; /* copy values */ if (!value || !value[0]) { SPRINT(interface_error, "Error in %s (line %d): Missing MS name and socket name.\n", filename, line); return(-1); } - SCPY(ifport->gsm_ms_name, value); + SCPY(interface->gsm_ms_name, value); /* check if name is used multiple times */ searchif = interface_newlist; while(searchif) { - searchifport = searchif->ifport; - while(searchifport) { - if (searchifport != ifport - && !strcmp(searchifport->gsm_ms_name, ifport->gsm_ms_name)) { - SPRINT(interface_error, "Error in %s (line %d): mobile '%s' already uses the given MS name '%s', choose a different one.\n", filename, line, ifport->gsm_ms_name, searchifport->gsm_ms_name); - return(-1); - } - searchifport = searchifport->next; + if (!strcmp(searchif->gsm_ms_name, interface->gsm_ms_name)) { + SPRINT(interface_error, "Error in %s (line %d): mobile '%s' already uses the given MS name '%s', choose a different one.\n", filename, line, interface->gsm_ms_name, searchif->gsm_ms_name); + return(-1); } searchif = searchif->next; } @@ -975,10 +949,6 @@ static int inter_sip(struct interface *interface, char *filename, int line, char #else char *p; - /* set portname */ - if (inter_portname(interface, filename, line, (char *)"portname", options.loopback_lcr)) - return(-1); - interface->sip = 1; /* copy values */ @@ -997,6 +967,12 @@ static int inter_sip(struct interface *interface, char *filename, int line, char return(0); #endif } +static int inter_rtp_bridge(struct interface *interface, char *filename, int line, char *parameter, char *value) +{ + interface->rtp_bridge = 1; + + return(0); +} static int inter_nonotify(struct interface *interface, char *filename, int line, char *parameter, char *value) { struct interface_port *ifport; @@ -1247,6 +1223,9 @@ struct interface_param interface_param[] = { {"sip", &inter_sip, " ", "Sets up SIP interface that represents one SIP endpoint.\n" "Give SIP configuration file."}, + {"rtp-bridge", &inter_rtp_bridge, "", + "Sets up SIP interface that represents one SIP endpoint.\n" + "Give SIP configuration file."}, {"nonotify", &inter_nonotify, "", "Prevents sending notify messages to this interface. A call placed on hold will\n" "Not affect the remote end (phone or telcom switch).\n" @@ -1524,28 +1503,65 @@ static void set_defaults(struct interface_port *ifport) void relink_interfaces(void) { struct mISDNport *mISDNport; - struct interface *interface; + struct interface *interface, *temp; struct interface_port *ifport; + int found; - /* unlink all mISDNports */ - mISDNport = mISDNport_first; - while(mISDNport) { - if (mISDNport->ifport) { - ifport = mISDNport->ifport; + interface = interface_first; + while(interface) { + found = 0; + temp = interface_newlist; + while(temp) { + if (!strcmp(temp->name, interface->name)) + found = 1; + temp = temp->next; + } + if (!found) { #ifdef WITH_GSM_MS - if (ifport->gsm_ms) - gsm_ms_delete(ifport->gsm_ms_name); + if (interface->gsm_ms) + gsm_ms_delete(interface->gsm_ms_name); #endif #ifdef WITH_GSM_BS - if (ifport->gsm_bs) + if (interface->gsm_bs) gsm_bs_exit(0); #endif #ifdef WITH_SIP -#warning FIXME: get out of mISDNport - if (ifport->interface->sip) - sip_exit_inst(mISDNport->ifport->interface); + if (interface->sip) + sip_exit_inst(interface); +#endif + } + interface = interface->next; + } + + interface = interface_newlist; + while(interface) { + found = 0; + temp = interface_first; + while(temp) { + if (!strcmp(temp->name, interface->name)) + found = 1; + temp = temp->next; + } + if (!found) { +#ifdef WITH_GSM_MS + if (interface->gsm_ms) + gsm_ms_new(interface); +#endif +#ifdef WITH_GSM_BS + if (interface->gsm_bs) + gsm_bs_init(interface); +#endif +#ifdef WITH_SIP + if (interface->sip) + sip_init_inst(interface); #endif } + interface = interface->next; + } + + /* unlink all mISDNports */ + mISDNport = mISDNport_first; + while(mISDNport) { mISDNport->ifport = NULL; mISDNport = mISDNport->next; } @@ -1625,19 +1641,6 @@ void load_port(struct interface_port *ifport) set_defaults(ifport); /* load static port instances */ mISDNport_static(mISDNport); -#ifdef WITH_GSM_MS - if (ifport->gsm_ms) - gsm_ms_new(ifport->gsm_ms_name); -#endif -#ifdef WITH_GSM_BS - if (ifport->gsm_bs) - gsm_bs_init(); -#endif -#ifdef WITH_SIP - if (ifport->interface->sip) - if (sip_init_inst(ifport->interface)) - ifport->block = 2; /* not available */ -#endif } else { ifport->block = 2; /* not available */ } @@ -1675,12 +1678,21 @@ void doc_interface(void) /* screen caller id * out==0: incoming caller id, out==1: outgoing caller id */ -void do_screen(int out, char *id, int idsize, int *type, int *present, struct interface *interface) +void do_screen(int out, char *id, int idsize, int *type, int *present, const char *interface_name) { char *msn1; struct interface_msn *ifmsn; struct interface_screen *ifscreen; char suffix[64]; + struct interface *interface = interface_first; + + while (interface) { + if (!strcmp(interface->name, interface_name)) + break; + interface = interface->next; + } + if (!interface) + return; /* screen incoming caller id */ if (!out) { diff --git a/interface.h b/interface.h index d9462ed..ea9cbad 100644 --- a/interface.h +++ b/interface.h @@ -51,13 +51,6 @@ struct interface_port { int tespecial; /* special TE-mode behavior */ int l1hold; /* hold layer 1 (1=on, 0=off) */ int l2hold; /* hold layer 2 (1=force, -1=disable, 0=default) */ -#ifdef WITH_GSM_BS - int gsm_bs; /* interface is an GSM BS interface */ -#endif -#ifdef WITH_GSM_MS - int gsm_ms; /* interface is an GSM MS interface */ - char gsm_ms_name[32]; /* name of ms */ -#endif unsigned int ss5; /* set, if SS5 signalling enabled, also holds feature bits */ int remote; /* interface is a remote app interface */ char remote_app[32]; /* name of remote application */ @@ -111,12 +104,20 @@ struct interface { char pipeline[256]; /* filter pipeline */ unsigned char bf_key[56]; /* filter blowfish */ int bf_len; /* filter length of blowfish */ +#ifdef WITH_GSM_BS + int gsm_bs; /* interface is an GSM BS interface */ +#endif +#ifdef WITH_GSM_MS + int gsm_ms; /* interface is an GSM MS interface */ + char gsm_ms_name[32]; /* name of ms */ +#endif #ifdef WITH_SIP int sip; /* interface is a SIP interface */ char sip_local_ip[16]; char sip_remote_ip[16]; void *sip_inst; /* sip instance */ #endif + int rtp_bridge; /* bridge RTP directly (for calls comming from interface) */ }; struct interface_param { @@ -137,5 +138,5 @@ void free_interfaces(struct interface *interface_start); void relink_interfaces(void); void load_port(struct interface_port *ifport); void doc_interface(void); -void do_screen(int out, char *id, int idsize, int *type, int *present, struct interface *interface); +void do_screen(int out, char *id, int idsize, int *type, int *present, const char *interface_name); diff --git a/lcradmin.c b/lcradmin.c index 2483a9b..f8a1ac8 100644 --- a/lcradmin.c +++ b/lcradmin.c @@ -621,7 +621,10 @@ const char *admin_state(int sock, char *argv[]) /* show interface summary */ move(++line>1?line:1, 0); color(white); - if (m[i].u.i.block >= 2) { + if (m[i].u.i.portnum == -100) { + SPRINT(buffer, "%s %s", m[i].u.i.interface_name, (m[i].u.i.extension)?" exten":""); + addstr(buffer); + } else if (m[i].u.i.block >= 2) { if (m[i].u.i.portnum < 0) SPRINT(buffer, "%s (port ?: %s)%s", m[i].u.i.interface_name, m[i].u.i.portname, (m[i].u.i.extension)?" exten":""); else diff --git a/mISDN.cpp b/mISDN.cpp index 002f83f..6392a4c 100644 --- a/mISDN.cpp +++ b/mISDN.cpp @@ -2001,7 +2001,6 @@ static int b_sock_callback(struct lcr_fd *fd, unsigned int what, void *instance, static int b_timer_timeout(struct lcr_timer *timer, void *instance, int i) { struct mISDNport *mISDNport = (struct mISDNport *)instance; -puts("fires"); bchannel_event(mISDNport, i, B_EVENT_TIMEOUT); @@ -2103,15 +2102,6 @@ struct mISDNport *mISDNport_open(struct interface_port *ifport) unsigned int protocol, prop; loop = 0; -#ifdef WITH_GSM_BS - loop |= ifport->gsm_bs; -#endif -#ifdef WITH_GSM_MS - loop |= ifport->gsm_ms; -#endif -#ifdef WITH_SIP - loop |= ifport->interface->sip; -#endif //printf("%s == %s\n", ifport->portname, options.loopback_int); if (!strcmp(ifport->portname, options.loopback_lcr)) loop = 1; @@ -2260,12 +2250,6 @@ struct mISDNport *mISDNport_open(struct interface_port *ifport) mISDNport->l1link = -1; mISDNport->l2link = -1; } -#ifdef WITH_GSM_BS - mISDNport->gsm_bs = ifport->gsm_bs; -#endif -#ifdef WITH_GSM_MS - mISDNport->gsm_ms = ifport->gsm_ms; -#endif mISDNport->isloopback = loop; pmemuse++; *mISDNportp = mISDNport; diff --git a/mISDN.h b/mISDN.h index c310023..e3e59a4 100644 --- a/mISDN.h +++ b/mISDN.h @@ -64,13 +64,6 @@ struct mISDNport { int locally; /* local causes are sent as local causes not remote */ int los, ais, rdi, slip_rx, slip_tx; - /* gsm */ -#ifdef WITH_GSM_BS - int gsm_bs; /* this is the (only) GSM BS interface */ -#endif -#ifdef WITH_GSM_MS - int gsm_ms; /* this is an GSM MS interface */ -#endif int lcr_sock; /* socket of loopback on LCR side */ int isloopback; /* will be set on open, in case it is a loopback if */ diff --git a/message.h b/message.h index 4cfc5b1..6330654 100644 --- a/message.h +++ b/message.h @@ -148,6 +148,13 @@ enum { B_MODE_HDLC, /* hdlc data mode */ }; +/* rtp-info structure */ +struct rtp_info { + int payload_type; + unsigned int ip; + unsigned short port; +}; + /* call-info structure CALLER */ struct caller_info { char id[32]; /* id of caller (user number) */ @@ -191,6 +198,7 @@ struct connect_info { int screen; /* who provided the number */ char display[84]; /* display information */ char imsi[16]; /* IMSI for gsm terminated calls */ + struct rtp_info rtpinfo; /* info about RTP peer */ }; /* call-info structure DISCONNECT */ @@ -240,6 +248,7 @@ struct notify_info { struct progress_info { int progress; /* progress indicator */ int location; /* progress location */ + struct rtp_info rtpinfo; /* info about RTP peer */ }; /* call-info structure FACILITY */ @@ -266,7 +275,8 @@ struct message_setup { struct redir_info redirinfo; /* info on redirection (to the calling user) */ struct capa_info capainfo; /* info on l2,l3 capability */ struct useruser_info useruser; /* user-user */ -// struct progress_info progress; /* info on call progress */ + struct progress_info progress; /* info on call progress */ + struct rtp_info rtpinfo; /* info about RTP peer */ char context[128]; /* asterisk context */ }; diff --git a/mncc.h b/mncc.h index e5f8216..04b3241 100644 --- a/mncc.h +++ b/mncc.h @@ -52,6 +52,9 @@ #define MNCC_FRAME_RECV 0x0201 #define MNCC_FRAME_DROP 0x0202 #define MNCC_LCHAN_MODIFY 0x0203 +#define MNCC_RTP_CREATE 0x0204 +#define MNCC_RTP_CONNECT 0x0205 +#define MNCC_RTP_FREE 0x0206 #define GSM_TCHF_FRAME 0x0300 #define GSM_TCHF_FRAME_EFR 0x0301 @@ -185,3 +188,11 @@ struct gsm_data_frame { unsigned char data[0]; }; +struct gsm_mncc_rtp { + uint32_t msg_type; + uint32_t callref; + uint32_t ip; + uint16_t port; +}; + + diff --git a/port.cpp b/port.cpp index 74f8aac..4afca9c 100644 --- a/port.cpp +++ b/port.cpp @@ -149,8 +149,6 @@ Port::Port(int type, const char *portname, struct port_settings *settings) { class Port *temp, **tempp; - PDEBUG(DEBUG_PORT, "new port of type 0x%x, name '%s'\n", type, portname); - /* initialize object */ if (settings) memcpy(&p_settings, settings, sizeof(struct port_settings)); @@ -195,6 +193,8 @@ Port::Port(int type, const char *portname, struct port_settings *settings) *tempp = this; classuse++; + + PDEBUG(DEBUG_PORT, "new port (%d) of type 0x%x, name '%s'\n", p_serial, type, portname); } @@ -206,7 +206,7 @@ Port::~Port(void) class Port *temp, **tempp; struct lcr_msg *message; - PDEBUG(DEBUG_PORT, "removing port of type 0x%x, name '%s'\n", p_type, p_name); + PDEBUG(DEBUG_PORT, "removing port (%d) of type 0x%x, name '%s'\n", p_serial, p_type, p_name); if (p_bridge) { PDEBUG(DEBUG_PORT, "Removing us from bridge %u\n", p_bridge->bridge_id); @@ -301,7 +301,7 @@ void Port::set_tone(const char *dir, const char *name) if (name == NULL) name = ""; - if (!dir && !dir[0]) + if (!dir || !dir[0]) dir = options.tones_dir; /* just in case we have no PmISDN instance */ /* no counter, no eof, normal speed */ diff --git a/port.h b/port.h index 066ace7..d09ba0c 100644 --- a/port.h +++ b/port.h @@ -18,16 +18,16 @@ #define PORT_CLASS_DSS1 0x1100 #define PORT_CLASS_DSS1_NT 0x1110 #define PORT_CLASS_DSS1_TE 0x1120 -#define PORT_CLASS_GSM 0x1200 -#define PORT_CLASS_GSM_BS 0x1210 -#define PORT_CLASS_GSM_MS 0x1220 #define PORT_CLASS_SS5 0x1300 #define PORT_CLASS_REMOTE 0x1400 -#define PORT_CLASS_SIP 0x1500 +#define PORT_CLASS_SIP 0x2000 +#define PORT_CLASS_GSM 0x3000 +#define PORT_CLASS_GSM_BS 0x3100 +#define PORT_CLASS_GSM_MS 0x3200 #define PORT_CLASS_MASK 0xf000 #define PORT_CLASS_mISDN_MASK 0xff00 #define PORT_CLASS_DSS1_MASK 0xfff0 -#define PORT_CLASS_GSM_MASK 0xfff0 +#define PORT_CLASS_GSM_MASK 0xff00 #define PORT_CLASS_DIR_MASK 0x000f #define PORT_CLASS_DIR_IN 0x0001 #define PORT_CLASS_DIR_OUT 0x0002 @@ -38,10 +38,10 @@ #define PORT_TYPE_DSS1_TE_IN 0x1121 #define PORT_TYPE_DSS1_TE_OUT 0x1122 /* gsm */ -#define PORT_TYPE_GSM_BS_IN 0x1211 -#define PORT_TYPE_GSM_BS_OUT 0x1212 -#define PORT_TYPE_GSM_MS_IN 0x1221 -#define PORT_TYPE_GSM_MS_OUT 0x1222 +#define PORT_TYPE_GSM_BS_IN 0x3101 +#define PORT_TYPE_GSM_BS_OUT 0x3102 +#define PORT_TYPE_GSM_MS_IN 0x3201 +#define PORT_TYPE_GSM_MS_OUT 0x3202 /* ss5 */ #define PORT_TYPE_SS5_IN 0x1311 #define PORT_TYPE_SS5_OUT 0x1312 @@ -50,10 +50,10 @@ #define PORT_TYPE_REMOTE_IN 0x1411 #define PORT_TYPE_REMOTE_OUT 0x1412 /* SIP */ -#define PORT_TYPE_SIP_IN 0x1511 -#define PORT_TYPE_SIP_OUT 0x1512 +#define PORT_TYPE_SIP_IN 0x2001 +#define PORT_TYPE_SIP_OUT 0x2002 /* answering machine */ -#define PORT_TYPE_VBOX_OUT 0x3111 +#define PORT_TYPE_VBOX_OUT 0xf111 enum { /* states of call */ diff --git a/sip.cpp b/sip.cpp index 40c5572..e39f19c 100644 --- a/sip.cpp +++ b/sip.cpp @@ -21,7 +21,9 @@ unsigned char flip[256]; su_home_t sip_home[1]; struct sip_inst { - struct interface *interface; + char interface_name[64]; + char local_ip[16]; + char remote_ip[16]; su_root_t *root; nua_t *nua; }; @@ -31,28 +33,32 @@ static int delete_event(struct lcr_work *work, void *instance, int index); /* * initialize SIP port */ -Psip::Psip(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode, struct interface *interface) : PmISDN(type, mISDNport, portname, settings, channel, exclusive, mode) +Psip::Psip(int type, char *portname, struct port_settings *settings, struct interface *interface) : Port(type, portname, settings) { - p_m_s_sip_inst = interface->sip_inst; - memset(&p_m_s_delete, 0, sizeof(p_m_s_delete)); - add_work(&p_m_s_delete, delete_event, this, 0); - p_m_s_handle = 0; - p_m_s_magic = 0; - memset(&p_m_s_rtp_fd, 0, sizeof(p_m_s_rtp_fd)); - memset(&p_m_s_rtcp_fd, 0, sizeof(p_m_s_rtcp_fd)); - memset(&p_m_s_rtp_sin_local, 0, sizeof(p_m_s_rtp_sin_local)); - memset(&p_m_s_rtcp_sin_local, 0, sizeof(p_m_s_rtcp_sin_local)); - memset(&p_m_s_rtp_sin_remote, 0, sizeof(p_m_s_rtp_sin_remote)); - memset(&p_m_s_rtcp_sin_remote, 0, sizeof(p_m_s_rtcp_sin_remote)); - p_m_s_rtp_ip_local = 0; - p_m_s_rtp_ip_remote = 0; - p_m_s_rtp_port_local = 0; - p_m_s_rtp_port_remote = 0; - p_m_s_b_sock = -1; - p_m_s_b_index = -1; - p_m_s_b_active = 0; - p_m_s_rxpos = 0; - p_m_s_rtp_tx_action = 0; + p_s_rtp_bridge = 0; + if (interface->rtp_bridge) + p_s_rtp_bridge = 1; + p_s_sip_inst = interface->sip_inst; + memset(&p_s_delete, 0, sizeof(p_s_delete)); + add_work(&p_s_delete, delete_event, this, 0); + p_s_handle = 0; + p_s_magic = 0; + memset(&p_s_rtp_fd, 0, sizeof(p_s_rtp_fd)); + memset(&p_s_rtcp_fd, 0, sizeof(p_s_rtcp_fd)); + memset(&p_s_rtp_sin_local, 0, sizeof(p_s_rtp_sin_local)); + memset(&p_s_rtcp_sin_local, 0, sizeof(p_s_rtcp_sin_local)); + memset(&p_s_rtp_sin_remote, 0, sizeof(p_s_rtp_sin_remote)); + memset(&p_s_rtcp_sin_remote, 0, sizeof(p_s_rtcp_sin_remote)); + p_s_rtp_payload_type = 0; + p_s_rtp_ip_local = 0; + p_s_rtp_ip_remote = 0; + p_s_rtp_port_local = 0; + p_s_rtp_port_remote = 0; + p_s_b_sock = -1; + p_s_b_index = -1; + p_s_b_active = 0; + p_s_rxpos = 0; + p_s_rtp_tx_action = 0; PDEBUG(DEBUG_SIP, "Created new Psip(%s).\n", portname); } @@ -65,15 +71,26 @@ Psip::~Psip() { PDEBUG(DEBUG_SIP, "Destroyed SIP process(%s).\n", p_name); - del_work(&p_m_s_delete); - - /* close audio transfer socket */ - if (p_m_s_b_sock > -1) - bchannel_close(); + del_work(&p_s_delete); rtp_close(); } +const char *payload_type2name(uint8_t payload_type) { + switch (payload_type) { + case 0: + return "PCMU"; + case 8: + return "PCMA"; + case 3: + case 96: + case 97: + case 98: + return "GSM"; + } + + return "UKN"; +} static void sip_trace_header(class Psip *sip, const char *message, int direction) { @@ -136,6 +153,8 @@ static int rtp_decode(class Psip *psip, unsigned char *data, int len) uint8_t *payload; int payload_len; int x_len; + unsigned char *from, *to; + int n; if (len < 12) { PDEBUG(DEBUG_SIP, "received RTP frame too short (len = %d)\n", len); @@ -222,7 +241,12 @@ static int rtp_decode(class Psip *psip, unsigned char *data, int len) return 0; } - psip->bchannel_send(PH_DATA_REQ, 0, payload, payload_len); + n = payload_len; + from = payload; + to = payload; + while(n--) + *to++ = flip[*from++]; + psip->bridge_tx(payload, payload_len); return 0; } @@ -319,27 +343,27 @@ int Psip::rtp_open(void) rtp_close(); return -EIO; } - p_m_s_rtp_fd.fd = rc; - register_fd(&p_m_s_rtp_fd, LCR_FD_READ, rtp_sock_callback, this, 0); + p_s_rtp_fd.fd = rc; + register_fd(&p_s_rtp_fd, LCR_FD_READ, rtp_sock_callback, this, 0); rc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (!rc) { rtp_close(); return -EIO; } - p_m_s_rtcp_fd.fd = rc; - register_fd(&p_m_s_rtcp_fd, LCR_FD_READ, rtcp_sock_callback, this, 0); + p_s_rtcp_fd.fd = rc; + register_fd(&p_s_rtcp_fd, LCR_FD_READ, rtcp_sock_callback, this, 0); /* bind socket */ ip = htonl(INADDR_ANY); ia.s_addr = ip; for (next_udp_port = next_udp_port % 0xffff; next_udp_port < 0xffff; next_udp_port += 2) { - rc = rtp_sub_socket_bind(p_m_s_rtp_fd.fd, &p_m_s_rtp_sin_local, ip, next_udp_port); + rc = rtp_sub_socket_bind(p_s_rtp_fd.fd, &p_s_rtp_sin_local, ip, next_udp_port); if (rc != 0) continue; - rc = rtp_sub_socket_bind(p_m_s_rtcp_fd.fd, &p_m_s_rtcp_sin_local, ip, next_udp_port+1); + rc = rtp_sub_socket_bind(p_s_rtcp_fd.fd, &p_s_rtcp_sin_local, ip, next_udp_port+1); if (rc == 0) break; } @@ -348,12 +372,12 @@ int Psip::rtp_open(void) rtp_close(); return rc; } - p_m_s_rtp_port_local = next_udp_port; - p_m_s_rtp_ip_local = ntohl(p_m_s_rtp_sin_local.sin_addr.s_addr); - PDEBUG(DEBUG_SIP, "local ip %08x port %d\n", p_m_s_rtp_ip_local, p_m_s_rtp_port_local); - PDEBUG(DEBUG_SIP, "remote ip %08x port %d\n", p_m_s_rtp_ip_remote, p_m_s_rtp_port_remote); + p_s_rtp_port_local = next_udp_port; + p_s_rtp_ip_local = ntohl(p_s_rtp_sin_local.sin_addr.s_addr); + PDEBUG(DEBUG_SIP, "local ip %08x port %d\n", p_s_rtp_ip_local, p_s_rtp_port_local); + PDEBUG(DEBUG_SIP, "remote ip %08x port %d\n", p_s_rtp_ip_remote, p_s_rtp_port_remote); - return p_m_s_rtp_port_local; + return p_s_rtp_port_local; } int Psip::rtp_connect(void) @@ -361,39 +385,39 @@ int Psip::rtp_connect(void) int rc; struct in_addr ia; - ia.s_addr = htonl(p_m_s_rtp_ip_remote); - PDEBUG(DEBUG_SIP, "rtp_connect(ip=%s, port=%u)\n", inet_ntoa(ia), p_m_s_rtp_port_remote); + ia.s_addr = htonl(p_s_rtp_ip_remote); + PDEBUG(DEBUG_SIP, "rtp_connect(ip=%s, port=%u)\n", inet_ntoa(ia), p_s_rtp_port_remote); - rc = rtp_sub_socket_connect(p_m_s_rtp_fd.fd, &p_m_s_rtp_sin_local, &p_m_s_rtp_sin_remote, p_m_s_rtp_ip_remote, p_m_s_rtp_port_remote); + rc = rtp_sub_socket_connect(p_s_rtp_fd.fd, &p_s_rtp_sin_local, &p_s_rtp_sin_remote, p_s_rtp_ip_remote, p_s_rtp_port_remote); if (rc < 0) return rc; - rc = rtp_sub_socket_connect(p_m_s_rtcp_fd.fd, &p_m_s_rtcp_sin_local, &p_m_s_rtcp_sin_remote, p_m_s_rtp_ip_remote, p_m_s_rtp_port_remote + 1); + rc = rtp_sub_socket_connect(p_s_rtcp_fd.fd, &p_s_rtcp_sin_local, &p_s_rtcp_sin_remote, p_s_rtp_ip_remote, p_s_rtp_port_remote + 1); if (rc < 0) return rc; - p_m_s_rtp_ip_local = ntohl(p_m_s_rtp_sin_local.sin_addr.s_addr); - PDEBUG(DEBUG_SIP, "local ip %08x port %d\n", p_m_s_rtp_ip_local, p_m_s_rtp_port_local); - PDEBUG(DEBUG_SIP, "remote ip %08x port %d\n", p_m_s_rtp_ip_remote, p_m_s_rtp_port_remote); - p_m_s_rtp_is_connected = 1; + p_s_rtp_ip_local = ntohl(p_s_rtp_sin_local.sin_addr.s_addr); + PDEBUG(DEBUG_SIP, "local ip %08x port %d\n", p_s_rtp_ip_local, p_s_rtp_port_local); + PDEBUG(DEBUG_SIP, "remote ip %08x port %d\n", p_s_rtp_ip_remote, p_s_rtp_port_remote); + p_s_rtp_is_connected = 1; return 0; } void Psip::rtp_close(void) { - if (p_m_s_rtp_fd.fd > 0) { - unregister_fd(&p_m_s_rtp_fd); - close(p_m_s_rtp_fd.fd); - p_m_s_rtp_fd.fd = 0; + if (p_s_rtp_fd.fd > 0) { + unregister_fd(&p_s_rtp_fd); + close(p_s_rtp_fd.fd); + p_s_rtp_fd.fd = 0; } - if (p_m_s_rtcp_fd.fd > 0) { - unregister_fd(&p_m_s_rtcp_fd); - close(p_m_s_rtcp_fd.fd); - p_m_s_rtcp_fd.fd = 0; + if (p_s_rtcp_fd.fd > 0) { + unregister_fd(&p_s_rtcp_fd); + close(p_s_rtcp_fd.fd); + p_s_rtcp_fd.fd = 0; } - if (p_m_s_rtp_is_connected) { + if (p_s_rtp_is_connected) { PDEBUG(DEBUG_SIP, "rtp closed\n"); - p_m_s_rtp_is_connected = 0; + p_s_rtp_is_connected = 0; } } @@ -413,25 +437,25 @@ void tv_difference(struct timeval *diff, const struct timeval *from, } /* encode and send a rtp frame */ -int Psip::rtp_send_frame(unsigned char *data, unsigned int len, int payload_type) +int Psip::rtp_send_frame(unsigned char *data, unsigned int len, uint8_t payload_type) { struct rtp_hdr *rtph; int payload_len; int duration; /* in samples */ unsigned char buffer[256]; - if (!p_m_s_rtp_is_connected) { + if (!p_s_rtp_is_connected) { /* drop silently */ return 0; } - if (!p_m_s_rtp_tx_action) { + if (!p_s_rtp_tx_action) { /* initialize sequences */ - p_m_s_rtp_tx_action = 1; - p_m_s_rtp_tx_ssrc = rand(); - p_m_s_rtp_tx_sequence = random(); - p_m_s_rtp_tx_timestamp = random(); - memset(&p_m_s_rtp_tx_last_tv, 0, sizeof(p_m_s_rtp_tx_last_tv)); + p_s_rtp_tx_action = 1; + p_s_rtp_tx_ssrc = rand(); + p_s_rtp_tx_sequence = random(); + p_s_rtp_tx_timestamp = random(); + memset(&p_s_rtp_tx_last_tv, 0, sizeof(p_s_rtp_tx_last_tv)); } switch (payload_type) { @@ -459,8 +483,8 @@ int Psip::rtp_send_frame(unsigned char *data, unsigned int len, int payload_type long int usec_diff, frame_diff; gettimeofday(&tv, NULL); - tv_difference(&tv_diff, &p_m_s_rtp_tx_last_tv, &tv); - p_m_s_rtp_tx_last_tv = tv; + tv_difference(&tv_diff, &p_s_rtp_tx_last_tv, &tv); + p_s_rtp_tx_last_tv = tv; usec_diff = tv_diff.tv_sec * 1000000 + tv_diff.tv_usec; frame_diff = (usec_diff / 20000); @@ -469,8 +493,8 @@ int Psip::rtp_send_frame(unsigned char *data, unsigned int len, int payload_type long int frame_diff_excess = frame_diff - 1; PDEBUG(DEBUG_SIP, "Correcting frame difference of %ld frames\n", frame_diff_excess); - p_m_s_rtp_tx_sequence += frame_diff_excess; - p_m_s_rtp_tx_timestamp += frame_diff_excess * duration; + p_s_rtp_tx_sequence += frame_diff_excess; + p_s_rtp_tx_timestamp += frame_diff_excess * duration; } } #endif @@ -482,14 +506,14 @@ int Psip::rtp_send_frame(unsigned char *data, unsigned int len, int payload_type rtph->csrc_count = 0; rtph->marker = 0; rtph->payload_type = payload_type; - rtph->sequence = htons(p_m_s_rtp_tx_sequence++); - rtph->timestamp = htonl(p_m_s_rtp_tx_timestamp); - p_m_s_rtp_tx_timestamp += duration; - rtph->ssrc = htonl(p_m_s_rtp_tx_ssrc); + rtph->sequence = htons(p_s_rtp_tx_sequence++); + rtph->timestamp = htonl(p_s_rtp_tx_timestamp); + p_s_rtp_tx_timestamp += duration; + rtph->ssrc = htonl(p_s_rtp_tx_ssrc); memcpy(buffer + sizeof(struct rtp_hdr), data, payload_len); - if (p_m_s_rtp_fd.fd > 0) { - len = write(p_m_s_rtp_fd.fd, &buffer, sizeof(struct rtp_hdr) + payload_len); + if (p_s_rtp_fd.fd > 0) { + len = write(p_s_rtp_fd.fd, &buffer, sizeof(struct rtp_hdr) + payload_len); if (len != sizeof(struct rtp_hdr) + payload_len) { PDEBUG(DEBUG_SIP, "write result=%d\n", len); // rtp_close(); @@ -501,147 +525,17 @@ int Psip::rtp_send_frame(unsigned char *data, unsigned int len, int payload_type return 0; } -/* - * bchannel handling - */ - -/* select free bchannel from loopback interface */ -int Psip::hunt_bchannel(void) -{ - return loop_hunt_bchannel(this, p_m_mISDNport); -} - -/* close SIP side bchannel */ -void Psip::bchannel_close(void) -{ - if (p_m_s_b_sock > -1) { - unregister_fd(&p_m_s_b_fd); - close(p_m_s_b_sock); - } - p_m_s_b_sock = -1; - p_m_s_b_index = -1; - p_m_s_b_active = 0; -} - -static int b_handler(struct lcr_fd *fd, unsigned int what, void *instance, int index); - -/* open external side bchannel */ -int Psip::bchannel_open(int index) -{ - int ret; - struct sockaddr_mISDN addr; - struct mISDNhead act; - - if (p_m_s_b_sock > -1) { - PERROR("Socket already created for index %d\n", index); - return(-EIO); - } - - /* open socket */ - ret = p_m_s_b_sock = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_B_RAW); - if (ret < 0) { - PERROR("Failed to open bchannel-socket for index %d\n", index); - bchannel_close(); - return(ret); - } - memset(&p_m_s_b_fd, 0, sizeof(p_m_s_b_fd)); - p_m_s_b_fd.fd = p_m_s_b_sock; - register_fd(&p_m_s_b_fd, LCR_FD_READ, b_handler, this, 0); - - - /* bind socket to bchannel */ - addr.family = AF_ISDN; - addr.dev = mISDNloop.port; - addr.channel = index+1+(index>15); - ret = bind(p_m_s_b_sock, (struct sockaddr *)&addr, sizeof(addr)); - if (ret < 0) { - PERROR("Failed to bind bchannel-socket for index %d\n", index); - bchannel_close(); - return(ret); - } - /* activate bchannel */ - PDEBUG(DEBUG_SIP, "Activating SIP side channel index %i.\n", index); - act.prim = PH_ACTIVATE_REQ; - act.id = 0; - ret = sendto(p_m_s_b_sock, &act, MISDN_HEADER_LEN, 0, NULL, 0); - if (ret < 0) { - PERROR("Failed to activate index %d\n", index); - bchannel_close(); - return(ret); - } - - p_m_s_b_index = index; - - return(0); -} - -/* receive from bchannel */ -void Psip::bchannel_receive(struct mISDNhead *hh, unsigned char *data, int len) +/* receive from remote */ +int Psip::bridge_rx(unsigned char *data, int len) { /* write to rx buffer */ while(len--) { - p_m_s_rxdata[p_m_s_rxpos++] = flip[*data++]; - if (p_m_s_rxpos == 160) { - p_m_s_rxpos = 0; + p_s_rxdata[p_s_rxpos++] = flip[*data++]; + if (p_s_rxpos == 160) { + p_s_rxpos = 0; /* transmit data via rtp */ - rtp_send_frame(p_m_s_rxdata, 160, (options.law=='a')?RTP_PT_ALAW:RTP_PT_ULAW); - } - } -} - -/* transmit to bchannel */ -void Psip::bchannel_send(unsigned int prim, unsigned int id, unsigned char *data, int len) -{ - unsigned char buf[MISDN_HEADER_LEN+len]; - struct mISDNhead *hh = (struct mISDNhead *)buf; - unsigned char *to = buf + MISDN_HEADER_LEN; - int n = len; - int ret; - - if (!p_m_s_b_active) - return; - - /* make and send frame */ - hh->prim = prim; - hh->id = 0; - while(n--) - *to++ = flip[*data++]; - ret = sendto(p_m_s_b_sock, buf, MISDN_HEADER_LEN+len, 0, NULL, 0); - if (ret <= 0) - PERROR("Failed to send to socket index %d\n", p_m_s_b_index); -} - -/* handle socket input */ -static int b_handler(struct lcr_fd *fd, unsigned int what, void *instance, int index) -{ - class Psip *psip = (class Psip *)instance; - int ret; - unsigned char buffer[2048+MISDN_HEADER_LEN]; - struct mISDNhead *hh = (struct mISDNhead *)buffer; - - /* handle message from bchannel */ - if (psip->p_m_s_b_sock > -1) { - ret = recv(psip->p_m_s_b_sock, buffer, sizeof(buffer), 0); - if (ret >= (int)MISDN_HEADER_LEN) { - switch(hh->prim) { - /* we don't care about confirms, we use rx data to sync tx */ - case PH_DATA_CNF: - break; - /* we receive audio data, we respond to it AND we send tones */ - case PH_DATA_IND: - psip->bchannel_receive(hh, buffer+MISDN_HEADER_LEN, ret-MISDN_HEADER_LEN); - break; - case PH_ACTIVATE_IND: - psip->p_m_s_b_active = 1; - break; - case PH_DEACTIVATE_IND: - psip->p_m_s_b_active = 0; - break; - } - } else { - if (ret < 0 && errno != EWOULDBLOCK) - PERROR("Read from GSM port, index %d failed with return code %d\n", ret); + rtp_send_frame(p_s_rxdata, 160, (options.law=='a')?RTP_PT_ALAW:RTP_PT_ULAW); } } @@ -827,22 +721,36 @@ int Psip::message_connect(unsigned int epoint_id, int message_id, union paramete struct in_addr ia; struct lcr_msg *message; - if (rtp_connect() < 0) { - nua_cancel(p_m_s_handle, TAG_END()); - nua_handle_destroy(p_m_s_handle); - p_m_s_handle = NULL; - sip_trace_header(this, "CANCEL", DIRECTION_OUT); - add_trace("reason", NULL, "failed to connect RTP/RTCP sockts"); - end_trace(); - message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE); - message->param.disconnectinfo.cause = 41; - message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; - message_put(message); - new_state(PORT_STATE_RELEASE); - trigger_work(&p_m_s_delete); - return 0; + if (param->connectinfo.rtpinfo.port) { + PDEBUG(DEBUG_SIP, "RTP info given by remote, forward that\n"); + p_s_rtp_bridge = 1; + p_s_rtp_payload_type = param->connectinfo.rtpinfo.payload_type; + p_s_rtp_ip_local = param->connectinfo.rtpinfo.ip; + p_s_rtp_port_local = param->connectinfo.rtpinfo.port; + PDEBUG(DEBUG_SIP, "local ip %08x port %d\n", p_s_rtp_ip_local, p_s_rtp_port_local); + PDEBUG(DEBUG_SIP, "remote ip %08x port %d\n", p_s_rtp_ip_remote, p_s_rtp_port_remote); + } else { + PDEBUG(DEBUG_SIP, "RTP info not given by remote, so we do our own RTP\n"); + p_s_rtp_payload_type = (options.law=='a') ? RTP_PT_ALAW : RTP_PT_ULAW; + /* open local RTP peer (if not bridging) */ + if (rtp_connect() < 0) { + nua_cancel(p_s_handle, TAG_END()); + nua_handle_destroy(p_s_handle); + p_s_handle = NULL; + sip_trace_header(this, "CANCEL", DIRECTION_OUT); + add_trace("reason", NULL, "failed to connect RTP/RTCP sockts"); + end_trace(); + message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE); + message->param.disconnectinfo.cause = 41; + message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; + message_put(message); + new_state(PORT_STATE_RELEASE); + trigger_work(&p_s_delete); + return 0; + } } - ia.s_addr = htonl(p_m_s_rtp_ip_local); + + ia.s_addr = htonl(p_s_rtp_ip_local); SPRINT(sdp_str, "v=0\n" @@ -852,10 +760,10 @@ int Psip::message_connect(unsigned int epoint_id, int message_id, union paramete "t=0 0\n" "m=audio %d RTP/AVP %d\n" "a=rtpmap:%d %s/8000\n" - , inet_ntoa(ia), inet_ntoa(ia), p_m_s_rtp_port_local, (options.law=='a')?RTP_PT_ALAW:RTP_PT_ULAW, (options.law=='a')?RTP_PT_ALAW:RTP_PT_ULAW, (options.law=='a')?"PCMA":"PCMU"); + , inet_ntoa(ia), inet_ntoa(ia), p_s_rtp_port_local, p_s_rtp_payload_type, p_s_rtp_payload_type, payload_type2name(p_s_rtp_payload_type)); PDEBUG(DEBUG_SIP, "Using SDP response: %s\n", sdp_str); - nua_respond(p_m_s_handle, SIP_200_OK, + nua_respond(p_s_handle, SIP_200_OK, NUTAG_MEDIA_ENABLE(0), SIPTAG_CONTENT_TYPE_STR("application/sdp"), SIPTAG_PAYLOAD_STR(sdp_str), TAG_END()); @@ -890,7 +798,7 @@ int Psip::message_release(unsigned int epoint_id, int message_id, union paramete if (cause_str[0]) add_trace("cause", "value", "%d", cause); end_trace(); - nua_cancel(p_m_s_handle, TAG_IF(cause_str[0], SIPTAG_REASON_STR(cause_str)), TAG_END()); + nua_cancel(p_s_handle, TAG_IF(cause_str[0], SIPTAG_REASON_STR(cause_str)), TAG_END()); break; case PORT_STATE_IN_SETUP: case PORT_STATE_IN_PROCEEDING: @@ -902,10 +810,10 @@ int Psip::message_release(unsigned int epoint_id, int message_id, union paramete add_trace("cause", "value", "%d", cause); add_trace("respond", "value", "%d %s", status, status_text); end_trace(); - nua_respond(p_m_s_handle, status, status_text, TAG_IF(cause_str[0], SIPTAG_REASON_STR(cause_str)), TAG_END()); - nua_handle_destroy(p_m_s_handle); - p_m_s_handle = NULL; - trigger_work(&p_m_s_delete); + nua_respond(p_s_handle, status, status_text, TAG_IF(cause_str[0], SIPTAG_REASON_STR(cause_str)), TAG_END()); + nua_handle_destroy(p_s_handle); + p_s_handle = NULL; + trigger_work(&p_s_delete); break; default: PDEBUG(DEBUG_SIP, "RELEASE/DISCONNECT will perform nua_bye\n"); @@ -913,7 +821,7 @@ int Psip::message_release(unsigned int epoint_id, int message_id, union paramete if (cause_str[0]) add_trace("cause", "value", "%d", cause); end_trace(); - nua_bye(p_m_s_handle, TAG_IF(cause_str[0], SIPTAG_REASON_STR(cause_str)), TAG_END()); + nua_bye(p_s_handle, TAG_IF(cause_str[0], SIPTAG_REASON_STR(cause_str)), TAG_END()); } if (message_id == MESSAGE_DISCONNECT) { @@ -934,78 +842,48 @@ int Psip::message_release(unsigned int epoint_id, int message_id, union paramete int Psip::message_setup(unsigned int epoint_id, int message_id, union parameter *param) { - struct sip_inst *inst = (struct sip_inst *) p_m_s_sip_inst; + struct sip_inst *inst = (struct sip_inst *) p_s_sip_inst; char from[128]; char to[128]; - const char *local = inst->interface->sip_local_ip; - const char *remote = inst->interface->sip_remote_ip; + const char *local = inst->local_ip; + const char *remote = inst->remote_ip; char sdp_str[256]; struct in_addr ia; struct epoint_list *epointlist; sip_cseq_t *cseq = NULL; - int ret; - int channel; PDEBUG(DEBUG_SIP, "Doing Setup (inst %p)\n", inst); - /* release if port is blocked */ - if (p_m_mISDNport->ifport->block) { - struct lcr_msg *message; - - sip_trace_header(this, "INVITE", DIRECTION_OUT); - add_trace("failure", NULL, "Port blocked."); - end_trace(); - message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE); - message->param.disconnectinfo.cause = 27; // temp. unavail. - message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; - message_put(message); - new_state(PORT_STATE_RELEASE); - trigger_work(&p_m_s_delete); - return 0; - } - - /* hunt channel */ - ret = channel = hunt_bchannel(); - if (ret < 0) - goto no_channel; - /* open channel */ - ret = seize_bchannel(channel, 1); - if (ret < 0) { - struct lcr_msg *message; - - no_channel: - sip_trace_header(this, "INVITE", DIRECTION_OUT); - add_trace("failure", NULL, "No internal audio channel available."); - end_trace(); - message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE); - message->param.disconnectinfo.cause = 34; - message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; - message_put(message); - new_state(PORT_STATE_RELEASE); - trigger_work(&p_m_s_delete); - return 0; - } - bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE); - if (bchannel_open(p_m_b_index)) - goto no_channel; - memcpy(&p_dialinginfo, ¶m->setup.dialinginfo, sizeof(p_dialinginfo)); memcpy(&p_callerinfo, ¶m->setup.callerinfo, sizeof(p_callerinfo)); memcpy(&p_redirinfo, ¶m->setup.redirinfo, sizeof(p_redirinfo)); - /* connect to remote RTP */ - if (rtp_open() < 0) { - struct lcr_msg *message; - - PERROR("Failed to open RTP sockets\n"); - /* send release message to endpoit */ - message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE); - message->param.disconnectinfo.cause = 41; - message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; - message_put(message); - new_state(PORT_STATE_RELEASE); - trigger_work(&p_m_s_delete); - return 0; + if (param->setup.rtpinfo.port) { + PDEBUG(DEBUG_SIP, "RTP info given by remote, forward that\n"); + p_s_rtp_bridge = 1; + p_s_rtp_payload_type = param->setup.rtpinfo.payload_type; + p_s_rtp_ip_local = param->setup.rtpinfo.ip; + p_s_rtp_port_local = param->setup.rtpinfo.port; + PDEBUG(DEBUG_SIP, "local ip %08x port %d\n", p_s_rtp_ip_local, p_s_rtp_port_local); + PDEBUG(DEBUG_SIP, "remote ip %08x port %d\n", p_s_rtp_ip_remote, p_s_rtp_port_remote); + } else { + PDEBUG(DEBUG_SIP, "RTP info not given by remote, so we do our own RTP\n"); + p_s_rtp_payload_type = (options.law=='a') ? RTP_PT_ALAW : RTP_PT_ULAW; + + /* open local RTP peer (if not bridging) */ + if (rtp_open() < 0) { + struct lcr_msg *message; + + PERROR("Failed to open RTP sockets\n"); + /* send release message to endpoit */ + message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE); + message->param.disconnectinfo.cause = 41; + message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; + message_put(message); + new_state(PORT_STATE_RELEASE); + trigger_work(&p_s_delete); + return 0; + } } SPRINT(from, "sip:%s@%s", param->setup.callerinfo.id, local); SPRINT(to, "sip:%s@%s", param->setup.dialinginfo.id, remote); @@ -1013,11 +891,11 @@ int Psip::message_setup(unsigned int epoint_id, int message_id, union parameter sip_trace_header(this, "INVITE", DIRECTION_OUT); add_trace("from", "uri", "%s", from); add_trace("to", "uri", "%s", to); - add_trace("rtp", "port", "%d,%d", p_m_s_rtp_port_local, p_m_s_rtp_port_local + 1); + add_trace("rtp", "port", "%d,%d", p_s_rtp_port_local, p_s_rtp_port_local + 1); end_trace(); - p_m_s_handle = nua_handle(inst->nua, NULL, TAG_END()); - if (!p_m_s_handle) { + p_s_handle = nua_handle(inst->nua, NULL, TAG_END()); + if (!p_s_handle) { struct lcr_msg *message; PERROR("Failed to create handle\n"); @@ -1027,17 +905,20 @@ int Psip::message_setup(unsigned int epoint_id, int message_id, union parameter message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; message_put(message); new_state(PORT_STATE_RELEASE); - trigger_work(&p_m_s_delete); + trigger_work(&p_s_delete); return 0; } /* apply handle */ sip_trace_header(this, "NEW handle", DIRECTION_IN); - add_trace("handle", "new", "0x%x", p_m_s_handle); + add_trace("handle", "new", "0x%x", p_s_handle); end_trace(); - inet_pton(AF_INET, local, &p_m_s_rtp_ip_local); - p_m_s_rtp_ip_local = ntohl(p_m_s_rtp_ip_local); - ia.s_addr = htonl(p_m_s_rtp_ip_local); + if (!p_s_rtp_ip_local) { + PDEBUG(DEBUG_SIP, "RTP local IP not known, so we use our local SIP ip %s\n", local); + inet_pton(AF_INET, local, &p_s_rtp_ip_local); + p_s_rtp_ip_local = ntohl(p_s_rtp_ip_local); + } + ia.s_addr = htonl(p_s_rtp_ip_local); SPRINT(sdp_str, "v=0\n" "o=LCR-Sofia-SIP 0 0 IN IP4 %s\n" @@ -1046,12 +927,12 @@ int Psip::message_setup(unsigned int epoint_id, int message_id, union parameter "t=0 0\n" "m=audio %d RTP/AVP %d\n" "a=rtpmap:%d %s/8000\n" - , inet_ntoa(ia), inet_ntoa(ia), p_m_s_rtp_port_local, (options.law=='a')?RTP_PT_ALAW:RTP_PT_ULAW, (options.law=='a')?RTP_PT_ALAW:RTP_PT_ULAW, (options.law=='a')?"PCMA":"PCMU"); + , inet_ntoa(ia), inet_ntoa(ia), p_s_rtp_port_local, p_s_rtp_payload_type, p_s_rtp_payload_type, payload_type2name(p_s_rtp_payload_type)); PDEBUG(DEBUG_SIP, "Using SDP for invite: %s\n", sdp_str); // cseq = sip_cseq_create(sip_home, 123, SIP_METHOD_INVITE); - nua_invite(p_m_s_handle, + nua_invite(p_s_handle, TAG_IF(from[0], SIPTAG_FROM_STR(from)), TAG_IF(to[0], SIPTAG_TO_STR(to)), TAG_IF(cseq, SIPTAG_CSEQ(cseq)), @@ -1073,11 +954,82 @@ int Psip::message_setup(unsigned int epoint_id, int message_id, union parameter return 0; } +int Psip::message_notify(unsigned int epoint_id, int message_id, union parameter *param) +{ +// char sdp_str[256]; +// struct in_addr ia; + + switch (param->notifyinfo.notify) { + case INFO_NOTIFY_REMOTE_HOLD: +#if 0 + SPRINT(sdp_str, + "v=0\n" + "o=LCR-Sofia-SIP 0 0 IN IP4 0.0.0.0\n" + "s=SIP Call\n" + "c=IN IP4 0.0.0.0\n" + "t=0 0\n" + ); + PDEBUG(DEBUG_SIP, "Using SDP for hold: %s\n", sdp_str); + nua_info(p_s_handle, +// TAG_IF(from[0], SIPTAG_FROM_STR(from)), +// TAG_IF(to[0], SIPTAG_TO_STR(to)), +// TAG_IF(cseq, SIPTAG_CSEQ(cseq)), + NUTAG_MEDIA_ENABLE(0), + SIPTAG_CONTENT_TYPE_STR("application/sdp"), + SIPTAG_PAYLOAD_STR(sdp_str), TAG_END()); +#endif + break; + case INFO_NOTIFY_REMOTE_RETRIEVAL: +#if 0 + ia.s_addr = htonl(p_s_rtp_ip_local); + SPRINT(sdp_str, + "v=0\n" + "o=LCR-Sofia-SIP 0 0 IN IP4 %s\n" + "s=SIP Call\n" + "c=IN IP4 %s\n" + "t=0 0\n" + "m=audio %d RTP/AVP %d\n" + "a=rtpmap:%d %s/8000\n" + , inet_ntoa(ia), inet_ntoa(ia), p_s_rtp_port_local, p_s_rtp_payload_type, p_s_rtp_payload_type, payload_type2name(p_s_rtp_payload_type)); + PDEBUG(DEBUG_SIP, "Using SDP for rertieve: %s\n", sdp_str); + nua_info(p_s_handle, +// TAG_IF(from[0], SIPTAG_FROM_STR(from)), +// TAG_IF(to[0], SIPTAG_TO_STR(to)), +// TAG_IF(cseq, SIPTAG_CSEQ(cseq)), + NUTAG_MEDIA_ENABLE(0), + SIPTAG_CONTENT_TYPE_STR("application/sdp"), + SIPTAG_PAYLOAD_STR(sdp_str), TAG_END()); +#endif + break; + } + + return 0; +} + +int Psip::message_dtmf(unsigned int epoint_id, int message_id, union parameter *param) +{ + char dtmf_str[64]; + + /* prepare DTMF info payload */ + SPRINT(dtmf_str, + "Signal=%c\n" + "Duration=160\n" + , param->dtmf); + + /* start invite to handle DTMF */ + nua_info(p_s_handle, + NUTAG_MEDIA_ENABLE(0), + SIPTAG_CONTENT_TYPE_STR("application/dtmf-relay"), + SIPTAG_PAYLOAD_STR(dtmf_str), TAG_END()); + + return 0; +} + int Psip::message_epoint(unsigned int epoint_id, int message_id, union parameter *param) { class Endpoint *epoint; - if (PmISDN::message_epoint(epoint_id, message_id, param)) + if (Port::message_epoint(epoint_id, message_id, param)) return 1; epoint = find_epoint_id(epoint_id); @@ -1091,7 +1043,7 @@ int Psip::message_epoint(unsigned int epoint_id, int message_id, union parameter if (p_state != PORT_STATE_IN_SETUP && p_state != PORT_STATE_IN_PROCEEDING) return 0; - nua_respond(p_m_s_handle, SIP_180_RINGING, TAG_END()); + nua_respond(p_s_handle, SIP_180_RINGING, TAG_END()); sip_trace_header(this, "RESPOND", DIRECTION_OUT); add_trace("respond", "value", "180 Ringing"); end_trace(); @@ -1115,6 +1067,14 @@ int Psip::message_epoint(unsigned int epoint_id, int message_id, union parameter message_setup(epoint_id, message_id, param); return 1; + case MESSAGE_DTMF: /* DTMF info to be transmitted via INFO transaction */ + if (p_state == PORT_STATE_CONNECT) + message_dtmf(epoint_id, message_id, param); + case MESSAGE_NOTIFY: /* notification about remote hold/retrieve */ + if (p_state == PORT_STATE_CONNECT) + message_notify(epoint_id, message_id, param); + return(1); + default: PDEBUG(DEBUG_SIP, "PORT(%s) SP port with (caller id %s) received an unsupported message: %d\n", p_name, p_callerinfo.id, message_id); } @@ -1122,7 +1082,7 @@ int Psip::message_epoint(unsigned int epoint_id, int message_id, union parameter return 0; } -int Psip::parse_sdp(sip_t const *sip, unsigned int *ip, unsigned short *port) +int Psip::parse_sdp(sip_t const *sip, unsigned int *ip, unsigned short *port, uint8_t payload_type) { int codec_supported = 0; @@ -1162,7 +1122,7 @@ int Psip::parse_sdp(sip_t const *sip, unsigned int *ip, unsigned short *port) conn = m->m_connections; PDEBUG(DEBUG_SIP, "CONN: address:'%s'\n", conn->c_address); inet_pton(AF_INET, conn->c_address, ip); - *ip = ntohl(p_m_s_rtp_ip_remote); + *ip = ntohl(p_s_rtp_ip_remote); } else { char *p = sip->sip_payload->pl_data; char addr[16]; @@ -1179,11 +1139,11 @@ int Psip::parse_sdp(sip_t const *sip, unsigned int *ip, unsigned short *port) if ((p = strchr(addr, '\r'))) *p = '\0'; PDEBUG(DEBUG_SIP, "CONN: address:'%s'\n", addr); inet_pton(AF_INET, addr, ip); - *ip = ntohl(p_m_s_rtp_ip_remote); + *ip = ntohl(p_s_rtp_ip_remote); } for (map = m->m_rtpmaps; map; map = map->rm_next) { - PDEBUG(DEBUG_SIP, "RTPMAP: coding:'%s' rate='%d'\n", map->rm_encoding, map->rm_rate); - if (!strcmp(map->rm_encoding, (options.law=='a')?"PCMA":"PCMU") && map->rm_rate == 8000) { + PDEBUG(DEBUG_SIP, "RTPMAP: coding:'%s' rate='%d' pt='%d'\n", map->rm_encoding, map->rm_rate, map->rm_pt); + if (map->rm_pt == payload_type) { PDEBUG(DEBUG_SIP, "supported codec found\n"); codec_supported = 1; goto done_codec; @@ -1202,11 +1162,12 @@ int Psip::parse_sdp(sip_t const *sip, unsigned int *ip, unsigned short *port) void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *magic, nua_handle_t *nh, nua_hmagic_t *hmagic, sip_t const *sip, tagi_t tagss[]) { + struct sip_inst *inst = (struct sip_inst *) p_s_sip_inst; const char *from = "", *to = ""; int ret; class Endpoint *epoint; struct lcr_msg *message; - int channel; + uint8_t payload_type; if (sip->sip_from && sip->sip_from->a_url) from = sip->sip_from->a_url->url_user; @@ -1214,14 +1175,18 @@ void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag to = sip->sip_to->a_url->url_user; PDEBUG(DEBUG_SIP, "invite received (%s->%s)\n", from, to); - ret = parse_sdp(sip, &p_m_s_rtp_ip_remote, &p_m_s_rtp_port_remote); + if (p_s_rtp_bridge) + payload_type = 3; // FIXME: use list and forward list to remote side + else + payload_type = (options.law=='a')?RTP_PT_ALAW:RTP_PT_ULAW; + ret = parse_sdp(sip, &p_s_rtp_ip_remote, &p_s_rtp_port_remote, payload_type); if (ret) { if (ret == 400) nua_respond(nh, SIP_400_BAD_REQUEST, TAG_END()); else nua_respond(nh, SIP_415_UNSUPPORTED_MEDIA, TAG_END()); nua_handle_destroy(nh); - p_m_s_handle = NULL; + p_s_handle = NULL; sip_trace_header(this, "RESPOND", DIRECTION_OUT); if (ret == 400) add_trace("respond", "value", "415 Unsupported Media"); @@ -1230,45 +1195,32 @@ void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag add_trace("reason", NULL, "offered codec does not match"); end_trace(); new_state(PORT_STATE_RELEASE); - trigger_work(&p_m_s_delete); + trigger_work(&p_s_delete); return; } - /* connect to remote RTP */ - if (rtp_open() < 0) { + /* open local RTP peer (if not bridging) */ + if (!p_s_rtp_bridge && rtp_open() < 0) { nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END()); nua_handle_destroy(nh); - p_m_s_handle = NULL; + p_s_handle = NULL; sip_trace_header(this, "RESPOND", DIRECTION_OUT); add_trace("respond", "value", "500 Internal Server Error"); add_trace("reason", NULL, "failed to open RTP/RTCP sockts"); end_trace(); new_state(PORT_STATE_RELEASE); - trigger_work(&p_m_s_delete); + trigger_work(&p_s_delete); return; } /* apply handle */ sip_trace_header(this, "NEW handle", DIRECTION_IN); add_trace("handle", "new", "0x%x", nh); - p_m_s_handle = nh; + p_s_handle = nh; end_trace(); - /* if blocked, release call */ - if (p_m_mISDNport->ifport->block) { - nua_respond(nh, SIP_503_SERVICE_UNAVAILABLE, TAG_END()); - nua_handle_destroy(nh); - p_m_s_handle = NULL; - sip_trace_header(this, "RESPOND", DIRECTION_OUT); - add_trace("respond", "value", "503 Service Unavailable"); - add_trace("reason", NULL, "port is blocked"); - end_trace(); - new_state(PORT_STATE_RELEASE); - trigger_work(&p_m_s_delete); - return; - } sip_trace_header(this, "INVITE", DIRECTION_IN); - add_trace("RTP", "port", "%d", p_m_s_rtp_port_remote); + add_trace("RTP", "port", "%d", p_s_rtp_port_remote); /* caller information */ if (!from[0]) { p_callerinfo.present = INFO_PRESENT_NOTAVAIL; @@ -1282,8 +1234,7 @@ void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag SCPY(p_callerinfo.id, from); add_trace("calling", "number", "%s", from); } - p_callerinfo.isdn_port = p_m_portnum; - SCPY(p_callerinfo.interface, p_m_mISDNport->ifport->interface->name); + SCPY(p_callerinfo.interface, inst->interface_name); /* dialing information */ if (to[0]) { p_dialinginfo.ntype = INFO_NTYPE_UNKNOWN; @@ -1302,30 +1253,6 @@ void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag end_trace(); - /* hunt channel */ - ret = channel = hunt_bchannel(); - if (ret < 0) - goto no_channel; - - /* open channel */ - ret = seize_bchannel(channel, 1); - if (ret < 0) { - no_channel: - nua_respond(nh, SIP_480_TEMPORARILY_UNAVAILABLE, TAG_END()); - nua_handle_destroy(nh); - p_m_s_handle = NULL; - sip_trace_header(this, "RESPOND", DIRECTION_OUT); - add_trace("respond", "value", "480 Temporarily Unavailable"); - add_trace("reason", NULL, "no channel"); - end_trace(); - new_state(PORT_STATE_RELEASE); - trigger_work(&p_m_s_delete); - return; - } - bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE); - if (bchannel_open(p_m_b_index)) - goto no_channel; - /* create endpoint */ if (p_epointlist) FATAL("Incoming call but already got an endpoint.\n"); @@ -1345,7 +1272,6 @@ void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag /* send setup message to endpoit */ message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_SETUP); - message->param.setup.isdn_port = p_m_portnum; message->param.setup.port_type = p_type; // message->param.setup.dtmf = 0; memcpy(&message->param.setup.dialinginfo, &p_dialinginfo, sizeof(struct dialing_info)); @@ -1354,6 +1280,12 @@ void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag // SCPY((char *)message->param.setup.useruser.data, useruser.info); // message->param.setup.useruser.len = strlen(mncc->useruser.info); // message->param.setup.useruser.protocol = mncc->useruser.proto; + if (p_s_rtp_bridge) { + PDEBUG(DEBUG_SIP, "sending setup with RTP info\n"); + message->param.setup.rtpinfo.payload_type = payload_type; + message->param.setup.rtpinfo.ip = p_s_rtp_ip_remote; + message->param.setup.rtpinfo.port = p_s_rtp_port_remote; + } message_put(message); } @@ -1377,7 +1309,7 @@ void Psip::i_bye(int status, char const *phrase, nua_t *nua, nua_magic_t *magic, add_trace("respond", "value", "200 OK"); end_trace(); // nua_handle_destroy(nh); - p_m_s_handle = NULL; + p_s_handle = NULL; rtp_close(); @@ -1391,7 +1323,7 @@ void Psip::i_bye(int status, char const *phrase, nua_t *nua, nua_magic_t *magic, free_epointlist(p_epointlist); } new_state(PORT_STATE_RELEASE); - trigger_work(&p_m_s_delete); + trigger_work(&p_s_delete); } void Psip::i_cancel(int status, char const *phrase, nua_t *nua, nua_magic_t *magic, nua_handle_t *nh, nua_hmagic_t *hmagic, sip_t const *sip, tagi_t tagss[]) @@ -1404,7 +1336,7 @@ void Psip::i_cancel(int status, char const *phrase, nua_t *nua, nua_magic_t *mag end_trace(); nua_handle_destroy(nh); - p_m_s_handle = NULL; + p_s_handle = NULL; rtp_close(); @@ -1418,7 +1350,7 @@ void Psip::i_cancel(int status, char const *phrase, nua_t *nua, nua_magic_t *mag free_epointlist(p_epointlist); } new_state(PORT_STATE_RELEASE); - trigger_work(&p_m_s_delete); + trigger_work(&p_s_delete); } void Psip::r_bye(int status, char const *phrase, nua_t *nua, nua_magic_t *magic, nua_handle_t *nh, nua_hmagic_t *hmagic, sip_t const *sip, tagi_t tagss[]) @@ -1426,11 +1358,11 @@ void Psip::r_bye(int status, char const *phrase, nua_t *nua, nua_magic_t *magic, PDEBUG(DEBUG_SIP, "bye response received\n"); nua_handle_destroy(nh); - p_m_s_handle = NULL; + p_s_handle = NULL; rtp_close(); - trigger_work(&p_m_s_delete); + trigger_work(&p_s_delete); } void Psip::r_cancel(int status, char const *phrase, nua_t *nua, nua_magic_t *magic, nua_handle_t *nh, nua_hmagic_t *hmagic, sip_t const *sip, tagi_t tagss[]) @@ -1438,11 +1370,11 @@ void Psip::r_cancel(int status, char const *phrase, nua_t *nua, nua_magic_t *mag PDEBUG(DEBUG_SIP, "cancel response received\n"); nua_handle_destroy(nh); - p_m_s_handle = NULL; + p_s_handle = NULL; rtp_close(); - trigger_work(&p_m_s_delete); + trigger_work(&p_s_delete); } void Psip::r_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *magic, nua_handle_t *nh, nua_hmagic_t *hmagic, sip_t const *sip, tagi_t tagss[]) @@ -1456,33 +1388,16 @@ void Psip::r_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag add_trace("respond", "value", "%d", status); end_trace(); - /* process 1xx */ - switch (status) { - case 100: - PDEBUG(DEBUG_SIP, "do proceeding\n"); - new_state(PORT_STATE_OUT_PROCEEDING); - message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROCEEDING); - message_put(message); - return; - case 180: - PDEBUG(DEBUG_SIP, "do alerting\n"); - new_state(PORT_STATE_OUT_ALERTING); - message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ALERTING); - message_put(message); - return; - default: - if (status < 100 || status > 199) - break; - PDEBUG(DEBUG_SIP, "skipping 1xx message\n"); - - return; - } - - /* process 2xx */ - if (status >= 200 && status <= 299) { + /* connect audio */ + if (status == 183 || (status >= 200 && status <= 299)) { int ret; + uint8_t payload_type; - ret = parse_sdp(sip, &p_m_s_rtp_ip_remote, &p_m_s_rtp_port_remote); + if (p_s_rtp_bridge) + payload_type = p_s_rtp_payload_type; + else + payload_type = (options.law=='a')?RTP_PT_ALAW:RTP_PT_ULAW; + ret = parse_sdp(sip, &p_s_rtp_ip_remote, &p_s_rtp_port_remote, payload_type); if (ret) { if (ret == 400) nua_cancel(nh, TAG_END()); @@ -1496,8 +1411,8 @@ void Psip::r_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag goto release_with_cause; } - /* connect to remote RTP */ - if (rtp_connect() < 0) { + /* connect to remote RTP (if not bridging) */ + if (!p_s_rtp_bridge && rtp_connect() < 0) { nua_cancel(nh, TAG_END()); sip_trace_header(this, "CANCEL", DIRECTION_OUT); add_trace("reason", NULL, "failed to open RTP/RTCP sockts"); @@ -1506,16 +1421,56 @@ void Psip::r_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag location = LOCATION_PRIVATE_LOCAL; goto release_with_cause; } + } + + /* process 1xx */ + switch (status) { + case 100: + PDEBUG(DEBUG_SIP, "do proceeding\n"); + new_state(PORT_STATE_OUT_PROCEEDING); + message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROCEEDING); + message_put(message); + return; + case 180: + PDEBUG(DEBUG_SIP, "do alerting\n"); + new_state(PORT_STATE_OUT_ALERTING); + message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ALERTING); + message_put(message); + return; + case 183: + PDEBUG(DEBUG_SIP, "do progress\n"); + message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROGRESS); + message->param.progressinfo.progress = 8; + message->param.progressinfo.location = 10; + if (p_s_rtp_bridge) { + message->param.progressinfo.rtpinfo.payload_type = p_s_rtp_payload_type; + message->param.progressinfo.rtpinfo.ip = p_s_rtp_ip_remote; + message->param.progressinfo.rtpinfo.port = p_s_rtp_port_remote; + } + message_put(message); + return; + default: + if (status < 100 || status > 199) + break; + PDEBUG(DEBUG_SIP, "skipping 1xx message\n"); + return; + } + + /* process 2xx */ + if (status >= 200 && status <= 299) { PDEBUG(DEBUG_SIP, "do connect\n"); nua_ack(nh, TAG_END()); new_state(PORT_STATE_CONNECT); message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_CONNECT); + if (p_s_rtp_bridge) { + message->param.connectinfo.rtpinfo.payload_type = p_s_rtp_payload_type; + message->param.connectinfo.rtpinfo.ip = p_s_rtp_ip_remote; + message->param.connectinfo.rtpinfo.port = p_s_rtp_port_remote; + } message_put(message); - return; } - cause = status2cause(status); location = LOCATION_BEYOND; @@ -1536,7 +1491,7 @@ release_with_cause: rtp_close(); - trigger_work(&p_m_s_delete); + trigger_work(&p_s_delete); } static void sip_callback(nua_event_t event, int status, char const *phrase, nua_t *nua, nua_magic_t *magic, nua_handle_t *nh, nua_hmagic_t *hmagic, sip_t const *sip, tagi_t tags[]) @@ -1553,16 +1508,27 @@ static void sip_callback(nua_event_t event, int status, char const *phrase, nua_ if (event == nua_i_invite) { char name[64]; + struct interface *interface = interface_first; + /* create call instance */ - SPRINT(name, "%s-%d-in", inst->interface->name, 0); - if (!(psip = new Psip(PORT_TYPE_SIP_IN, (inst->interface->ifport) ? inst->interface->ifport->mISDNport : NULL, name, NULL, 0, 0, B_MODE_TRANSPARENT, inst->interface))) + SPRINT(name, "%s-%d-in", inst->interface_name, 0); + while (interface) { + if (!strcmp(interface->name, inst->interface_name)) + break; + interface = interface->next; + } + if (!interface) { + PERROR("Cannot find interface %s.\n", inst->interface_name); + return; + } + if (!(psip = new Psip(PORT_TYPE_SIP_IN, name, NULL, interface))) FATAL("Cannot create Port instance.\n"); } else { port = port_first; while(port) { if ((port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_SIP) { psip = (class Psip *)port; - if (psip->p_m_s_handle == nh) { + if (psip->p_s_handle == nh) { break; } } @@ -1631,8 +1597,8 @@ void Psip::rtp_shutdown(void) sip_trace_header(this, "RTP terminated", DIRECTION_IN); end_trace(); - nua_handle_destroy(p_m_s_handle); - p_m_s_handle = NULL; + nua_handle_destroy(p_s_handle); + p_s_handle = NULL; while(p_epointlist) { /* send setup message to endpoit */ @@ -1644,7 +1610,7 @@ void Psip::rtp_shutdown(void) free_epointlist(p_epointlist); } new_state(PORT_STATE_RELEASE); - trigger_work(&p_m_s_delete); + trigger_work(&p_s_delete); } int sip_init_inst(struct interface *interface) @@ -1652,7 +1618,9 @@ int sip_init_inst(struct interface *interface) struct sip_inst *inst = (struct sip_inst *) MALLOC(sizeof(*inst)); interface->sip_inst = inst; - inst->interface = interface; + SCPY(inst->interface_name, interface->name); + SCPY(inst->local_ip, interface->sip_local_ip); + SCPY(inst->remote_ip, interface->sip_remote_ip); /* init root object */ inst->root = su_root_create(inst); diff --git a/sip.h b/sip.h index 1bc06f7..2cfc62d 100644 --- a/sip.h +++ b/sip.h @@ -12,57 +12,57 @@ #include /* SIP port class */ -class Psip : public PmISDN +class Psip : public Port { public: - Psip(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode, struct interface *interface); + Psip(int type, char *portname, struct port_settings *settings, struct interface *interface); ~Psip(); int message_epoint(unsigned int epoint_id, int message, union parameter *param); int message_connect(unsigned int epoint_id, int message, union parameter *param); int message_release(unsigned int epoint_id, int message, union parameter *param); int message_setup(unsigned int epoint_id, int message, union parameter *param); + int message_notify(unsigned int epoint_id, int message, union parameter *param); + int message_dtmf(unsigned int epoint_id, int message, union parameter *param); void i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *magic, nua_handle_t *nh, nua_hmagic_t *hmagic, sip_t const *sip, tagi_t tags[]); void i_bye(int status, char const *phrase, nua_t *nua, nua_magic_t *magic, nua_handle_t *nh, nua_hmagic_t *hmagic, sip_t const *sip, tagi_t tags[]); void i_cancel(int status, char const *phrase, nua_t *nua, nua_magic_t *magic, nua_handle_t *nh, nua_hmagic_t *hmagic, sip_t const *sip, tagi_t tags[]); void r_bye(int status, char const *phrase, nua_t *nua, nua_magic_t *magic, nua_handle_t *nh, nua_hmagic_t *hmagic, sip_t const *sip, tagi_t tags[]); void r_cancel(int status, char const *phrase, nua_t *nua, nua_magic_t *magic, nua_handle_t *nh, nua_hmagic_t *hmagic, sip_t const *sip, tagi_t tags[]); void r_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *magic, nua_handle_t *nh, nua_hmagic_t *hmagic, sip_t const *sip, tagi_t tags[]); - void *p_m_s_sip_inst; - struct lcr_work p_m_s_delete; - nua_handle_t *p_m_s_handle; - nua_magic_t *p_m_s_magic; - unsigned short p_m_s_rtp_port_local; - unsigned short p_m_s_rtp_port_remote; - unsigned int p_m_s_rtp_ip_local; - unsigned int p_m_s_rtp_ip_remote; - struct sockaddr_in p_m_s_rtp_sin_local; - struct sockaddr_in p_m_s_rtp_sin_remote; - struct sockaddr_in p_m_s_rtcp_sin_local; - struct sockaddr_in p_m_s_rtcp_sin_remote; - struct lcr_fd p_m_s_rtp_fd; - struct lcr_fd p_m_s_rtcp_fd; - int p_m_s_rtp_is_connected; /* if RTP session is connected, so we may send frames */ - int p_m_s_rtp_tx_action; - uint16_t p_m_s_rtp_tx_sequence; - uint32_t p_m_s_rtp_tx_timestamp; - uint32_t p_m_s_rtp_tx_ssrc; - struct timeval p_m_s_rtp_tx_last_tv; + void *p_s_sip_inst; + struct lcr_work p_s_delete; + nua_handle_t *p_s_handle; + nua_magic_t *p_s_magic; + int p_s_rtp_bridge; /* bridge RTP instead of having a local RTP peer */ + uint8_t p_s_rtp_payload_type; + unsigned short p_s_rtp_port_local; + unsigned short p_s_rtp_port_remote; + unsigned int p_s_rtp_ip_local; + unsigned int p_s_rtp_ip_remote; + struct sockaddr_in p_s_rtp_sin_local; + struct sockaddr_in p_s_rtp_sin_remote; + struct sockaddr_in p_s_rtcp_sin_local; + struct sockaddr_in p_s_rtcp_sin_remote; + struct lcr_fd p_s_rtp_fd; + struct lcr_fd p_s_rtcp_fd; + int p_s_rtp_is_connected; /* if RTP session is connected, so we may send frames */ + int p_s_rtp_tx_action; + uint16_t p_s_rtp_tx_sequence; + uint32_t p_s_rtp_tx_timestamp; + uint32_t p_s_rtp_tx_ssrc; + struct timeval p_s_rtp_tx_last_tv; int rtp_open(void); int rtp_connect(void); void rtp_close(void); - int rtp_send_frame(unsigned char *data, unsigned int len, int payload_type); - int p_m_s_b_sock; /* SIP bchannel socket */ - struct lcr_fd p_m_s_b_fd; /* event node */ - int p_m_s_b_index; /* SIP bchannel socket index to use */ - int p_m_s_b_active; /* SIP bchannel socket is activated */ - unsigned char p_m_s_rxdata[160]; /* receive audio buffer */ - int p_m_s_rxpos; /* position in audio buffer 0..159 */ - int hunt_bchannel(void); - void bchannel_close(void); - int bchannel_open(int); - void bchannel_receive(struct mISDNhead *hh, unsigned char *data, int len); - void bchannel_send(unsigned int prim, unsigned int id, unsigned char *data, int len); - int parse_sdp(sip_t const *sip, unsigned int *ip, unsigned short *port); + int rtp_send_frame(unsigned char *data, unsigned int len, uint8_t payload_type); + int p_s_b_sock; /* SIP bchannel socket */ + struct lcr_fd p_s_b_fd; /* event node */ + int p_s_b_index; /* SIP bchannel socket index to use */ + int p_s_b_active; /* SIP bchannel socket is activated */ + unsigned char p_s_rxdata[160]; /* receive audio buffer */ + int p_s_rxpos; /* position in audio buffer 0..159 */ + int bridge_rx(unsigned char *data, int len); + int parse_sdp(sip_t const *sip, unsigned int *ip, unsigned short *port, uint8_t payload_type); void rtp_shutdown(void); }; diff --git a/socket_server.c b/socket_server.c index 9a774b6..2fba2eb 100644 --- a/socket_server.c +++ b/socket_server.c @@ -844,6 +844,8 @@ int admin_state(struct admin_queue **responsep) interface = interface_first; while(interface) { ifport = interface->ifport; + if (!ifport) + i++; while(ifport) { i++; ifport = ifport->next; @@ -905,6 +907,18 @@ int admin_state(struct admin_queue **responsep) num = 0; while(interface) { ifport = interface->ifport; + if (!ifport) { + /* message */ + response->am[num].message = ADMIN_RESPONSE_S_INTERFACE; + /* interface */ + SCPY(response->am[num].u.i.interface_name, interface->name); + /* portnum */ + response->am[num].u.i.portnum = -100; /* indicate: no ifport */ + /* iftype */ + response->am[num].u.i.extension = interface->extension; + /* block */ + num++; + } while(ifport) { /* message */ response->am[num].message = ADMIN_RESPONSE_S_INTERFACE; diff --git a/ss5.cpp b/ss5.cpp index 09f97eb..a12f936 100644 --- a/ss5.cpp +++ b/ss5.cpp @@ -1740,8 +1740,8 @@ void Pss5::message_setup(unsigned int epoint_id, int message_id, union parameter memcpy(&p_capainfo, ¶m->setup.capainfo, sizeof(p_capainfo)); memcpy(&p_redirinfo, ¶m->setup.redirinfo, sizeof(p_redirinfo)); /* screen outgoing caller id */ - do_screen(1, p_callerinfo.id, sizeof(p_callerinfo.id), &p_callerinfo.ntype, &p_callerinfo.present, p_m_mISDNport->ifport->interface); - do_screen(1, p_callerinfo.id2, sizeof(p_callerinfo.id2), &p_callerinfo.ntype2, &p_callerinfo.present2, p_m_mISDNport->ifport->interface); + do_screen(1, p_callerinfo.id, sizeof(p_callerinfo.id), &p_callerinfo.ntype, &p_callerinfo.present, p_m_mISDNport->ifport->interface->name); + do_screen(1, p_callerinfo.id2, sizeof(p_callerinfo.id2), &p_callerinfo.ntype2, &p_callerinfo.present2, p_m_mISDNport->ifport->interface->name); /* parse dial string */ dash = 0; /* dash must be used next time */ -- 2.13.6