1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665 |
- /*
- * $Id$
- *
- * Copyright (C) 2013 Robert Boisvert
- *
- * This file is part of the mohqueue module for sip-router, a free SIP server.
- *
- * The mohqueue module is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * The mohqueue module is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
- #include <stdarg.h>
- #include "mohq.h"
- #include "mohq_db.h"
- #include "mohq_funcs.h"
- /**********
- * definitions
- **********/
- #define ALLOWHDR "Allow: INVITE, ACK, BYE, CANCEL, NOTIFY, PRACK"
- #define CLENHDR "Content-Length"
- #define SIPEOL "\r\n"
- #define USRAGNT "Kamailio MOH Queue v1.0"
- /**********
- * local constants
- **********/
- str p100rel [1] = {STR_STATIC_INIT ("100rel")};
- str pallq [1] = {STR_STATIC_INIT ("*")};
- str paudio [1] = {STR_STATIC_INIT ("audio")};
- str pbye [1] = {STR_STATIC_INIT ("BYE")};
- str pinvite [1] = {STR_STATIC_INIT ("INVITE")};
- str pmi_nolock [1] = {STR_STATIC_INIT ("Unable to lock queue")};
- str pmi_noqueue [1] = {STR_STATIC_INIT ("No matching queue name found")};
- str prefer [1] = {STR_STATIC_INIT ("REFER")};
- str presp_noaccept [1] = {STR_STATIC_INIT ("Not Acceptable Here")};
- str presp_noallow [1] = {STR_STATIC_INIT ("Method Not Allowed")};
- str presp_nocall [1] = {STR_STATIC_INIT ("Call/Transaction Does Not Exist")};
- str presp_ok [1] = {STR_STATIC_INIT ("OK")};
- str presp_reqpend [1] = {STR_STATIC_INIT ("Request Pending")};
- str presp_reqterm [1] = {STR_STATIC_INIT ("Request Terminated")};
- str presp_ring [1] = {STR_STATIC_INIT ("Ringing")};
- str psipfrag [1] = {STR_STATIC_INIT ("message/sipfrag")};
- str presp_srverr [1] = {STR_STATIC_INIT ("Server Internal Error")};
- str presp_unsupp [1] = {STR_STATIC_INIT ("Unsupported Media Type")};
- rtpmap prtpmap [] =
- {
- {9, "G722/8000"},
- {0, "PCMU/8000"},
- {8, "PCMA/8000"},
- {18, "G729/8000"},
- {3, "GSM/8000"},
- {4, "G723/8000"},
- {15, "G728/8000"},
- {5, "DVI4/8000"},
- {7, "LPC/8000"},
- {12, "QCELP/8000"},
- {13, "CN/8000"},
- {16, "DVI4/11025"},
- {6, "DVI4/16000"},
- {17, "DVI4/22050"},
- {10, "L16/44100"},
- {11, "L16/44100"},
- {14, "MPA/90000"},
- {0, 0}
- };
- rtpmap *pmohfiles [30]; // element count should be equal or greater than prtpmap
- str pallowhdr [1] = { STR_STATIC_INIT (ALLOWHDR SIPEOL) };
- char pbyemsg [] =
- {
- "%s"
- "Max-Forwards: 70" SIPEOL
- "Contact: <%s>" SIPEOL
- "User-Agent: " USRAGNT SIPEOL
- };
- str pextrahdr [1] =
- {
- STR_STATIC_INIT (
- ALLOWHDR SIPEOL
- "Supported: 100rel" SIPEOL
- "Accept-Language: en" SIPEOL
- "Content-Type: application/sdp" SIPEOL
- "User-Agent: " USRAGNT SIPEOL
- )
- };
- char pinvitesdp [] =
- {
- "v=0" SIPEOL
- "o=- %d %d IN %s" SIPEOL
- "s=" USRAGNT SIPEOL
- "c=IN %s" SIPEOL
- "t=0 0" SIPEOL
- "a=send%s" SIPEOL
- "m=audio %d RTP/AVP "
- };
- char prefermsg [] =
- {
- "%s"
- "Max-Forwards: 70" SIPEOL
- "Refer-To: <%s>" SIPEOL
- "Referred-By: <%.*s>" SIPEOL
- "User-Agent: " USRAGNT SIPEOL
- };
- char preinvitemsg [] =
- {
- "%s"
- "Max-Forwards: 70" SIPEOL
- "Contact: <%s>" SIPEOL
- ALLOWHDR SIPEOL
- "Supported: 100rel" SIPEOL
- "User-Agent: " USRAGNT SIPEOL
- "Accept-Language: en" SIPEOL
- "Content-Type: application/sdp" SIPEOL
- };
- char prtpsdp [] =
- {
- "v=0" SIPEOL
- // IP address and audio port faked since they will be replaced
- "o=- 1 1 IN IP4 1.1.1.1" SIPEOL
- "s=" USRAGNT SIPEOL
- "c=IN IP4 1.1.1.1" SIPEOL
- "t=0 0" SIPEOL
- "a=sendrecv" SIPEOL
- "m=audio 1 RTP/AVP"
- };
- /**********
- * local function declarations
- **********/
- void delete_call (call_lst *);
- void drop_call (sip_msg_t *, call_lst *);
- int find_call (sip_msg_t *, call_lst **);
- dlg_t *form_dialog (call_lst *, struct to_body *);
- int form_rtp_SDP (str *, call_lst *, char *);
- static void invite_cb (struct cell *, int, struct tmcb_params *);
- int refer_call (call_lst *, mohq_lock *);
- static void refer_cb (struct cell *, int, struct tmcb_params *);
- int send_prov_rsp (sip_msg_t *, call_lst *);
- int send_rtp_answer (sip_msg_t *, call_lst *);
- int search_hdr_ext (struct hdr_field *, str *);
- int start_stream (sip_msg_t *, call_lst *, int);
- /**********
- * local functions
- **********/
- /**********
- * Process ACK Message
- *
- * INPUT:
- * Arg (1) = SIP message pointer
- * Arg (2) = call pointer
- * OUTPUT: 0=failed
- **********/
- int ack_msg (sip_msg_t *pmsg, call_lst *pcall)
- {
- /**********
- * part of INVITE?
- **********/
- char *pfncname = "ack_msg: ";
- struct cell *ptrans;
- tm_api_t *ptm = pmod_data->ptm;
- if (pcall->call_state != CLSTA_INVITED)
- {
- /**********
- * ignore if from rejected re-INVITE
- **********/
- if (pcall->call_state != CLSTA_INQUEUE)
- { LM_ERR ("%sUnexpected ACK (%s)!", pfncname, pcall->call_from); }
- else
- {
- mohq_debug (pcall->pmohq, "%sACK from refused re-INVITE (%s)!",
- pfncname, pcall->call_from);
- }
- return 1;
- }
- /**********
- * o release INVITE transaction
- * o save SDP address info
- * o put in queue
- **********/
- if (ptm->t_lookup_ident (&ptrans, pcall->call_hash, pcall->call_label) < 0)
- {
- LM_ERR ("%sINVITE transaction missing for call (%s)!",
- pfncname, pcall->call_from);
- return 1;
- }
- else
- {
- if (ptm->t_release (pcall->call_pmsg) < 0)
- {
- LM_ERR ("%sRelease transaction failed for call (%s)!",
- pfncname, pcall->call_from);
- return 1;
- }
- }
- pcall->call_hash = pcall->call_label = 0;
- sprintf (pcall->call_addr, "%s %s",
- pmsg->rcv.dst_ip.af == AF_INET ? "IP4" : "IP6",
- ip_addr2a (&pmsg->rcv.dst_ip));
- pcall->call_state = CLSTA_INQUEUE;
- update_call_rec (pcall);
- pcall->call_cseq = 1;
- mohq_debug (pcall->pmohq,
- "%sACK received for call (%s); placed in queue (%s)",
- pfncname, pcall->call_from, pcall->pmohq->mohq_name);
- return 1;
- }
- /**********
- * BYE Callback
- *
- * INPUT:
- * Arg (1) = cell pointer
- * Arg (2) = callback type
- * Arg (3) = callback parms
- * OUTPUT: none
- **********/
- static void bye_cb
- (struct cell *ptrans, int ntype, struct tmcb_params *pcbp)
- {
- /**********
- * o error means must have hung after REFER
- * o delete the call
- **********/
- char *pfncname = "bye_cb: ";
- call_lst *pcall = (call_lst *)*pcbp->param;
- if (ntype == TMCB_ON_FAILURE)
- {
- LM_ERR ("%sCall (%s) did not respond to BYE", pfncname,
- pcall->call_from);
- }
- else
- {
- int nreply = pcbp->code;
- if ((nreply / 100) != 2)
- {
- LM_ERR ("%sCall (%s) BYE error (%d)", pfncname,
- pcall->call_from, nreply);
- }
- else
- {
- mohq_debug (pcall->pmohq, "%sCall (%s) BYE reply=%d", pfncname,
- pcall->call_from, nreply);
- }
- }
- delete_call (pcall);
- return;
- }
- /**********
- * Process BYE Message
- *
- * INPUT:
- * Arg (1) = SIP message pointer
- * Arg (2) = call pointer
- * OUTPUT: 0=failed
- **********/
- int bye_msg (sip_msg_t *pmsg, call_lst *pcall)
- {
- /**********
- * o send OK
- * o teardown call
- **********/
- char *pfncname = "bye_msg: ";
- if (pmod_data->psl->freply (pmsg, 200, presp_ok) < 0)
- {
- LM_ERR ("%sUnable to create reply to call (%s)", pfncname,
- pcall->call_from);
- return 1;
- }
- if (pcall->call_state >= CLSTA_INQUEUE)
- { drop_call (pmsg, pcall); }
- else
- {
- LM_ERR ("%sEnding call (%s) before placed in queue!",
- pfncname, pcall->call_from);
- delete_call (pcall);
- }
- return 1;
- }
- /**********
- * Process CANCEL Message
- *
- * INPUT:
- * Arg (1) = SIP message pointer
- * Arg (2) = call pointer
- * OUTPUT: 0=failed
- **********/
- int cancel_msg (sip_msg_t *pmsg, call_lst *pcall)
- {
- /**********
- * still in INVITE dialog?
- **********/
- char *pfncname = "cancel_msg: ";
- if (pcall->call_state < CLSTA_INQUEUE)
- {
- pcall->call_state = CLSTA_CANCEL;
- mohq_debug (pcall->pmohq, "%sCANCELed call (%s)",
- pfncname, pcall->call_from);
- if (pmod_data->psl->freply (pmsg, 487, presp_reqterm) < 0)
- { LM_ERR ("%sUnable to create reply!", pfncname); }
- }
- else
- {
- LM_ERR ("%sUnable to CANCEL because accepted INVITE for call (%s)!",
- pfncname, pcall->call_from);
- if (pmod_data->psl->freply (pmsg, 481, presp_nocall) < 0)
- { LM_ERR ("%sUnable to create reply!", pfncname); }
- }
- return 1;
- }
- /**********
- * Close the Call
- *
- * INPUT:
- * Arg (1) = SIP message pointer
- * Arg (2) = call pointer
- * OUTPUT: none
- **********/
- void close_call (sip_msg_t *pmsg, call_lst *pcall)
- {
- /**********
- * o destroy proxy connection
- * o create dialog
- **********/
- char *pfncname = "close_call: ";
- int bsent = 0;
- char *phdr = 0;
- if (pmsg != FAKED_REPLY)
- {
- mohq_debug (pcall->pmohq, "%sDestroying RTP link for call (%s)",
- pfncname, pcall->call_from);
- if (pmod_data->fn_rtp_destroy (pmsg, 0, 0) != 1)
- {
- LM_ERR ("%srtpproxy_destroy refused for call (%s)!",
- pfncname, pcall->call_from);
- }
- }
- struct to_body ptob [2];
- dlg_t *pdlg = form_dialog (pcall, ptob);
- if (!pdlg)
- { goto bye_err; }
- pdlg->state = DLG_CONFIRMED;
- /**********
- * form BYE header
- * o calculate size
- * o create buffer
- **********/
- tm_api_t *ptm = pmod_data->ptm;
- char *pquri = pcall->pmohq->mohq_uri;
- int npos1 = sizeof (pbyemsg) // BYE template
- + strlen (pcall->call_via) // Via
- + strlen (pquri); // Contact
- phdr = pkg_malloc (npos1);
- if (!phdr)
- {
- LM_ERR ("%sNo more memory!", pfncname);
- goto bye_err;
- }
- sprintf (phdr, pbyemsg,
- pcall->call_via, // Via
- pquri); // Contact
- str phdrs [1];
- phdrs->s = phdr;
- phdrs->len = strlen (phdr);
- /**********
- * send BYE request
- **********/
- uac_req_t puac [1];
- set_uac_req (puac, pbye, phdrs, 0, pdlg,
- TMCB_LOCAL_COMPLETED | TMCB_ON_FAILURE, bye_cb, pcall);
- pcall->call_state = CLSTA_BYE;
- if (ptm->t_request_within (puac) < 0)
- {
- LM_ERR ("%sUnable to create BYE request for call (%s)!",
- pfncname, pcall->call_from);
- goto bye_err;
- }
- mohq_debug (pcall->pmohq, "%sSent BYE request for call (%s)",
- pfncname, pcall->call_from);
- bsent = 1;
- /**********
- * o free memory
- * o delete call
- **********/
- bye_err:
- if (pdlg)
- { pkg_free (pdlg); }
- if (phdr)
- { pkg_free (phdr); }
- if (!bsent)
- { delete_call (pcall); }
- return;
- }
- /**********
- * Create New Call Record
- *
- * INPUT:
- * Arg (1) = queue index
- * Arg (2) = SIP message pointer
- * OUTPUT: call index; -1 if unable to create
- **********/
- int create_call (int mohq_idx, sip_msg_t *pmsg)
- {
- /**********
- * o lock calls
- * o already in use?
- * o find inactive slot
- **********/
- char *pfncname = "create_call: ";
- if (!mohq_lock_set (pmod_data->pcall_lock, 1, 2000))
- {
- LM_ERR ("%sUnable to lock calls!", pfncname);
- return -1;
- }
- call_lst *pcall;
- int ncall_idx = find_call (pmsg, &pcall);
- if (pcall)
- {
- mohq_lock_release (pmod_data->pcall_lock);
- LM_ERR ("%sCall already in use (%s)!", pfncname, pcall->call_from);
- return -1;
- }
- for (ncall_idx = 0; ncall_idx < pmod_data->call_cnt; ncall_idx++)
- {
- if (!pmod_data->pcall_lst [ncall_idx].call_active)
- { break; }
- }
- if (ncall_idx == pmod_data->call_cnt)
- {
- mohq_lock_release (pmod_data->pcall_lock);
- LM_ERR ("%sNo call slots available!", pfncname);
- return -1;
- }
- /**********
- * add values to new entry
- **********/
- pcall = &pmod_data->pcall_lst [ncall_idx];
- pcall->call_active = 1;
- pcall->pmohq = &pmod_data->pmohq_lst [mohq_idx];
- pcall->call_state = 0;
- str *pstr = &pmsg->callid->body;
- strncpy (pcall->call_id, pstr->s, pstr->len);
- pcall->call_id [pstr->len] = '\0';
- pstr = &pmsg->from->body;
- strncpy (pcall->call_from, pstr->s, pstr->len);
- pcall->call_from [pstr->len] = '\0';
- *pcall->call_tag = '\0';
- if (!pmsg->contact)
- { *pcall->call_contact = '\0'; }
- else
- {
- pstr = &pmsg->contact->body;
- strncpy (pcall->call_contact, pstr->s, pstr->len);
- pcall->call_contact [pstr->len] = '\0';
- }
- /**********
- * extract Via headers
- **********/
- hdr_field_t *phdr = pmsg->h_via1;
- if (phdr)
- {
- int npos1 = 0;
- while ((phdr = next_sibling_hdr (phdr)))
- {
- struct via_body *pvia;
- char *pviabuf;
- int bovrflow = 0;
- int npos2;
- int nvia_max = sizeof (pcall->call_via);
- for (pvia = (struct via_body *)phdr->parsed; pvia; pvia = pvia->next)
- {
- /**********
- * o skip trailing whitespace
- * o check if overflow
- **********/
- npos2 = pvia->bsize;
- pviabuf = pvia->name.s;
- while (npos2)
- {
- --npos2;
- if (pviabuf [npos2] == ' ' || pviabuf [npos2] == '\r'
- || pviabuf [npos2] == '\n' || pviabuf [npos2] == '\t' || pviabuf [npos2] == ',')
- { continue; }
- break;
- }
- if ((npos2 + npos1 + 7) >= nvia_max)
- {
- LM_WARN ("%sVia buffer overflowed!", pfncname);
- bovrflow = 1;
- break;
- }
- /**********
- * copy via
- **********/
- strcpy (&pcall->call_via [npos1], "Via: ");
- npos1 += 5;
- strncpy (&pcall->call_via [npos1], pviabuf, npos2);
- npos1 += npos2;
- strcpy (&pcall->call_via [npos1], SIPEOL);
- npos1 += 2;
- }
- if (bovrflow)
- { break; }
- }
- }
- /**********
- * o release call lock
- * o update DB
- * o lock MOH queue
- **********/
- pcall->call_state = CLSTA_ENTER;
- mohq_lock_release (pmod_data->pcall_lock);
- add_call_rec (ncall_idx);
- mohq_lock_set (pmod_data->pmohq_lock, 0, 0);
- mohq_debug (pcall->pmohq, "%sAdded call (%s) to queue (%s)",
- pfncname, pcall->call_from, pcall->pmohq->mohq_name);
- return ncall_idx;
- }
- /**********
- * Delete Call
- *
- * INPUT:
- * Arg (1) = call pointer
- * OUTPUT: none
- **********/
- void delete_call (call_lst *pcall)
- {
- /**********
- * release transaction
- **********/
- char *pfncname = "delete_call: ";
- struct cell *ptrans;
- tm_api_t *ptm = pmod_data->ptm;
- if (pcall->call_hash || pcall->call_label)
- {
- if (ptm->t_lookup_ident (&ptrans, pcall->call_hash, pcall->call_label) < 0)
- {
- LM_ERR ("%sLookup transaction failed for call (%s)!", pfncname,
- pcall->call_from);
- }
- else
- {
- if (ptm->t_release (pcall->call_pmsg) < 0)
- {
- LM_ERR ("%sRelease transaction failed for call (%s)!",
- pfncname, pcall->call_from);
- }
- }
- pcall->call_hash = pcall->call_label = 0;
- }
- /**********
- * o update DB
- * o inactivate slot
- * o release MOH queue
- **********/
- mohq_debug (pcall->pmohq, "delete_call: Deleting call (%s) from queue (%s)",
- pcall->call_from, pcall->pmohq->mohq_name);
- delete_call_rec (pcall);
- pcall->call_active = 0;
- mohq_lock_release (pmod_data->pmohq_lock);
- return;
- }
- /**********
- * Deny Method
- *
- * INPUT:
- * Arg (1) = SIP message pointer
- * Arg (2) = call pointer
- * OUTPUT: none
- **********/
- void deny_method (sip_msg_t *pmsg, call_lst *pcall)
- {
- /**********
- * RFC 3261 section 8.2.1
- * o get transaction
- * o respond with 405 and Allow header
- **********/
- char *pfncname = "deny_method: ";
- tm_api_t *ptm = pmod_data->ptm;
- if (ptm->t_newtran (pmsg) < 0)
- {
- LM_ERR ("%sUnable to create new transaction!", pfncname);
- if (pmod_data->psl->freply (pmsg, 500, presp_srverr) < 0)
- {
- LM_ERR ("%sUnable to create reply to %.*s!", pfncname,
- STR_FMT (&REQ_LINE (pmsg).method));
- }
- return;
- }
- if (!add_lump_rpl2 (pmsg, pallowhdr->s, pallowhdr->len, LUMP_RPL_HDR))
- { LM_ERR ("%sUnable to add Allow header!", pfncname); }
- LM_ERR ("%sRefused %.*s for call (%s)!", pfncname,
- STR_FMT (&REQ_LINE (pmsg).method), pcall->call_from);
- if (ptm->t_reply (pmsg, 405, presp_noallow->s) < 0)
- {
- LM_ERR ("%sUnable to create reply to %.*s!", pfncname,
- STR_FMT (&REQ_LINE (pmsg).method));
- }
- return;
- }
- /**********
- * Drop the Call
- *
- * INPUT:
- * Arg (1) = SIP message pointer
- * Arg (2) = call pointer
- * OUTPUT: none
- **********/
- void drop_call (sip_msg_t *pmsg, call_lst *pcall)
- {
- /**********
- * o destroy proxy connection
- * o delete call
- **********/
- char *pfncname = "drop_call: ";
- if (pmsg != FAKED_REPLY)
- {
- mohq_debug (pcall->pmohq, "%sDestroying RTP link for call (%s)",
- pfncname, pcall->call_from);
- if (pmod_data->fn_rtp_destroy (pmsg, 0, 0) != 1)
- {
- LM_ERR ("%srtpproxy_destroy refused for call (%s)!",
- pfncname, pcall->call_from);
- }
- }
- delete_call (pcall);
- return;
- }
- /**********
- * Find Call
- *
- * INPUT:
- * Arg (1) = SIP message pointer
- * Arg (2) = pointer to call pointer
- * OUTPUT: queue index; -1 if unable to find
- **********/
- int find_call (sip_msg_t *pmsg, call_lst **ppcall)
- {
- /**********
- * o find current RURI
- * o strip off parms or headers
- * o search MOH queue
- **********/
- str *pruri =
- pmsg->new_uri.s ? &pmsg->new_uri : &pmsg->first_line.u.request.uri;
- int nidx;
- str pstr [1];
- pstr->s = pruri->s;
- pstr->len = pruri->len;
- for (nidx = 0; nidx < pruri->len; nidx++)
- {
- if (pstr->s [nidx] == ';' || pstr->s [nidx] == '?')
- {
- pstr->len = nidx;
- break;
- }
- }
- mohq_lst *pqlst = pmod_data->pmohq_lst;
- int nqidx;
- for (nqidx = 0; nqidx < pmod_data->mohq_cnt; nqidx++)
- {
- str pmohstr [1];
- pmohstr->s = pqlst [nqidx].mohq_uri;
- pmohstr->len = strlen (pmohstr->s);
- if (STR_EQ (*pmohstr, *pstr))
- { break; }
- }
- *ppcall = 0;
- if (nqidx == pmod_data->mohq_cnt)
- { return -1;}
- /**********
- * o get to tag
- * o get callID
- * o ignore to tag if CANCEL on first INVITE
- * o search call queue
- **********/
- str *ptotag = &(get_to (pmsg)->tag_value);
- if (!ptotag->len)
- { ptotag = 0; }
- if (!pmsg->callid)
- { return -1; }
- str *pcallid = &pmsg->callid->body;
- if (!pcallid)
- { return -1; }
- for (nidx = 0; nidx < pmod_data->call_cnt; nidx++)
- {
- /**********
- * o call active?
- * o call timed out on ACK?
- * o callID matches?
- * o to tag matches?
- * o return call pointer
- **********/
- call_lst *pcall = &pmod_data->pcall_lst [nidx];
- if (!pcall->call_active)
- { continue; }
- if (pcall->call_time && (pcall->call_state < CLSTA_INQUEUE))
- {
- if ((pcall->call_time + 32) < time (0))
- {
- LM_ERR ("find_call: No ACK response for call (%s)", pcall->call_from);
- delete_call (pcall);
- continue;
- }
- }
- str tmpstr [1];
- tmpstr->s = pcall->call_id;
- tmpstr->len = strlen (tmpstr->s);
- if (!STR_EQ (*tmpstr, *pcallid))
- { continue; }
- if (ptotag)
- {
- tmpstr->s = pcall->call_tag;
- tmpstr->len = strlen (tmpstr->s);
- if (!STR_EQ (*tmpstr, *ptotag))
- { continue; }
- }
- *ppcall = pcall;
- return nqidx;
- }
- /**********
- * first INVITE?
- **********/
- if (pmsg->REQ_METHOD == METHOD_INVITE)
- { return 0; }
- return -1;
- }
- /**********
- * Find Queue
- *
- * INPUT:
- * Arg (1) = queue name str pointer
- * OUTPUT: queue index; -1 if unable to find
- **********/
- int find_queue (str *pqname)
- {
- char *pfncname = "find_queue: ";
- int nidx;
- str tmpstr;
- if (!mohq_lock_set (pmod_data->pmohq_lock, 0, 500))
- {
- LM_ERR ("%sUnable to lock queues!", pfncname);
- return -1;
- }
- for (nidx = 0; nidx < pmod_data->mohq_cnt; nidx++)
- {
- tmpstr.s = pmod_data->pmohq_lst [nidx].mohq_name;
- tmpstr.len = strlen (tmpstr.s);
- if (STR_EQ (tmpstr, *pqname))
- { break; }
- }
- if (nidx == pmod_data->mohq_cnt)
- {
- LM_ERR ("%sUnable to find queue (%.*s)!", pfncname, STR_FMT (pqname));
- nidx = -1;
- }
- mohq_lock_release (pmod_data->pmohq_lock);
- return nidx;
- }
- /**********
- * Find Referred Call
- *
- * INPUT:
- * Arg (1) = referred-by value
- * OUTPUT: call index; -1 if unable to find
- **********/
- int find_referred_call (str *pvalue)
- {
- /**********
- * get URI
- **********/
- char *pfncname = "find_referred_call: ";
- struct to_body pref [1];
- parse_to (pvalue->s, &pvalue->s [pvalue->len + 1], pref);
- if (pref->error != PARSE_OK)
- {
- // should never happen
- LM_ERR ("%sInvalid Referred-By URI (%.*s)!", pfncname, STR_FMT (pvalue));
- return -1;
- }
- if (pref->param_lst)
- { free_to_params (pref); }
- /**********
- * search calls for matching
- **********/
- int nidx;
- str tmpstr;
- struct to_body pfrom [1];
- for (nidx = 0; nidx < pmod_data->call_cnt; nidx++)
- {
- if (!pmod_data->pcall_lst [nidx].call_active)
- { continue; }
- tmpstr.s = pmod_data->pcall_lst [nidx].call_from;
- tmpstr.len = strlen (tmpstr.s);
- parse_to (tmpstr.s, &tmpstr.s [tmpstr.len + 1], pfrom);
- if (pfrom->error != PARSE_OK)
- {
- // should never happen
- LM_ERR ("%sInvalid From URI (%.*s)!", pfncname, STR_FMT (&tmpstr));
- continue;
- }
- if (pfrom->param_lst)
- { free_to_params (pfrom); }
- if (STR_EQ (pfrom->uri, pref->uri))
- { return nidx; }
- }
- return -1;
- }
- /**********
- * Process First INVITE Message
- *
- * INPUT:
- * Arg (1) = SIP message pointer
- * Arg (2) = queue index
- * OUTPUT: 0=failed
- **********/
- int first_invite_msg (sip_msg_t *pmsg, int mohq_idx)
- {
- /**********
- * create call record
- **********/
- char *pfncname = "first_invite_msg: ";
- int ncall_idx = create_call (mohq_idx, pmsg);
- if (ncall_idx == -1)
- { return 0; }
- call_lst *pcall = &pmod_data->pcall_lst [ncall_idx];
- /**********
- * o SDP exists?
- * o accepts REFER?
- * o send rtpproxy offer
- **********/
- if (!(pmsg->msg_flags & FL_SDP_BODY))
- {
- if (parse_sdp (pmsg))
- {
- LM_ERR ("%sINVITE lacks SDP (%s)!", pfncname, pcall->call_from);
- delete_call (pcall);
- return 0;
- }
- }
- if (pmsg->allow)
- {
- if (!search_hdr_ext (pmsg->allow, prefer))
- {
- LM_ERR ("%sMissing REFER support (%s)!", pfncname, pcall->call_from);
- delete_call (pcall);
- return 0;
- }
- }
- mohq_debug (pcall->pmohq, "%sMaking offer for RTP link for call (%s)",
- pfncname, pcall->call_from);
- if (pmod_data->fn_rtp_offer (pmsg, 0, 0) != 1)
- {
- LM_ERR ("%srtpproxy_offer refused for call (%s)!",
- pfncname, pcall->call_from);
- delete_call (pcall);
- return 0;
- }
- /**********
- * o create new transaction
- * o save To tag
- * o catch failures
- * o save transaction data
- **********/
- tm_api_t *ptm = pmod_data->ptm;
- if (ptm->t_newtran (pmsg) < 0)
- {
- LM_ERR ("%sUnable to create new transaction for call (%s)!",
- pfncname, pcall->call_from);
- delete_call (pcall);
- return 0;
- }
- struct cell *ptrans = ptm->t_gett ();
- pcall->call_hash = ptrans->hash_index;
- pcall->call_label = ptrans->label;
- str ptotag [1];
- if (ptm->t_get_reply_totag (pmsg, ptotag) != 1)
- {
- LM_ERR ("%sUnable to create totag for call (%s)!",
- pfncname, pcall->call_from);
- if (ptm->t_reply (pmsg, 500, presp_srverr->s) < 0)
- { LM_ERR ("%sUnable to reply to INVITE!", pfncname); }
- delete_call (pcall);
- return 1;
- }
- strncpy (pcall->call_tag, ptotag->s, ptotag->len);
- pcall->call_tag [ptotag->len] = '\0';
- pcall->call_cseq = 1;
- if (ptm->register_tmcb (pmsg, 0, TMCB_DESTROY | TMCB_ON_FAILURE,
- invite_cb, pcall, 0) < 0)
- {
- LM_ERR ("%sUnable to set callback for call (%s)!",
- pfncname, pcall->call_from);
- if (ptm->t_reply (pmsg, 500, presp_srverr->s) < 0)
- { LM_ERR ("%sUnable to reply to INVITE!", pfncname); }
- delete_call (pcall);
- return 1;
- }
- /**********
- * o add contact to reply
- * o supports/requires PRACK? (RFC 3262 section 3)
- * o exit if not ringing
- **********/
- str pcontact [1];
- char *pcontacthdr = "Contact: <%s>" SIPEOL;
- pcontact->s = pkg_malloc (strlen (pmod_data->pmohq_lst [mohq_idx].mohq_uri)
- + strlen (pcontacthdr));
- if (!pcontact->s)
- {
- LM_ERR ("%sNo more memory!", pfncname);
- delete_call (pcall);
- return 1;
- }
- sprintf (pcontact->s, pcontacthdr, pmod_data->pmohq_lst [mohq_idx].mohq_uri);
- pcontact->len = strlen (pcontact->s);
- if (!add_lump_rpl2 (pmsg, pcontact->s, pcontact->len, LUMP_RPL_HDR))
- {
- LM_ERR ("%sUnable to add contact (%s) to call (%s)!",
- pfncname, pcontact->s, pcall->call_from);
- }
- pkg_free (pcontact->s);
- pcall->call_pmsg = pmsg;
- if (search_hdr_ext (pmsg->require, p100rel))
- {
- if (!send_prov_rsp (pmsg, pcall))
- {
- delete_call (pcall);
- return 1;
- }
- }
- else
- {
- if (ptm->t_reply (pmsg, 180, presp_ring->s) < 0)
- {
- LM_ERR ("%sUnable to reply to INVITE!", pfncname);
- return 1;
- }
- else
- {
- pcall->call_state = CLSTA_RINGING;
- mohq_debug (pcall->pmohq, "%sSent RINGING for call (%s)",
- pfncname, pcall->call_from);
- }
- }
- /**********
- * o call cancelled?
- * o accept call with RTP
- **********/
- if (pcall->call_state == CLSTA_CANCEL)
- {
- delete_call (pcall);
- return 1;
- }
- if (!send_rtp_answer (pmsg, pcall))
- {
- if (pmod_data->psl->freply (pmsg, 500, presp_srverr) < 0)
- { LM_ERR ("%sUnable to create reply!", pfncname); }
- delete_call (pcall);
- }
- return 1;
- }
- /**********
- * Form Dialog
- *
- * INPUT:
- * Arg (1) = call pointer
- * Arg (2) = to_body [2] pointer
- * OUTPUT: dlg_t * if successful; 0=if not
- **********/
- dlg_t *form_dialog (call_lst *pcall, struct to_body *pto_body)
- {
- /**********
- * get from/to values
- **********/
- char *pfncname = "form_dialog: ";
- struct to_body *ptob = &pto_body [0];
- struct to_body *pcontact = &pto_body [1];
- parse_to (pcall->call_from,
- &pcall->call_from [strlen (pcall->call_from) + 1], ptob);
- if (ptob->error != PARSE_OK)
- {
- // should never happen
- LM_ERR ("%sInvalid from URI (%s)!", pfncname, pcall->call_from);
- return 0;
- }
- if (ptob->param_lst)
- { free_to_params (ptob); }
- str ptarget [1];
- if (!*pcall->call_contact)
- {
- ptarget->s = ptob->uri.s;
- ptarget->len = ptob->uri.len;
- }
- else
- {
- parse_to (pcall->call_contact,
- &pcall->call_contact [strlen (pcall->call_contact) + 1], pcontact);
- if (pcontact->error != PARSE_OK)
- {
- // should never happen
- LM_ERR ("%sInvalid contact (%s) for call (%s)!", pfncname,
- pcall->call_contact, pcall->call_from);
- return 0;
- }
- if (pcontact->param_lst)
- { free_to_params (pcontact); }
- ptarget->s = pcontact->uri.s;
- ptarget->len = pcontact->uri.len;
- }
- /**********
- * create dialog
- **********/
- dlg_t *pdlg = (dlg_t *)pkg_malloc (sizeof (dlg_t));
- if (!pdlg)
- {
- LM_ERR ("%sNo more memory!", pfncname);
- return 0;
- }
- memset (pdlg, 0, sizeof (dlg_t));
- pdlg->loc_seq.value = pcall->call_cseq++;
- pdlg->loc_seq.is_set = 1;
- pdlg->id.call_id.s = pcall->call_id;
- pdlg->id.call_id.len = strlen (pcall->call_id);
- pdlg->id.loc_tag.s = pcall->call_tag;
- pdlg->id.loc_tag.len = strlen (pcall->call_tag);
- pdlg->id.rem_tag.s = ptob->tag_value.s;
- pdlg->id.rem_tag.len = ptob->tag_value.len;
- pdlg->rem_target.s = ptarget->s;
- pdlg->rem_target.len = ptarget->len;
- pdlg->loc_uri.s = pcall->pmohq->mohq_uri;
- pdlg->loc_uri.len = strlen (pdlg->loc_uri.s);
- pdlg->rem_uri.s = ptob->uri.s;
- pdlg->rem_uri.len = ptob->uri.len;
- return pdlg;
- }
- /**********
- * Form RTP SDP String
- *
- * INPUT:
- * Arg (1) = string pointer
- * Arg (2) = call pointer
- * Arg (3) = SDP body pointer
- * OUTPUT: 0 if failed
- **********/
- int form_rtp_SDP (str *pstr, call_lst *pcall, char *pSDP)
- {
- /**********
- * o find available files
- * o calculate size of SDP
- **********/
- char *pfncname = "form_rtp_SDP: ";
- rtpmap **pmohfiles = find_MOH (pcall->pmohq->mohq_mohdir,
- pcall->pmohq->mohq_mohfile);
- if (!pmohfiles [0])
- {
- LM_ERR ("%sUnable to find any MOH files for queue (%s)!", pfncname,
- pcall->pmohq->mohq_name);
- return 0;
- }
- int nsize = strlen (pSDP) + 2;
- int nidx;
- for (nidx = 0; pmohfiles [nidx]; nidx++)
- {
- nsize += strlen (pmohfiles [nidx]->pencode) // encode length
- + 19; // space, type number, "a=rtpmap:%d ", EOL
- }
- /**********
- * o allocate memory
- * o form SDP
- **********/
- pstr->s = pkg_malloc (nsize + 1);
- if (!pstr->s)
- {
- LM_ERR ("%sNo more memory!", pfncname);
- return 0;
- }
- strcpy (pstr->s, pSDP);
- nsize = strlen (pstr->s);
- for (nidx = 0; pmohfiles [nidx]; nidx++)
- {
- /**********
- * add payload types to media description
- **********/
- sprintf (&pstr->s [nsize], " %d", pmohfiles [nidx]->ntype);
- nsize += strlen (&pstr->s [nsize]);
- }
- strcpy (&pstr->s [nsize], SIPEOL);
- nsize += 2;
- for (nidx = 0; pmohfiles [nidx]; nidx++)
- {
- /**********
- * add rtpmap attributes
- **********/
- sprintf (&pstr->s [nsize], "a=rtpmap:%d %s %s",
- pmohfiles [nidx]->ntype, pmohfiles [nidx]->pencode, SIPEOL);
- nsize += strlen (&pstr->s [nsize]);
- }
- pstr->len = nsize;
- return 1;
- }
- /**********
- * Invite Callback
- *
- * INPUT:
- * Arg (1) = cell pointer
- * Arg (2) = callback type
- * Arg (3) = callback parms
- * OUTPUT: none
- **********/
- static void
- invite_cb (struct cell *ptrans, int ntype, struct tmcb_params *pcbp)
- {
- call_lst *pcall = (call_lst *)*pcbp->param;
- if (ntype == TMCB_DESTROY)
- { pcall->call_hash = pcall->call_label = 0; }
- LM_ERR ("invite_cb: INVITE failed for call (%s)!", pcall->call_from);
- delete_call (pcall);
- return;
- }
- /**********
- * Process NOTIFY Message
- *
- * INPUT:
- * Arg (1) = SIP message pointer
- * Arg (2) = call pointer
- * OUTPUT: 0=failed
- **********/
- int notify_msg (sip_msg_t *pmsg, call_lst *pcall)
- {
- /**********
- * waiting on REFER?
- **********/
- char *pfncname = "notify_msg: ";
- if (pcall->call_state != CLSTA_RFRWAIT)
- {
- LM_ERR ("%sNot waiting on a REFER for call (%s)!", pfncname,
- pcall->call_from);
- if (pmod_data->psl->freply (pmsg, 481, presp_nocall) < 0)
- { LM_ERR ("%sUnable to create reply!", pfncname); }
- return 1;
- }
- /**********
- * o sipfrag?
- * o get status from body
- * o add CRLF so parser can go beyond first line
- **********/
- if (!search_hdr_ext (pmsg->content_type, psipfrag))
- {
- LM_ERR ("%sNot a %s type for call (%s)!", pfncname,
- psipfrag->s, pcall->call_from);
- if (pmod_data->psl->freply (pmsg, 415, presp_unsupp) < 0)
- { LM_ERR ("%sUnable to create reply!", pfncname); }
- return 1;
- }
- char *pfrag = get_body (pmsg);
- if (!pfrag)
- {
- LM_ERR ("%s%s body missing for call (%s)!", pfncname,
- psipfrag->s, pcall->call_from);
- if (pmod_data->psl->freply (pmsg, 415, presp_unsupp) < 0)
- { LM_ERR ("%sUnable to create reply!", pfncname); }
- return 1;
- }
- str pbody [1];
- pbody->len = pmsg->len - (int)(pfrag - pmsg->buf);
- pbody->s = pkg_malloc (pbody->len + 2);
- if (!pbody->s)
- {
- LM_ERR ("%sNo more memory!", pfncname);
- return 1;
- }
- strncpy (pbody->s, pfrag, pbody->len);
- if (pbody->s [pbody->len - 1] != '\n')
- {
- strncpy (&pbody->s [pbody->len], SIPEOL, 2);
- pbody->len += 2;
- }
- struct msg_start pstart [1];
- parse_first_line (pbody->s, pbody->len + 1, pstart);
- pkg_free (pbody->s);
- if (pstart->type != SIP_REPLY)
- {
- LM_ERR ("%sReply missing for call (%s)!", pfncname, pcall->call_from);
- if (pmod_data->psl->freply (pmsg, 415, presp_unsupp) < 0)
- { LM_ERR ("%sUnable to create reply!", pfncname); }
- return 1;
- }
- /**********
- * o send OK
- * o REFER done?
- **********/
- if (pmod_data->psl->freply (pmsg, 200, presp_ok) < 0)
- {
- LM_ERR ("%sUnable to create reply for call (%s)!",
- pfncname, pcall->call_from);
- return 1;
- }
- int nreply = pstart->u.reply.statuscode;
- mohq_debug (pcall->pmohq, "%sNOTIFY received reply (%d) for call (%s)",
- pfncname, nreply, pcall->call_from);
- switch (nreply / 100)
- {
- case 1:
- break;
- case 2:
- close_call (pmsg, pcall);
- break;
- default:
- LM_WARN ("%sUnable to redirect call (%s)!", pfncname, pcall->call_from);
- if (nreply == 487)
- {
- /**********
- * call was canceled
- **********/
- drop_call (pmsg, pcall);
- return 1;
- }
- /**********
- * return call to queue
- **********/
- pcall->call_state = CLSTA_INQUEUE;
- update_call_rec (pcall);
- break;
- }
- return 1;
- }
- /**********
- * Process PRACK Message
- *
- * INPUT:
- * Arg (1) = SIP message pointer
- * Arg (2) = call pointer
- * OUTPUT: 0=failed
- **********/
- int prack_msg (sip_msg_t *pmsg, call_lst *pcall)
- {
- /**********
- * waiting on PRACK?
- **********/
- char *pfncname = "prack_msg: ";
- tm_api_t *ptm = pmod_data->ptm;
- if (pcall->call_state != CLSTA_PRACKSTRT)
- {
- LM_ERR ("%sUnexpected PRACK (%s)!", pfncname, pcall->call_from);
- if (pmod_data->psl->freply (pmsg, 481, presp_nocall) < 0)
- { LM_ERR ("%sUnable to create reply!", pfncname); }
- return 1;
- }
- /**********
- * o check RAck ??? need to check
- * o accept PRACK
- **********/
- if (ptm->t_newtran (pmsg) < 0)
- {
- LM_ERR ("%sUnable to create new transaction for call (%s)!",
- pfncname, pcall->call_from);
- if (pmod_data->psl->freply (pmsg, 500, presp_srverr) < 0)
- { LM_ERR ("%sUnable to create reply!", pfncname); }
- return 1;
- }
- if (ptm->t_reply (pmsg, 200, presp_ok->s) < 0)
- {
- LM_ERR ("%sUnable to reply to PRACK for call (%s)!",
- pfncname, pcall->call_from);
- return 1;
- }
- pcall->call_state = CLSTA_PRACKRPLY;
- return 1;
- }
- /**********
- * Refer Call
- *
- * INPUT:
- * Arg (1) = call pointer
- * Arg (2) = lock pointer
- * OUTPUT: 0 if failed
- **********/
- int refer_call (call_lst *pcall, mohq_lock *plock)
- {
- /**********
- * create dialog
- **********/
- char *pfncname = "refer_call: ";
- int nret = 0;
- struct to_body ptob [2];
- dlg_t *pdlg = form_dialog (pcall, ptob);
- if (!pdlg)
- {
- mohq_lock_release (plock);
- return 0;
- }
- pdlg->state = DLG_CONFIRMED;
- /**********
- * form REFER message
- * o calculate basic size
- * o create buffer
- **********/
- str puri [1];
- puri->s = pcall->call_referto;
- puri->len = strlen (puri->s);
- int npos1 = sizeof (prefermsg) // REFER template
- + strlen (pcall->call_via) // Via
- + puri->len // Refer-To
- + ptob->uri.len; // Referred-By
- char *pbuf = pkg_malloc (npos1);
- if (!pbuf)
- {
- LM_ERR ("%sNo more memory!", pfncname);
- goto refererr;
- }
- sprintf (pbuf, prefermsg,
- pcall->call_via, // Via
- puri->s, // Refer-To
- STR_FMT (&ptob->uri)); // Referred-By
- /**********
- * send REFER request
- **********/
- tm_api_t *ptm = pmod_data->ptm;
- uac_req_t puac [1];
- str phdrs [1];
- phdrs->s = pbuf;
- phdrs->len = strlen (pbuf);
- set_uac_req (puac, prefer, phdrs, 0, pdlg,
- TMCB_LOCAL_COMPLETED | TMCB_ON_FAILURE, refer_cb, pcall);
- pcall->call_state = CLSTA_REFER;
- update_call_rec (pcall);
- mohq_lock_release (plock);
- if (ptm->t_request_within (puac) < 0)
- {
- pcall->call_state = CLSTA_INQUEUE;
- LM_ERR ("%sUnable to create REFER request for call (%s)!",
- pfncname, pcall->call_from);
- update_call_rec (pcall);
- goto refererr;
- }
- mohq_debug (pcall->pmohq, "%sSent REFER request for call (%s) to %s",
- pfncname, pcall->call_from, pcall->call_referto);
- nret = -1;
- refererr:
- if (pdlg)
- { pkg_free (pdlg); }
- pkg_free (pbuf);
- return nret;
- }
- /**********
- * REFER Callback
- *
- * INPUT:
- * Arg (1) = cell pointer
- * Arg (2) = callback type
- * Arg (3) = callback parms
- * OUTPUT: none
- **********/
- static void refer_cb
- (struct cell *ptrans, int ntype, struct tmcb_params *pcbp)
- {
- char *pfncname = "refer_cb: ";
- call_lst *pcall = (call_lst *)*pcbp->param;
- if ((ntype == TMCB_ON_FAILURE) || (pcbp->req == FAKED_REPLY))
- {
- LM_ERR ("%sCall (%s) did not respond to REFER", pfncname,
- pcall->call_from);
- drop_call (pcbp->req, pcall);
- return;
- }
- int nreply = pcbp->code;
- if ((nreply / 100) == 2)
- {
- pcall->call_state = CLSTA_RFRWAIT;
- mohq_debug (pcall->pmohq, "%sCall (%s) REFER reply=%d",
- pfncname, pcall->call_from, nreply);
- }
- else
- {
- LM_ERR ("%sCall (%s) REFER error (%d)", pfncname,
- pcall->call_from, nreply);
- if (nreply == 481)
- { delete_call (pcall); }
- else
- {
- pcall->call_state = CLSTA_INQUEUE;
- update_call_rec (pcall);
- }
- }
- return;
- }
- /**********
- * Process re-INVITE Message
- *
- * INPUT:
- * Arg (1) = SIP message pointer
- * Arg (2) = call pointer
- * OUTPUT: 0=failed
- **********/
- int reinvite_msg (sip_msg_t *pmsg, call_lst *pcall)
- {
- /**********
- * RFC 3261 section 14.2
- * o dialog pending?
- * o get SDP
- **********/
- char *pfncname = "reinvite_msg: ";
- if ((pcall->call_state / 100) < 2)
- {
- mohq_debug (pcall->pmohq, "%sINVITE still pending for call (%s)",
- pfncname, pcall->call_from);
- if (pmod_data->psl->freply (pmsg, 491, presp_reqpend) < 0)
- { LM_ERR ("%sUnable to create reply!", pfncname); }
- return 1;
- }
- if (!(pmsg->msg_flags & FL_SDP_BODY))
- {
- if (parse_sdp (pmsg))
- {
- LM_ERR ("%sre-INVITE lacks SDP (%s)!", pfncname, pcall->call_from);
- if (pmod_data->psl->freply (pmsg, 488, presp_noaccept) < 0)
- { LM_ERR ("%sUnable to create reply!", pfncname); }
- return 1;
- }
- }
- /**********
- * o find available MOH files
- * o look for hold condition and matching payload type
- **********/
- rtpmap **pmohfiles = find_MOH (pcall->pmohq->mohq_mohdir,
- pcall->pmohq->mohq_mohfile);
- int bhold = 0;
- int bmatch = 0;
- int nsession;
- sdp_session_cell_t *psession;
- for (nsession = 0; (psession = get_sdp_session (pmsg, nsession)); nsession++)
- {
- int nstream;
- sdp_stream_cell_t *pstream;
- for (nstream = 0; (pstream = get_sdp_stream (pmsg, nsession, nstream));
- nstream++)
- {
- /**********
- * o RTP?
- * o audio?
- * o hold?
- * o at least one payload matches?
- **********/
- if (!pstream->is_rtp)
- { continue; }
- if (!STR_EQ (*paudio, pstream->media))
- { continue; }
- if (pstream->is_on_hold)
- {
- bhold = 1;
- break;
- }
- if (bmatch)
- { continue; }
- /**********
- * check payload types for a match
- **********/
- sdp_payload_attr_t *ppayload;
- for (ppayload = pstream->payload_attr; ppayload; ppayload = ppayload->next)
- {
- int ntype = atoi (ppayload->rtp_payload.s);
- int nidx;
- for (nidx = 0; pmohfiles [nidx]; nidx++)
- {
- if (pmohfiles [nidx]->ntype == ntype)
- {
- bmatch = 1;
- break;
- }
- }
- }
- }
- }
- /**********
- * if no hold, allow re-INVITE if matching file
- **********/
- if (!bhold)
- {
- if (!bmatch)
- {
- LM_ERR ("%sre-INVITE refused because no matching payload for call (%s)!",
- pfncname, pcall->call_from);
- if (pmod_data->psl->freply (pmsg, 488, presp_noaccept) < 0)
- {
- LM_ERR ("%sUnable to create reply!", pfncname);
- return 1;
- }
- }
- else
- {
- mohq_debug (pcall->pmohq, "%sAccepted re-INVITE for call (%s)",
- pfncname, pcall->call_from);
- if (pmod_data->psl->freply (pmsg, 200, presp_ok) < 0)
- {
- LM_ERR ("%sUnable to create reply!", pfncname);
- return 1;
- }
- }
- return 1;
- }
- /**********
- * hold not allowed, say good-bye
- **********/
- LM_ERR ("%sTerminating call (%s) because hold not allowed!",
- pfncname, pcall->call_from);
- if (pmod_data->psl->freply (pmsg, 200, presp_ok) < 0)
- {
- LM_ERR ("%sUnable to create reply!", pfncname);
- return 1;
- }
- close_call (pmsg, pcall);
- return 1;
- }
- /**********
- * Search Header for Extension
- *
- * INPUT:
- * Arg (1) = header field pointer
- * Arg (2) = extension str pointer
- * OUTPUT: 0=not found
- **********/
- int search_hdr_ext (struct hdr_field *phdr, str *pext)
- {
- if (!phdr)
- { return 0; }
- str *pstr = &phdr->body;
- int npos1, npos2;
- for (npos1 = 0; npos1 < pstr->len; npos1++)
- {
- /**********
- * o find non-space
- * o search to end, space or comma
- * o same size?
- * o same name?
- **********/
- if (pstr->s [npos1] == ' ')
- { continue; }
- for (npos2 = npos1++; npos1 < pstr->len; npos1++)
- {
- if (pstr->s [npos1] == ' ' || pstr->s [npos1] == ',')
- { break; }
- }
- if (npos1 - npos2 != pext->len)
- { continue; }
- if (!strncasecmp (&pstr->s [npos2], pext->s, pext->len))
- { return 1; }
- }
- return 0;
- }
- /**********
- * Send Provisional Response
- *
- * INPUT:
- * Arg (1) = SIP message pointer
- * Arg (2) = call pointer
- * OUTPUT: 0=unable to process; 1=processed
- **********/
- int send_prov_rsp (sip_msg_t *pmsg, call_lst *pcall)
- {
- /**********
- * o send ringing response with require
- * o update record
- **********/
- char *pfncname = "send_prov_rsp: ";
- tm_api_t *ptm = pmod_data->ptm;
- pcall->call_cseq = rand ();
- char phdrtmp [200];
- char *phdrtmplt =
- "Accept-Language: en" SIPEOL
- "Require: 100rel" SIPEOL
- "RSeq: %d" SIPEOL
- "User-Agent: " USRAGNT SIPEOL
- ;
- sprintf (phdrtmp, phdrtmplt, pcall->call_cseq);
- struct lump_rpl **phdrlump = add_lump_rpl2 (pmsg, phdrtmp,
- strlen (phdrtmp), LUMP_RPL_HDR);
- if (!phdrlump)
- {
- LM_ERR ("%sUnable to create new header for call (%s)!",
- pfncname, pcall->call_from);
- if (pmod_data->psl->freply (pmsg, 500, presp_srverr) < 0)
- { LM_ERR ("%sUnable to create reply!", pfncname); }
- return 0;
- }
- if (ptm->t_reply (pmsg, 180, presp_ring->s) < 0)
- {
- LM_ERR ("%sUnable to reply to INVITE for call (%s)",
- pfncname, pcall->call_from);
- return 0;
- }
- pcall->call_state = CLSTA_PRACKSTRT;
- mohq_debug (pcall->pmohq, "%sSent PRACK RINGING for call (%s)",
- pfncname, pcall->call_from);
- /**********
- * o wait until PRACK (64*T1 RFC 3261 section 7.1.1)
- * o remove header lump
- **********/
- time_t nstart = time (0) + 32;
- while (1)
- {
- usleep (USLEEP_LEN);
- if (pcall->call_state != CLSTA_PRACKSTRT)
- { break; }
- if (nstart < time (0))
- {
- LM_ERR ("%sNo PRACK response for call (%s)",
- pfncname, pcall->call_from);
- break;
- }
- }
- unlink_lump_rpl (pmsg, *phdrlump);
- if (pcall->call_state != CLSTA_PRACKRPLY)
- { return 0; }
- return 1;
- }
- /**********
- * Send RTPProxy Answer
- *
- * INPUT:
- * Arg (1) = SIP message pointer
- * Arg (2) = call pointer
- * OUTPUT: 0=unable to process; 1=processed
- **********/
- int send_rtp_answer (sip_msg_t *pmsg, call_lst *pcall)
- {
- /**********
- * build response from request
- **********/
- char *pfncname = "send_rtp_answer: ";
- int nret = 0;
- tm_api_t *ptm = pmod_data->ptm;
- struct cell *ptrans = ptm->t_gett ();
- str ptotag [1];
- ptotag->s = pcall->call_tag;
- ptotag->len = strlen (pcall->call_tag);
- str pbuf [1];
- struct bookmark pBM [1];
- pbuf->s = build_res_buf_from_sip_req (200, presp_ok, ptotag, ptrans->uas.request,
- (unsigned int *)&pbuf->len, pBM);
- if (!pbuf->s || !pbuf->len)
- {
- LM_ERR ("%sUnable to create SDP response for call (%s)!",
- pfncname, pcall->call_from);
- return 0;
- }
- /**********
- * parse out first line and headers
- **********/
- char *pclenhdr = CLENHDR;
- str pparse [20];
- int npos1, npos2;
- int nhdrcnt = 0;
- for (npos1 = 0; npos1 < pbuf->len; npos1++)
- {
- /**********
- * find EOL
- **********/
- for (npos2 = npos1++; npos1 < pbuf->len; npos1++)
- {
- /**********
- * o not EOL? (CRLF assumed)
- * o next line a continuation? (RFC 3261 section 7.3.1)
- **********/
- if (pbuf->s [npos1] != '\n')
- { continue; }
- if (npos1 + 1 == pbuf->len)
- { break; }
- if (pbuf->s [npos1 + 1] == ' '
- || pbuf->s [npos1 + 1] == '\t')
- { continue; }
- break;
- }
- /**********
- * o blank is end of header (RFC 3261 section 7)
- * o ignore Content-Length (assume followed by colon)
- * o save header
- **********/
- if (npos1 - npos2 == 1)
- { break; }
- if (npos1 - npos2 > 14)
- {
- if (!strncasecmp (&pbuf->s [npos2], pclenhdr, 14))
- { continue; }
- }
- pparse [nhdrcnt].s = &pbuf->s [npos2];
- pparse [nhdrcnt++].len = npos1 - npos2 + 1;
- }
- /**********
- * recreate buffer with extra headers and SDP
- * o form SDP
- * o count hdrs, extra hdrs, content-length hdr, SDP
- * o alloc new buffer
- * o form new buffer
- * o replace orig buffer
- **********/
- str pSDP [1] = {STR_NULL};
- if (!form_rtp_SDP (pSDP, pcall, prtpsdp))
- { goto answer_done; }
- for (npos1 = npos2 = 0; npos2 < nhdrcnt; npos2++)
- { npos1 += pparse [npos2].len; }
- char pbodylen [30];
- sprintf (pbodylen, "%s: %d\r\n\r\n", pclenhdr, pSDP->len);
- npos1 += pextrahdr->len + strlen (pbodylen) + pSDP->len + 1;
- char *pnewbuf = pkg_malloc (npos1);
- if (!pnewbuf)
- {
- LM_ERR ("%sNo more memory!", pfncname);
- goto answer_done;
- }
- for (npos1 = npos2 = 0; npos2 < nhdrcnt; npos2++)
- {
- memcpy (&pnewbuf [npos1], pparse [npos2].s, pparse [npos2].len);
- npos1 += pparse [npos2].len;
- }
- npos2 = pextrahdr->len;
- memcpy (&pnewbuf [npos1], pextrahdr->s, npos2);
- npos1 += npos2;
- npos2 = strlen (pbodylen);
- memcpy (&pnewbuf [npos1], pbodylen, npos2);
- npos1 += npos2;
- npos2 = pSDP->len;
- memcpy (&pnewbuf [npos1], pSDP->s, npos2);
- npos1 += npos2;
- pkg_free (pbuf->s);
- pbuf->s = pnewbuf;
- pbuf->len = npos1;
- /**********
- * build SIP msg
- **********/
- struct sip_msg pnmsg [1];
- build_sip_msg_from_buf (pnmsg, pbuf->s, pbuf->len, 0);
- memcpy (&pnmsg->rcv, &pmsg->rcv, sizeof (struct receive_info));
- /**********
- * o send rtpproxy answer
- * o form stream file
- * o send stream
- **********/
- mohq_debug (pcall->pmohq, "%sAnswering RTP link for call (%s)",
- pfncname, pcall->call_from);
- if (pmod_data->fn_rtp_answer (pnmsg, 0, 0) != 1)
- {
- LM_ERR ("%srtpproxy_answer refused for call (%s)!",
- pfncname, pcall->call_from);
- goto answer_done;
- }
- if (!start_stream (pnmsg, pcall, 0))
- { goto answer_done; }
- /**********
- * o create buffer from response
- * o find SDP
- **********/
- pbuf->s = build_res_buf_from_sip_res (pnmsg, (unsigned int *)&pbuf->len);
- pkg_free (pnewbuf);
- free_sip_msg (pnmsg);
- if (!pbuf->s || !pbuf->len)
- {
- LM_ERR ("%sUnable to create SDP response for call (%s)!",
- pfncname, pcall->call_from);
- goto answer_done;
- }
- str pnewSDP [1];
- for (npos1 = 0; npos1 < pbuf->len; npos1++)
- {
- if (pbuf->s [npos1] != '\n')
- { continue; }
- if (pbuf->s [npos1 - 3] == '\r')
- { break; }
- }
- pnewSDP->s = &pbuf->s [npos1 + 1];
- pnewSDP->len = pbuf->len - npos1 - 1;
- /**********
- * o save media port number
- * o send adjusted reply
- **********/
- char *pfnd = strstr (pnewSDP->s, "m=audio ");
- if (!pfnd)
- {
- // should not happen
- LM_ERR ("%sUnable to find audio port for call (%s)!",
- pfncname, pcall->call_from);
- goto answer_done;
- }
- pcall->call_aport = strtol (pfnd + 8, NULL, 10);
- if (!add_lump_rpl2 (pmsg, pextrahdr->s, pextrahdr->len, LUMP_RPL_HDR))
- {
- LM_ERR ("%sUnable to add header for call (%s)!",
- pfncname, pcall->call_from);
- goto answer_done;
- }
- if (!add_lump_rpl2 (pmsg, pnewSDP->s, pnewSDP->len, LUMP_RPL_BODY))
- {
- LM_ERR ("%sUnable to add SDP body for call (%s)!",
- pfncname, pcall->call_from);
- goto answer_done;
- }
- if (ptm->t_reply (pmsg, 200, presp_ok->s) < 0)
- {
- LM_ERR ("%sUnable to reply to INVITE for call (%s)!",
- pfncname, pcall->call_from);
- goto answer_done;
- }
- pcall->call_state = CLSTA_INVITED;
- mohq_debug (pcall->pmohq, "%sResponded to INVITE with RTP for call (%s)",
- pfncname, pcall->call_from);
- nret = 1;
- /**********
- * free buffer and return
- **********/
- answer_done:
- if (pSDP->s)
- { pkg_free (pSDP->s); }
- pkg_free (pbuf->s);
- return nret;
- }
- /**********
- * Start Streaming
- *
- * INPUT:
- * Arg (1) = SIP message pointer
- * Arg (2) = call pointer
- * Arg (3) = server flag
- * OUTPUT: 0 if failed
- **********/
- int start_stream (sip_msg_t *pmsg, call_lst *pcall, int bserver)
- {
- char *pfncname = "start_stream: ";
- char pfile [MOHDIRLEN + MOHFILELEN + 2];
- strcpy (pfile, pcall->pmohq->mohq_mohdir);
- int npos = strlen (pfile);
- pfile [npos++] = '/';
- strcpy (&pfile [npos], pcall->pmohq->mohq_mohfile);
- npos += strlen (&pfile [npos]);
- str pMOH [1] = {{pfile, npos}};
- pv_elem_t *pmodel;
- pv_parse_format (pMOH, &pmodel);
- cmd_function fn_stream = bserver ? pmod_data->fn_rtp_stream_s
- : pmod_data->fn_rtp_stream_c;
- mohq_debug (pcall->pmohq, "%sStarting RTP link for call (%s)",
- pfncname, pcall->call_from);
- if (fn_stream (pmsg, (char *)pmodel, (char *)-1) != 1)
- {
- LM_ERR ("%srtpproxy_stream refused for call (%s)!",
- pfncname, pcall->call_from);
- return 0;
- }
- return 1;
- }
- /**********
- * Form Char Array from STR
- *
- * INPUT:
- * Arg (1) = str pointer
- * OUTPUT: char pointer; NULL if unable to allocate
- **********/
- char *form_tmpstr (str *pstr)
- {
- char *pcstr = malloc (pstr->len + 1);
- if (!pcstr)
- {
- LM_ERR ("No more memory!");
- return NULL;
- }
- memcpy (pcstr, pstr->s, pstr->len);
- pcstr [pstr->len] = 0;
- return pcstr;
- }
- /**********
- * Release Char Array
- *
- * INPUT:
- * Arg (1) = char pointer
- * OUTPUT: none
- **********/
- void free_tmpstr (char *pcstr)
- {
- if (pcstr)
- { free (pcstr); }
- return;
- }
- /**********
- * external functions
- **********/
- /**********
- * Find MOH Files
- *
- * INPUT:
- * Arg (1) = mohdir pointer
- * Arg (2) = mohfile pointer
- * OUTPUT: array of pointers for matching files; last element=0
- **********/
- rtpmap **find_MOH (char *pmohdir, char *pmohfile)
- {
- /**********
- * form base file name
- **********/
- char pfile [MOHDIRLEN + MOHFILELEN + 6];
- strcpy (pfile, pmohdir);
- int nflen = strlen (pfile);
- pfile [nflen++] = '/';
- strcpy (&pfile [nflen], pmohfile);
- nflen += strlen (&pfile [nflen]);
- pfile [nflen++] = '.';
- /**********
- * find available files based on RTP payload type
- **********/
- int nidx;
- int nfound = 0;
- for (nidx = 0; prtpmap [nidx].pencode; nidx++)
- {
- /**********
- * o form file name based on payload type
- * o exists?
- **********/
- sprintf (&pfile [nflen], "%d", prtpmap [nidx].ntype);
- struct stat psb [1];
- if (lstat (pfile, psb))
- { continue; }
- pmohfiles [nfound++] = &prtpmap [nidx];
- }
- pmohfiles [nfound] = 0;
- return pmohfiles;
- }
- /**********
- * MI Debug
- *
- * PARAMETERS:
- * queue name = queue to use
- * state = 0=off, <>0=on
- *
- * INPUT:
- * Arg (1) = command tree pointer
- * Arg (2) = parms pointer
- * OUTPUT: root pointer
- **********/
- struct mi_root *mi_debug (struct mi_root *pcmd_tree, void *parms)
- {
- /**********
- * o parm count correct?
- * o find queue
- * o lock queue
- **********/
- struct mi_node *pnode = pcmd_tree->node.kids;
- if (!pnode || !pnode->next || pnode->next->next)
- { return init_mi_tree (400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); }
- int nq_idx = find_queue (&pnode->value);
- if (nq_idx == -1)
- { return init_mi_tree (400, pmi_noqueue->s, pmi_noqueue->len); }
- char pint [20];
- int nsize = (pnode->next->value.len >= sizeof (pint))
- ? sizeof (pint) - 1 : pnode->next->value.len;
- strncpy (pint, pnode->next->value.s, nsize);
- pint [nsize] = '\0';
- int bdebug = atoi (pint) ? 1 : 0;
- if (!mohq_lock_set (pmod_data->pmohq_lock, 0, 5000))
- { return init_mi_tree (400, pmi_nolock->s, pmi_nolock->len); }
- /**********
- * o set flag
- * o update queue table
- * o release lock
- **********/
- mohq_lst *pqueue = &pmod_data->pmohq_lst [nq_idx];
- if (bdebug)
- { pqueue->mohq_flags |= MOHQF_DBG; }
- else
- { pqueue->mohq_flags &= ~MOHQF_DBG; }
- update_debug (pqueue, bdebug);
- mohq_lock_release (pmod_data->pmohq_lock);
- return init_mi_tree (200, MI_OK_S, MI_OK_LEN);
- }
- /**********
- * MI Drop Call
- *
- * PARAMETERS:
- * queue name = queue to use
- * callID = *=all, otherwise callID
- *
- * INPUT:
- * Arg (1) = command tree pointer
- * Arg (2) = parms pointer
- * OUTPUT: root pointer
- **********/
- struct mi_root *mi_drop_call (struct mi_root *pcmd_tree, void *parms)
- {
- /**********
- * o parm count correct?
- * o find queue
- * o lock calls
- **********/
- struct mi_node *pnode = pcmd_tree->node.kids;
- if (!pnode || !pnode->next || pnode->next->next)
- { return init_mi_tree (400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); }
- int nq_idx = find_queue (&pnode->value);
- if (nq_idx == -1)
- { return init_mi_tree (400, pmi_noqueue->s, pmi_noqueue->len); }
- if (!mohq_lock_set (pmod_data->pcall_lock, 0, 5000))
- { return init_mi_tree (400, pmi_nolock->s, pmi_nolock->len); }
- /**********
- * o find matching calls
- * o release lock
- **********/
- mohq_lst *pqueue = &pmod_data->pmohq_lst [nq_idx];
- int nidx;
- str *pcallid = &pnode->next->value;
- for (nidx = 0; nidx < pmod_data->call_cnt; nidx++)
- {
- /**********
- * o call active?
- * o callID matches?
- * o close call
- **********/
- call_lst *pcall = &pmod_data->pcall_lst [nidx];
- if (!pcall->call_active)
- { continue; }
- if (pqueue->mohq_id != pcall->pmohq->mohq_id)
- { continue; }
- str tmpstr [1];
- if (!STR_EQ (*pcallid, *pallq))
- {
- tmpstr->s = pcall->call_id;
- tmpstr->len = strlen (tmpstr->s);
- if (!STR_EQ (*tmpstr, *pcallid))
- { continue; }
- }
- close_call (FAKED_REPLY, pcall);
- }
- mohq_lock_release (pmod_data->pcall_lock);
- return init_mi_tree (200, MI_OK_S, MI_OK_LEN);
- }
- /**********
- * Count Messages
- *
- * INPUT:
- * Arg (1) = SIP message pointer
- * Arg (2) = queue name
- * Arg (3) = pv result name
- * OUTPUT: -1 if no items in queue; else result = count
- **********/
- int mohq_count (sip_msg_t *pmsg, char *pqueue, pv_spec_t *presult)
- {
- /**********
- * get queue and pv names
- **********/
- char *pfncname = "mohq_count: ";
- str pqname [1];
- if (!pqueue || !presult)
- {
- LM_ERR ("%sParameters missing!", pfncname);
- return -1;
- }
- if (fixup_get_svalue (pmsg, (gparam_p)pqueue, pqname))
- {
- LM_ERR ("%sInvalid queue name!", pfncname);
- return -1;
- }
- /**********
- * o find queue
- * o lock calls
- * o count items in queue
- **********/
- int nq_idx = find_queue (pqname);
- int ncount = 0;
- call_lst *pcalls = pmod_data->pcall_lst;
- int ncall_idx, mohq_id;
- if (!mohq_lock_set (pmod_data->pcall_lock, 0, 200))
- { LM_ERR ("%sUnable to lock calls!", pfncname); }
- else
- {
- if (nq_idx != -1)
- {
- mohq_id = pmod_data->pmohq_lst [nq_idx].mohq_id;
- for (ncall_idx = 0; ncall_idx < pmod_data->call_cnt; ncall_idx++)
- {
- if (!pcalls [ncall_idx].call_active)
- { continue; }
- if (pcalls [ncall_idx].pmohq->mohq_id == mohq_id
- && pcalls [ncall_idx].call_state == CLSTA_INQUEUE)
- { ncount++; }
- }
- }
- mohq_lock_release (pmod_data->pcall_lock);
- }
- /**********
- * o set pv result
- * o exit with result
- **********/
- pv_value_t pavp_val [1];
- memset (pavp_val, 0, sizeof (pv_value_t));
- pavp_val->ri = ncount;
- pavp_val->flags = PV_TYPE_INT | PV_VAL_INT;
- if (presult->setf (pmsg, &presult->pvp, (int)EQ_T, pavp_val) < 0)
- {
- LM_ERR ("%sUnable to set pv value for mohq_count ()!", pfncname);
- return -1;
- }
- return 1;
- }
- /**********
- * Log Debug Statement
- *
- * INPUT:
- * Arg (1) = MOH queue pointer
- * Arg (2) = format pointer
- * Arg (...) = optional format values
- * OUTPUT: outputs debugging values
- **********/
- void mohq_debug (mohq_lst *pmohq, char *pfmt, ...)
- {
- /**********
- * o get system and MOHQ log level
- * o exit if no debug printing
- * o force local debug
- * o form message and log
- * o reset log level
- **********/
- int nsys_log = get_debug_level (LOG_MNAME, LOG_MNAME_LEN);
- int nmohq_log = (pmohq->mohq_flags & MOHQF_DBG) ? L_DBG : L_INFO;
- if (nmohq_log < L_DBG && nsys_log < L_DBG)
- { return; }
- if (nsys_log < nmohq_log)
- { set_local_debug_level (nmohq_log); }
- char ptext [1024];
- va_list ap;
- va_start (ap, pfmt);
- vsnprintf (ptext, sizeof (ptext), pfmt, ap);
- va_end (ap);
- LM_DBG ("%s", ptext);
- if (nsys_log < nmohq_log)
- { reset_local_debug_level (); }
- return;
- }
- /**********
- * Process Message
- *
- * INPUT:
- * Arg (1) = SIP message pointer
- * OUTPUT: -1=not directed to queue; 1=successfully processed
- **********/
- int mohq_process (sip_msg_t *pmsg)
- {
- /**********
- * o parse headers
- * o lock MOH queue
- * o directed to message queue?
- * o connect to database
- **********/
- char *pfncname = "mohq_process: ";
- if (parse_headers (pmsg, HDR_EOH_F, 0) < 0)
- {
- LM_ERR ("%sUnable to parse header!", pfncname);
- return -1;
- }
- if (!mohq_lock_set (pmod_data->pmohq_lock, 0, 2000))
- {
- LM_ERR ("%sUnable to lock calls!", pfncname);
- return -1;
- }
- call_lst *pcall;
- int mohq_idx = find_call (pmsg, &pcall);
- db1_con_t *pconn = mohq_dbconnect ();
- if (pconn)
- {
- /**********
- * o last update older than 1 minute?
- * o exclusively lock MOH queue
- * o update queue
- **********/
- if (pmod_data->mohq_update + 60 < time (0))
- {
- if (mohq_lock_change (pmod_data->pmohq_lock, 1))
- {
- update_mohq_lst (pconn);
- mohq_lock_change (pmod_data->pmohq_lock, 0);
- pmod_data->mohq_update = time (0);
- }
- }
- mohq_dbdisconnect (pconn);
- }
- if (mohq_idx < 0)
- {
- mohq_lock_release (pmod_data->pmohq_lock);
- return -1;
- }
- /**********
- * o process message
- * o release MOH queue
- **********/
- mohq_debug (&pmod_data->pmohq_lst [mohq_idx],
- "%sProcessing %.*s, queue (%s)", pfncname,
- STR_FMT (&REQ_LINE (pmsg).method),
- pmod_data->pmohq_lst [mohq_idx].mohq_name);
- int ret;
- switch (pmsg->REQ_METHOD)
- {
- case METHOD_INVITE:
- /**********
- * initial INVITE?
- **********/
- if (!pcall)
- { ret = first_invite_msg (pmsg, mohq_idx); }
- else
- { ret = reinvite_msg (pmsg, pcall); }
- break;
- case METHOD_NOTIFY:
- ret = notify_msg (pmsg, pcall);
- break;
- case METHOD_PRACK:
- ret = prack_msg (pmsg, pcall);
- break;
- case METHOD_ACK:
- ret = ack_msg (pmsg, pcall);
- break;
- case METHOD_BYE:
- ret = bye_msg (pmsg, pcall);
- break;
- case METHOD_CANCEL:
- ret = cancel_msg (pmsg, pcall);
- break;
- default:
- deny_method (pmsg, pcall);
- ret = 1;
- break;
- }
- mohq_lock_release (pmod_data->pmohq_lock);
- return ret ? 1 : -1;
- }
- /**********
- * Retrieve Oldest Queued Call
- *
- * INPUT:
- * Arg (1) = SIP message pointer
- * Arg (2) = queue name
- * Arg (3) = redirect URI
- * OUTPUT: -1 if no items in queue or error; 1 redirects oldest call
- **********/
- int mohq_retrieve (sip_msg_t *pmsg, char *pqueue, char *pURI)
- {
- /**********
- * o get queue name and URI
- * o check URI
- **********/
- char *pfncname = "mohq_retrieve: ";
- str puri [1], pqname [1];
- if (!pqueue || !pURI)
- {
- LM_ERR ("%sParameters missing!", pfncname);
- return -1;
- }
- if (fixup_get_svalue (pmsg, (gparam_p)pqueue, pqname))
- {
- LM_ERR ("%sInvalid queue name!", pfncname);
- return -1;
- }
- if (fixup_get_svalue (pmsg, (gparam_p)pURI, puri))
- {
- LM_ERR ("%sInvalid URI!", pfncname);
- return -1;
- }
- if (puri->len > URI_LEN)
- {
- LM_ERR ("%sURI too long!", pfncname);
- return -1;
- }
- struct sip_uri puri_parsed [1];
- if (parse_uri (puri->s, puri->len, puri_parsed))
- {
- LM_ERR ("%sInvalid URI (%.*s)!", pfncname, STR_FMT (puri));
- return -1;
- }
- /**********
- * o find queue
- * o lock calls
- * o find oldest call
- **********/
- int nq_idx = find_queue (pqname);
- if (nq_idx == -1)
- { return -1; }
- if (!mohq_lock_set (pmod_data->pcall_lock, 0, 200))
- {
- LM_ERR ("%sUnable to lock calls!", pfncname);
- return -1;
- }
- call_lst *pcall = 0;
- int ncall_idx;
- time_t ntime = 0;
- int nfound = -1;
- int mohq_id = pmod_data->pmohq_lst [nq_idx].mohq_id;
- for (ncall_idx = 0; ncall_idx < pmod_data->call_cnt; ncall_idx++)
- {
- /**********
- * o active call?
- * o matching queue?
- * o in queue?
- * o check age
- **********/
- pcall = &pmod_data->pcall_lst [ncall_idx];
- if (!pcall->call_active)
- { continue; }
- if (pcall->pmohq->mohq_id != mohq_id)
- { continue; }
- if (pcall->call_state != CLSTA_INQUEUE)
- { continue; }
- if (!ntime)
- {
- nfound = ncall_idx;
- ntime = pcall->call_time;
- }
- else
- {
- if (pcall->call_time < ntime)
- {
- nfound = ncall_idx;
- ntime = pcall->call_time;
- }
- }
- }
- if (nfound == -1)
- {
- LM_WARN ("%sNo calls in queue (%.*s)", pfncname, STR_FMT (pqname));
- mohq_lock_release (pmod_data->pcall_lock);
- return -1;
- }
- pcall = &pmod_data->pcall_lst [nfound];
- /**********
- * o save refer-to URI
- * o send refer
- **********/
- strncpy (pcall->call_referto, puri->s, puri->len);
- pcall->call_referto [puri->len] = '\0';
- if (refer_call (pcall, pmod_data->pcall_lock))
- { return 1; }
- LM_ERR ("%sUnable to refer call (%s)!", pfncname, pcall->call_from);
- return -1;
- }
- /**********
- * Send Message to Queue
- *
- * INPUT:
- * Arg (1) = SIP message pointer
- * Arg (2) = queue name
- * OUTPUT: -1 if no items in queue; 1 if successfull
- **********/
- int mohq_send (sip_msg_t *pmsg, char *pqueue)
- {
- /**********
- * o first INVITE?
- * o get queue name
- **********/
- char *pfncname = "mohq_send: ";
- if (pmsg->REQ_METHOD != METHOD_INVITE)
- {
- LM_ERR ("%sNot an INVITE message!", pfncname);
- return -1;
- }
- to_body_t *pto_body = get_to (pmsg);
- if (pto_body->tag_value.len)
- {
- LM_ERR ("%sNot a first INVITE message!", pfncname);
- return -1;
- }
- str pqname [1];
- if (!pqueue)
- {
- LM_ERR ("%sParameters missing!", pfncname);
- return -1;
- }
- if (fixup_get_svalue (pmsg, (gparam_p)pqueue, pqname))
- {
- LM_ERR ("%sInvalid queue name!", pfncname);
- return -1;
- }
- /**********
- * o find queue
- * o change RURI
- * o relay message
- **********/
- int nq_idx = find_queue (pqname);
- if (nq_idx == -1)
- { return -1; }
- str pruri [1] = {{0, strlen (pmod_data->pmohq_lst [nq_idx].mohq_uri)}};
- pruri->s = pkg_malloc (pruri->len + 1);
- if (!pruri->s)
- {
- LM_ERR ("%sNo more memory!", pfncname);
- return -1;
- }
- strcpy (pruri->s, pmod_data->pmohq_lst [nq_idx].mohq_uri);
- if (pmsg->new_uri.s)
- { pkg_free (pmsg->new_uri.s); }
- pmsg->new_uri.s = pruri->s;
- pmsg->new_uri.len = pruri->len;
- pmsg->parsed_uri_ok = 0;
- pmsg->parsed_orig_ruri_ok = 0;
- if (pmod_data->ptm->t_relay (pmsg, 0, 0) < 0)
- {
- LM_ERR ("%sUnable to relay INVITE!", pfncname);
- return -1;
- }
- return 1;
- }
|