12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516 |
- /*
- * Asterisk -- A telephony toolkit for Linux.
- *
- * Implementation of Inter-Asterisk eXchange
- *
- * Copyright (C) 1999, Mark Spencer
- *
- * Mark Spencer <markster@linux-support.net>
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License
- */
- #include <asterisk/lock.h>
- #include <asterisk/frame.h>
- #include <asterisk/channel.h>
- #include <asterisk/channel_pvt.h>
- #include <asterisk/logger.h>
- #include <asterisk/module.h>
- #include <asterisk/pbx.h>
- #include <asterisk/sched.h>
- #include <asterisk/io.h>
- #include <asterisk/config.h>
- #include <asterisk/options.h>
- #include <asterisk/cli.h>
- #include <asterisk/translate.h>
- #include <asterisk/md5.h>
- #include <asterisk/cdr.h>
- #include <asterisk/crypto.h>
- #include <asterisk/acl.h>
- #include <asterisk/manager.h>
- #include <asterisk/utils.h>
- #include <arpa/inet.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netinet/in_systm.h>
- #include <netinet/ip.h>
- #include <sys/time.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <errno.h>
- #include <unistd.h>
- #include <netdb.h>
- #include <fcntl.h>
- #include <signal.h>
- #include <sys/signal.h>
- #ifdef MYSQL_FRIENDS
- #include <mysql/mysql.h>
- #endif
- #include "iax.h"
- #ifndef IPTOS_MINCOST
- #define IPTOS_MINCOST 0x02
- #endif
- #define IAX_CONF_FILE "iax1.conf"
- /* Deprecated old configuration file */
- #define IAX_OLD_CONF_FILE "iax.conf"
- /*
- * Uncomment to try experimental IAX bridge optimization,
- * designed to reduce latency when IAX calls cannot
- * be trasnferred
- */
- #define BRIDGE_OPTIMIZATION
- #define DEFAULT_RETRY_TIME 1000
- #define MEMORY_SIZE 100
- #define DEFAULT_DROP 3
- #define DEBUG_SUPPORT
- /* Sample over last 100 units to determine historic jitter */
- #define GAMMA (0.01)
- #ifdef MYSQL_FRIENDS
- AST_MUTEX_DEFINE_STATIC(mysqllock);
- static MYSQL *mysql;
- static char mydbuser[80];
- static char mydbpass[80];
- static char mydbhost[80];
- static char mydbname[80];
- #endif
- static char *desc = "Inter Asterisk eXchange";
- static char *tdesc = "Inter Asterisk eXchange Drver";
- static char *ctype = "IAX";
- static char *type = "IAX1";
- static char context[80] = "default";
- static int max_retries = 4;
- static int ping_time = 20;
- static int lagrq_time = 10;
- static int nextcallno = 0;
- static int maxjitterbuffer=3000;
- static int iaxdefaultdpcache=10 * 60; /* Cache dialplan entries for 10 minutes by default */
- static int iaxdefaulttimeout = 5; /* Default to wait no more than 5 seconds for a reply to come back */
- static int netsocket = -1;
- static int tos = 0;
- static int expirey = AST_DEFAULT_REG_EXPIRE;
- static int usecnt;
- AST_MUTEX_DEFINE_STATIC(usecnt_lock);
- int (*iax_regfunk)(char *username, int onoff) = NULL;
- /* Ethernet, etc */
- #define IAX_CAPABILITY_FULLBANDWIDTH 0xFFFF
- /* T1, maybe ISDN */
- #define IAX_CAPABILITY_MEDBANDWIDTH (IAX_CAPABILITY_FULLBANDWIDTH & \
- ~AST_FORMAT_SLINEAR & \
- ~AST_FORMAT_ULAW & \
- ~AST_FORMAT_ALAW)
- /* A modem */
- #define IAX_CAPABILITY_LOWBANDWIDTH (IAX_CAPABILITY_MEDBANDWIDTH & \
- ~AST_FORMAT_ADPCM & \
- ~AST_FORMAT_G726)
- #define IAX_CAPABILITY_LOWFREE (IAX_CAPABILITY_LOWBANDWIDTH & \
- ~AST_FORMAT_G723_1)
- #define DEFAULT_MAXMS 2000 /* Must be faster than 2 seconds by default */
- #define DEFAULT_FREQ_OK 60 * 1000 /* How often to check for the host to be up */
- #define DEFAULT_FREQ_NOTOK 10 * 1000 /* How often to check, if the host is down... */
- static struct io_context *io;
- static struct sched_context *sched;
- static int iax_capability = IAX_CAPABILITY_FULLBANDWIDTH;
- static int iax_dropcount = DEFAULT_DROP;
- static int use_jitterbuffer = 1;
- static int iaxdebug = 0;
- static char accountcode[20];
- static int amaflags = 0;
- static pthread_t netthreadid = AST_PTHREADT_NULL;
- #define IAX_STATE_STARTED (1 << 0)
- #define IAX_STATE_AUTHENTICATED (1 << 1)
- #define IAX_STATE_TBD (1 << 2)
- struct iax_context {
- char context[AST_MAX_EXTENSION];
- struct iax_context *next;
- };
- struct iax_user {
- char name[80];
- char secret[80];
- char methods[80];
- char accountcode[20];
- char inkeys[80]; /* Key(s) this user can use to authenticate to us */
- int amaflags;
- int hascallerid;
- int delme;
- char callerid[AST_MAX_EXTENSION];
- struct ast_ha *ha;
- struct iax_context *contexts;
- struct iax_user *next;
- };
- struct iax_peer {
- char name[80];
- char username[80];
- char secret[80];
- char outkey[80]; /* What key we use to talk to this peer */
- char context[AST_MAX_EXTENSION]; /* Default context (for transfer really) */
- struct sockaddr_in addr;
- int formats;
- struct in_addr mask;
- /* Dynamic Registration fields */
- int dynamic; /* If this is a dynamic peer */
- struct sockaddr_in defaddr; /* Default address if there is one */
- char methods[80];
- char inkeys[80]; /* Key(s) this peer can use to authenticate to us */
- int hascallerid;
- /* Suggested caller id if registering */
- char callerid[AST_MAX_EXTENSION];
- /* Whether or not to send ANI */
- int sendani;
- int expire; /* Schedule entry for expirey */
- int expirey; /* How soon to expire */
- int capability; /* Capability */
- int delme; /* I need to be deleted */
- /* Qualification */
- int callno; /* Call number of POKE request */
- int pokeexpire; /* When to expire poke */
- int lastms; /* How long last response took (in ms), or -1 for no response */
- int maxms; /* Max ms we will accept for the host to be up, 0 to not monitor */
-
- struct ast_ha *ha;
- struct iax_peer *next;
- };
- #define REG_STATE_UNREGISTERED 0
- #define REG_STATE_REGSENT 1
- #define REG_STATE_AUTHSENT 2
- #define REG_STATE_REGISTERED 3
- #define REG_STATE_REJECTED 4
- #define REG_STATE_TIMEOUT 5
- #define REG_STATE_NOAUTH 6
- #define TRANSFER_NONE 0
- #define TRANSFER_BEGIN 1
- #define TRANSFER_READY 2
- #define TRANSFER_RELEASED 3
- #define TRANSFER_PASSTHROUGH 4
- struct iax_registry {
- struct sockaddr_in addr; /* Who we connect to for registration purposes */
- char username[80];
- char secret[80]; /* Password or key name in []'s */
- char random[80];
- int expire; /* Sched ID of expiration */
- int refresh; /* How often to refresh */
- int regstate;
- int callno; /* Associated call number if applicable */
- struct sockaddr_in us; /* Who the server thinks we are */
- struct iax_registry *next;
- };
- static struct iax_registry *registrations;
- /* Don't retry more frequently than every 10 ms, or less frequently than every 5 seconds */
- #define MIN_RETRY_TIME 10
- #define MAX_RETRY_TIME 10000
- #define MAX_JITTER_BUFFER 50
- /* If we have more than this much excess real jitter buffer, srhink it. */
- static int max_jitter_buffer = MAX_JITTER_BUFFER;
- struct chan_iax_pvt {
- /* Pipes for communication. pipe[1] belongs to the
- network thread (write), and pipe[0] belongs to the individual
- channel (read) */
- /* Whether or not we Quelch audio */
- int quelch;
- /* Last received voice format */
- int voiceformat;
- /* Last sent voice format */
- int svoiceformat;
- /* What we are capable of sending */
- int capability;
- /* Last received timestamp */
- unsigned int last;
- /* Last sent timestamp - never send the same timestamp twice in a single call */
- unsigned int lastsent;
- /* Ping time */
- unsigned int pingtime;
- /* Max time for initial response */
- int maxtime;
- /* Peer Address */
- struct sockaddr_in addr;
- /* Our call number */
- int callno;
- /* Peer callno */
- int peercallno;
- /* Peer selected format */
- int peerformat;
- /* Peer capability */
- int peercapability;
- /* timeval that we base our transmission on */
- struct timeval offset;
- /* timeval that we base our delivery on */
- struct timeval rxcore;
- /* Historical delivery time */
- int history[MEMORY_SIZE];
- /* Current base jitterbuffer */
- int jitterbuffer;
- /* Current jitter measure */
- int jitter;
- /* Historic jitter value */
- int historicjitter;
- /* LAG */
- int lag;
- /* Error, as discovered by the manager */
- int error;
- /* Owner if we have one */
- struct ast_channel *owner;
- /* What's our state? */
- int state;
- /* Expirey (optional) */
- int expirey;
- /* Next outgoing sequence number */
- unsigned short oseqno;
- /* Next incoming sequence number */
- unsigned short iseqno;
- /* Peer name */
- char peer[80];
- /* Default Context */
- char context[80];
- /* Caller ID if available */
- char callerid[80];
- /* Hidden Caller ID (i.e. ANI) if appropriate */
- char ani[80];
- /* Whether or not ani should be transmitted in addition to Caller*ID */
- int sendani;
- /* DNID */
- char dnid[80];
- /* Requested Extension */
- char exten[AST_MAX_EXTENSION];
- /* Expected Username */
- char username[80];
- /* Expected Secret */
- char secret[80];
- /* permitted authentication methods */
- char methods[80];
- /* MD5 challenge */
- char challenge[10];
- /* Public keys permitted keys for incoming authentication */
- char inkeys[80];
- /* Private key for outgoing authentication */
- char outkey[80];
- /* Preferred language */
- char language[80];
- /* Associated registry */
- struct iax_registry *reg;
- /* Associated peer for poking */
- struct iax_peer *peerpoke;
- /* Transferring status */
- int transferring;
- /* Already disconnected */
- int alreadygone;
- /* Who we are IAX transfering to */
- struct sockaddr_in transfer;
- /* What's the new call number for the transfer */
- int transfercallno;
- /* Status of knowledge of peer ADSI capability */
- int peeradsicpe;
-
- /* Who we are bridged to */
- int bridgecallno;
- int pingid; /* Transmit PING request */
- int lagid; /* Retransmit lag request */
- int autoid; /* Auto hangup for Dialplan requestor */
- int initid; /* Initial peer auto-congest ID (based on qualified peers) */
- char dproot[AST_MAX_EXTENSION];
- char accountcode[20];
- int amaflags;
- struct iax_dpcache *dpentries;
- };
- #define DIRECTION_INGRESS 1
- #define DIRECTION_OUTGRESS 2
- struct ast_iax_frame {
- /* Actual, isolated frame */
- struct ast_frame *f;
- /* /Our/ call number */
- short callno;
- /* Start of raw frame (outgoing only) */
- void *data;
- /* Length of frame (outgoing only) */
- int datalen;
- /* How many retries so far? */
- int retries;
- /* Outgoing relative timestamp (ms) */
- unsigned int ts;
- /* How long to wait before retrying */
- int retrytime;
- /* Are we received out of order? */
- int outoforder;
- /* Have we been sent at all yet? */
- int sentyet;
- /* Packet sequence number */
- int seqno;
- /* Non-zero if should be sent to transfer peer */
- int transfer;
- /* Non-zero if this is the final message */
- int final;
- /* Ingress or outgres */
- int direction;
- /* Retransmission ID */
- int retrans;
- /* Easy linking */
- struct ast_iax_frame *next;
- struct ast_iax_frame *prev;
- };
- static struct ast_iax_queue {
- struct ast_iax_frame *head;
- struct ast_iax_frame *tail;
- int count;
- ast_mutex_t lock;
- } iaxq;
- static struct ast_user_list {
- struct iax_user *users;
- ast_mutex_t lock;
- } userl;
- static struct ast_peer_list {
- struct iax_peer *peers;
- ast_mutex_t lock;
- } peerl;
- /* Extension exists */
- #define CACHE_FLAG_EXISTS (1 << 0)
- /* Extension is non-existant */
- #define CACHE_FLAG_NONEXISTANT (1 << 1)
- /* Extension can exist */
- #define CACHE_FLAG_CANEXIST (1 << 2)
- /* Waiting to hear back response */
- #define CACHE_FLAG_PENDING (1 << 3)
- /* Timed out */
- #define CACHE_FLAG_TIMEOUT (1 << 4)
- /* Request transmitted */
- #define CACHE_FLAG_TRANSMITTED (1 << 5)
- /* Timeout */
- #define CACHE_FLAG_UNKNOWN (1 << 6)
- /* Matchmore */
- #define CACHE_FLAG_MATCHMORE (1 << 7)
- static struct iax_dpcache {
- char peercontext[AST_MAX_EXTENSION];
- char exten[AST_MAX_EXTENSION];
- struct timeval orig;
- struct timeval expirey;
- int flags;
- int callno;
- int waiters[256];
- struct iax_dpcache *next;
- struct iax_dpcache *peer; /* For linking in peers */
- } *dpcache;
- AST_MUTEX_DEFINE_STATIC(dpcache_lock);
- #ifdef DEBUG_SUPPORT
- static void showframe(struct ast_iax_frame *f, struct ast_iax_full_hdr *fhi, int rx, struct sockaddr_in *sin)
- {
- char *frames[] = {
- "(0?)",
- "DTMF ",
- "VOICE ",
- "VIDEO ",
- "CONTROL",
- "NULL ",
- "IAX ",
- "TEXT ",
- "IMAGE " };
- char *iaxs[] = {
- "(0?)",
- "NEW ",
- "PING ",
- "PONG ",
- "ACK ",
- "HANGUP ",
- "REJECT ",
- "ACCEPT ",
- "AUTHREQ",
- "AUTHREP",
- "INVAL ",
- "LAGRQ ",
- "LAGRP ",
- "REGREQ ",
- "REGAUTH",
- "REGACK ",
- "REGREJ ",
- "REGREL ",
- "VNAK ",
- "DPREQ ",
- "DPREP ",
- "DIAL ",
- "TXREQ ",
- "TXCNT ",
- "TXACC ",
- "TXREADY",
- "TXREL ",
- "TXREJ ",
- "QUELCH ",
- "UNQULCH",
- "POKE",
- };
- char *cmds[] = {
- "(0?)",
- "HANGUP ",
- "RING ",
- "RINGING",
- "ANSWER ",
- "BUSY ",
- "TKOFFHK ",
- "OFFHOOK" };
- struct ast_iax_full_hdr *fh;
- char retries[20] = "";
- char class2[20];
- char subclass2[20];
- char *class;
- char *subclass;
- char iabuf[INET_ADDRSTRLEN];
- if (f) {
- fh = f->data;
- snprintf(retries, sizeof(retries), "%03d", f->retries);
- } else {
- strncpy(retries, "N/A", sizeof(retries) - 1);
- fh = fhi;
- }
- if (!(ntohs(fh->callno) & AST_FLAG_FULL)) {
- /* Don't mess with mini-frames */
- return;
- }
- if (fh->type > sizeof(frames)/sizeof(char *)) {
- snprintf(class2, sizeof(class2), "(%d?)", fh->type);
- class = class2;
- } else {
- class = frames[(int)fh->type];
- }
- if (fh->type == AST_FRAME_DTMF) {
- snprintf(subclass2, sizeof(subclass2), "%c", fh->csub);
- subclass = subclass2;
- } else if (fh->type == AST_FRAME_IAX) {
- if (fh->csub >= sizeof(iaxs)/sizeof(iaxs[0])) {
- snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
- subclass = subclass2;
- } else {
- subclass = iaxs[(int)fh->csub];
- }
- } else if (fh->type == AST_FRAME_CONTROL) {
- if (fh->csub > sizeof(cmds)/sizeof(char *)) {
- snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
- subclass = subclass2;
- } else {
- subclass = cmds[(int)fh->csub];
- }
- } else {
- snprintf(subclass2, sizeof(subclass2), "%d", fh->csub);
- subclass = subclass2;
- }
- ast_verbose(
- "%s-Frame Retry[%s] -- Seqno: %2.2d Type: %s Subclass: %s\n",
- (rx ? "Rx" : "Tx"),
- retries, ntohs(fh->seqno), class, subclass);
- fprintf(stderr,
- " Timestamp: %05ldms Callno: %5.5d DCall: %5.5d [%s:%d]\n",
- (long)ntohl(fh->ts),
- (short)(ntohs(fh->callno) & ~AST_FLAG_FULL), (short) ntohs(fh->dcallno),
- ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port));
- }
- #endif
- /* XXX We probably should use a mutex when working with this XXX */
- static struct chan_iax_pvt *iaxs[AST_IAX_MAX_CALLS];
- static ast_mutex_t iaxsl[AST_IAX_MAX_CALLS];
- static int send_command(struct chan_iax_pvt *, char, int, unsigned int, char *, int, int);
- static int send_command_immediate(struct chan_iax_pvt *, char, int, unsigned int, char *, int, int);
- static int send_command_final(struct chan_iax_pvt *, char, int, unsigned int, char *, int, int);
- static int send_command_transfer(struct chan_iax_pvt *, char, int, unsigned int, char *, int);
- static unsigned int calc_timestamp(struct chan_iax_pvt *p, unsigned int ts);
- static int send_ping(void *data)
- {
- int callno = (long)data;
- /* Ping only if it's real, not if it's bridged */
- if (iaxs[callno]) {
- #ifdef BRIDGE_OPTIMIZATION
- if (iaxs[callno]->bridgecallno < 0)
- #endif
- send_command(iaxs[callno], AST_FRAME_IAX, AST_IAX_COMMAND_PING, 0, NULL, 0, -1);
- return 1;
- } else
- return 0;
- }
- static int send_lagrq(void *data)
- {
- int callno = (long)data;
- /* Ping only if it's real not if it's bridged */
- if (iaxs[callno]) {
- #ifdef BRIDGE_OPTIMIZATION
- if (iaxs[callno]->bridgecallno < 0)
- #endif
- send_command(iaxs[callno], AST_FRAME_IAX, AST_IAX_COMMAND_LAGRQ, 0, NULL, 0, -1);
- return 1;
- } else
- return 0;
- }
- static unsigned char compress_subclass(int subclass)
- {
- int x;
- int power=-1;
- /* If it's 128 or smaller, just return it */
- if (subclass < AST_FLAG_SC_LOG)
- return subclass;
- /* Otherwise find its power */
- for (x = 0; x < AST_MAX_SHIFT; x++) {
- if (subclass & (1 << x)) {
- if (power > -1) {
- ast_log(LOG_WARNING, "Can't compress subclass %d\n", subclass);
- return 0;
- } else
- power = x;
- }
- }
- return power | AST_FLAG_SC_LOG;
- }
- static int uncompress_subclass(unsigned char csub)
- {
- /* If the SC_LOG flag is set, return 2^csub otherwise csub */
- if (csub & AST_FLAG_SC_LOG) {
- /* special case for 'compressed' -1 */
- if (csub == 0xff)
- return -1;
- else
- return 1 << (csub & ~AST_FLAG_SC_LOG & AST_MAX_SHIFT);
- }
- else
- return csub;
- }
- static struct chan_iax_pvt *new_iax(void)
- {
- struct chan_iax_pvt *tmp;
- tmp = malloc(sizeof(struct chan_iax_pvt));
- if (tmp) {
- memset(tmp, 0, sizeof(struct chan_iax_pvt));
- tmp->callno = -1;
- tmp->peercallno = -1;
- tmp->transfercallno = -1;
- tmp->bridgecallno = -1;
- tmp->pingid = -1;
- tmp->lagid = -1;
- tmp->autoid = -1;
- tmp->initid = -1;
- /* strncpy(tmp->context, context, sizeof(tmp->context)-1); */
- strncpy(tmp->exten, "s", sizeof(tmp->exten)-1);
- }
- return tmp;
- }
- static int get_samples(struct ast_frame *f)
- {
- int samples=0;
- switch(f->subclass) {
- case AST_FORMAT_G723_1:
- samples = 240 /* XXX Not necessarily true XXX */;
- break;
- case AST_FORMAT_GSM:
- samples = 160 * (f->datalen / 33);
- break;
- case AST_FORMAT_ILBC:
- samples = 240 * (f->datalen / 50);
- break;
- case AST_FORMAT_G729A:
- samples = 160 * (f->datalen / 20);
- break;
- case AST_FORMAT_SLINEAR:
- samples = f->datalen / 2;
- break;
- case AST_FORMAT_LPC10:
- samples = 22 * 8;
- samples += (((char *)(f->data))[7] & 0x1) * 8;
- break;
- case AST_FORMAT_ULAW:
- samples = f->datalen;
- break;
- case AST_FORMAT_ALAW:
- samples = f->datalen;
- break;
- case AST_FORMAT_ADPCM:
- case AST_FORMAT_G726:
- samples = f->datalen *2;
- break;
- case AST_FORMAT_SPEEX:
- samples = (f->datalen/39)*160;
- break;
- default:
- ast_log(LOG_WARNING, "Don't know how to calculate samples on %d packets\n", f->subclass);
- }
- return samples;
- }
- static int frames = 0;
- static int iframes = 0;
- static int oframes = 0;
- static struct ast_iax_frame *ast_iax_frame_new(int direction)
- {
- struct ast_iax_frame *fr;
- fr = malloc(sizeof(struct ast_iax_frame));
- if (fr) {
- fr->direction = direction;
- fr->retrans = -1;
- frames++;
- if (fr->direction == DIRECTION_INGRESS)
- iframes++;
- else
- oframes++;
- }
- return fr;
- }
- static void ast_iax_frame_free(struct ast_iax_frame *fr)
- {
- if (fr->retrans > -1)
- ast_sched_del(sched, fr->retrans);
- if (fr->direction == DIRECTION_INGRESS)
- iframes--;
- else if (fr->direction == DIRECTION_OUTGRESS)
- oframes--;
- else {
- ast_log(LOG_WARNING, "Attempt to double free frame detected\n");
- CRASH;
- return;
- }
- fr->direction = 0;
- free(fr);
- frames--;
- }
- static struct ast_iax_frame *iaxfrdup2(struct ast_iax_frame *fr, int ch)
- {
- /* Malloc() a copy of a frame */
- struct ast_iax_frame *new = ast_iax_frame_new(DIRECTION_INGRESS);
- if (new) {
- memcpy(new, fr, sizeof(struct ast_iax_frame));
- new->f = ast_frdup(fr->f);
- /* Copy full header */
- if (ch) {
- memcpy(new->f->data - sizeof(struct ast_iax_full_hdr),
- fr->f->data - sizeof(struct ast_iax_full_hdr),
- sizeof(struct ast_iax_full_hdr));
- /* Grab new data pointer */
- new->data = new->f->data - (fr->f->data - fr->data);
- } else {
- new->data = NULL;
- new->datalen = 0;
- }
- new->direction = DIRECTION_INGRESS;
- new->retrans = -1;
- }
- return new;
- }
- #define NEW_PREVENT 0
- #define NEW_ALLOW 1
- #define NEW_FORCE 2
- static int match(struct sockaddr_in *sin, short callno, short dcallno, struct chan_iax_pvt *cur)
- {
- if ((cur->addr.sin_addr.s_addr == sin->sin_addr.s_addr) &&
- (cur->addr.sin_port == sin->sin_port)) {
- /* This is the main host */
- if ((cur->peercallno == callno) ||
- ((dcallno == cur->callno) && (cur->peercallno) == -1)) {
- /* That's us. Be sure we keep track of the peer call number */
- return 1;
- }
- }
- if ((cur->transfer.sin_addr.s_addr == sin->sin_addr.s_addr) &&
- (cur->transfer.sin_port == sin->sin_port) && (cur->transferring)) {
- /* We're transferring */
- if (dcallno == cur->callno)
- return 1;
- }
- return 0;
- }
- static int find_callno(short callno, short dcallno ,struct sockaddr_in *sin, int new)
- {
- int res = -1;
- int x;
- int start;
- if (new <= NEW_ALLOW) {
- /* Look for an existing connection first */
- for (x=0;(res < 0) && (x<AST_IAX_MAX_CALLS);x++) {
- ast_mutex_lock(&iaxsl[x]);
- if (iaxs[x]) {
- /* Look for an exact match */
- if (match(sin, callno, dcallno, iaxs[x])) {
- res = x;
- }
- }
- ast_mutex_unlock(&iaxsl[x]);
- }
- }
- if ((res < 0) && (new >= NEW_ALLOW)) {
- /* Create a new one */
- start = nextcallno;
- for (x = (nextcallno + 1) % AST_IAX_MAX_CALLS; iaxs[x] && (x != start); x = (x + 1) % AST_IAX_MAX_CALLS)
- if (x == start) {
- ast_log(LOG_WARNING, "Unable to accept more calls\n");
- return -1;
- }
- ast_mutex_lock(&iaxsl[x]);
- iaxs[x] = new_iax();
- ast_mutex_unlock(&iaxsl[x]);
- if (iaxs[x]) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Creating new call structure %d\n", x);
- iaxs[x]->addr.sin_port = sin->sin_port;
- iaxs[x]->addr.sin_family = sin->sin_family;
- iaxs[x]->addr.sin_addr.s_addr = sin->sin_addr.s_addr;
- iaxs[x]->peercallno = callno;
- iaxs[x]->callno = x;
- iaxs[x]->pingtime = DEFAULT_RETRY_TIME;
- iaxs[x]->expirey = expirey;
- iaxs[x]->pingid = ast_sched_add(sched, ping_time * 1000, send_ping, (void *)(long)x);
- iaxs[x]->lagid = ast_sched_add(sched, lagrq_time * 1000, send_lagrq, (void *)(long)x);
- iaxs[x]->amaflags = amaflags;
- strncpy(iaxs[x]->accountcode, accountcode, sizeof(iaxs[x]->accountcode)-1);
- } else {
- ast_log(LOG_WARNING, "Out of resources\n");
- return -1;
- }
- res = x;
- nextcallno = x;
- }
- return res;
- }
- static int iax_queue_frame(int callno, struct ast_frame *f)
- {
- int pass =0;
- /* Assumes lock for callno is already held... */
- for (;;) {
- pass++;
- if (iaxs[callno] && iaxs[callno]->owner) {
- if (ast_mutex_trylock(&iaxs[callno]->owner->lock)) {
- /* Avoid deadlock by pausing and trying again */
- ast_mutex_unlock(&iaxsl[callno]);
- usleep(1);
- ast_mutex_lock(&iaxsl[callno]);
- } else {
- ast_queue_frame(iaxs[callno]->owner, f);
- ast_mutex_unlock(&iaxs[callno]->owner->lock);
- break;
- }
- } else
- break;
- }
- return 0;
- }
- static int iax_send(struct chan_iax_pvt *pvt, struct ast_frame *f, unsigned int ts, int seqno, int now, int transfer, int final);
- static int __do_deliver(void *data)
- {
- /* Just deliver the packet by using queueing. This is called by
- the IAX thread with the iaxsl lock held. */
- struct ast_iax_frame *fr = data;
- unsigned int ts;
- fr->retrans = -1;
- if (iaxs[fr->callno] && !iaxs[fr->callno]->alreadygone) {
- if (fr->f->frametype == AST_FRAME_IAX) {
- /* We have to treat some of these packets specially because
- they're LAG measurement packets */
- if (fr->f->subclass == AST_IAX_COMMAND_LAGRQ) {
- /* If we got a queued request, build a reply and send it */
- fr->f->subclass = AST_IAX_COMMAND_LAGRP;
- iax_send(iaxs[fr->callno], fr->f, fr->ts, -1, 0, 0, 0);
- } else if (fr->f->subclass == AST_IAX_COMMAND_LAGRP) {
- /* This is a reply we've been given, actually measure the difference */
- ts = calc_timestamp(iaxs[fr->callno], 0);
- iaxs[fr->callno]->lag = ts - fr->ts;
- }
- } else {
- iax_queue_frame(fr->callno, fr->f);
- }
- }
- /* Free the packet */
- ast_frfree(fr->f);
- /* And our iax frame */
- ast_iax_frame_free(fr);
- /* And don't run again */
- return 0;
- }
- static int do_deliver(void *data)
- {
- /* Locking version of __do_deliver */
- struct ast_iax_frame *fr = data;
- int callno = fr->callno;
- int res;
- ast_mutex_lock(&iaxsl[callno]);
- res = __do_deliver(data);
- ast_mutex_unlock(&iaxsl[callno]);
- return res;
- }
- static int handle_error(void)
- {
- /* XXX Ideally we should figure out why an error occured and then abort those
- rather than continuing to try. Unfortunately, the published interface does
- not seem to work XXX */
- #if 0
- struct sockaddr_in *sin;
- int res;
- struct msghdr m;
- struct sock_extended_err e;
- m.msg_name = NULL;
- m.msg_namelen = 0;
- m.msg_iov = NULL;
- m.msg_control = &e;
- m.msg_controllen = sizeof(e);
- m.msg_flags = 0;
- res = recvmsg(netsocket, &m, MSG_ERRQUEUE);
- if (res < 0)
- ast_log(LOG_WARNING, "Error detected, but unable to read error: %s\n", strerror(errno));
- else {
- if (m.msg_controllen) {
- sin = (struct sockaddr_in *)SO_EE_OFFENDER(&e);
- if (sin)
- ast_log(LOG_WARNING, "Receive error from %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr));
- else
- ast_log(LOG_WARNING, "No address detected??\n");
- } else {
- ast_log(LOG_WARNING, "Local error: %s\n", strerror(e.ee_errno));
- }
- }
- #endif
- return 0;
- }
- static int send_packet(struct ast_iax_frame *f)
- {
- int res;
- char iabuf[INET_ADDRSTRLEN];
- /* Called with iaxsl held */
- if (option_debug)
- ast_log(LOG_DEBUG, "Sending %d on %d/%d to %s:%d\n", f->ts, f->callno, iaxs[f->callno]->peercallno, ast_inet_ntoa(iabuf, sizeof(iabuf), iaxs[f->callno]->addr.sin_addr), ntohs(iaxs[f->callno]->addr.sin_port));
- /* Don't send if there was an error, but return error instead */
- if (f->callno < 0) {
- ast_log(LOG_WARNING, "Call number = %d\n", f->callno);
- return -1;
- }
- if (!iaxs[f->callno])
- return -1;
- if (iaxs[f->callno]->error)
- return -1;
- if (f->transfer) {
- #ifdef DEBUG_SUPPORT
- if (iaxdebug)
- showframe(f, NULL, 0, &iaxs[f->callno]->transfer);
- #endif
- res = sendto(netsocket, f->data, f->datalen, 0,(struct sockaddr *)&iaxs[f->callno]->transfer,
- sizeof(iaxs[f->callno]->transfer));
- } else {
- #ifdef DEBUG_SUPPORT
- if (iaxdebug)
- showframe(f, NULL, 0, &iaxs[f->callno]->addr);
- #endif
- res = sendto(netsocket, f->data, f->datalen, 0,(struct sockaddr *)&iaxs[f->callno]->addr,
- sizeof(iaxs[f->callno]->addr));
- }
- if (res < 0) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Received error: %s\n", strerror(errno));
- handle_error();
- } else
- res = 0;
- return res;
- }
- static int iax_predestroy(int callno)
- {
- struct ast_channel *c;
- struct chan_iax_pvt *pvt;
- ast_mutex_lock(&iaxsl[callno]);
- pvt = iaxs[callno];
- if (!pvt) {
- ast_mutex_unlock(&iaxsl[callno]);
- return -1;
- }
- if (!pvt->alreadygone) {
- /* No more pings or lagrq's */
- if (pvt->pingid > -1)
- ast_sched_del(sched, pvt->pingid);
- if (pvt->lagid > -1)
- ast_sched_del(sched, pvt->lagid);
- if (pvt->autoid > -1)
- ast_sched_del(sched, pvt->autoid);
- if (pvt->initid > -1)
- ast_sched_del(sched, pvt->initid);
- pvt->pingid = -1;
- pvt->lagid = -1;
- pvt->autoid = -1;
- pvt->initid = -1;
- pvt->alreadygone = 1;
- }
- c = pvt->owner;
- if (c) {
- c->_softhangup |= AST_SOFTHANGUP_DEV;
- c->pvt->pvt = NULL;
- pvt->owner = NULL;
- ast_mutex_lock(&usecnt_lock);
- usecnt--;
- if (usecnt < 0)
- ast_log(LOG_WARNING, "Usecnt < 0???\n");
- ast_mutex_unlock(&usecnt_lock);
- ast_update_use_count();
- }
- ast_mutex_unlock(&iaxsl[callno]);
- return 0;
- }
- static int iax_predestroy_nolock(int callno)
- {
- int res;
- ast_mutex_unlock(&iaxsl[callno]);
- res = iax_predestroy(callno);
- ast_mutex_lock(&iaxsl[callno]);
- return res;
- }
- static void iax_destroy(int callno)
- {
- struct chan_iax_pvt *pvt;
- struct ast_iax_frame *cur;
- struct ast_channel *owner;
- retry:
- ast_mutex_lock(&iaxsl[callno]);
- pvt = iaxs[callno];
- iaxs[callno] = NULL;
- if (pvt)
- owner = pvt->owner;
- else
- owner = NULL;
- if (owner) {
- if (ast_mutex_trylock(&owner->lock)) {
- ast_log(LOG_NOTICE, "Avoiding IAX destroy deadlock\n");
- ast_mutex_unlock(&iaxsl[callno]);
- usleep(1);
- goto retry;
- }
- }
- if (pvt) {
- pvt->owner = NULL;
- /* No more pings or lagrq's */
- if (pvt->pingid > -1)
- ast_sched_del(sched, pvt->pingid);
- if (pvt->lagid > -1)
- ast_sched_del(sched, pvt->lagid);
- if (pvt->autoid > -1)
- ast_sched_del(sched, pvt->autoid);
- if (pvt->initid > -1)
- ast_sched_del(sched, pvt->initid);
- pvt->pingid = -1;
- pvt->lagid = -1;
- pvt->autoid = -1;
- pvt->initid = -1;
- /* Already gone */
- pvt->alreadygone = 1;
- if (owner) {
- /* If there's an owner, prod it to give up */
- owner->pvt->pvt = NULL;
- owner->_softhangup |= AST_SOFTHANGUP_DEV;
- ast_queue_hangup(owner);
- }
- for (cur = iaxq.head; cur ; cur = cur->next) {
- /* Cancel any pending transmissions */
- if (cur->callno == pvt->callno)
- cur->retries = -1;
- }
- if (pvt->reg) {
- pvt->reg->callno = -1;
- }
- free(pvt);
- }
- if (owner) {
- ast_mutex_unlock(&owner->lock);
- }
- ast_mutex_unlock(&iaxsl[callno]);
- }
- static void iax_destroy_nolock(int callno)
- {
- /* Actually it's easier to unlock, kill it, and relock */
- ast_mutex_unlock(&iaxsl[callno]);
- iax_destroy(callno);
- ast_mutex_lock(&iaxsl[callno]);
- }
- static int attempt_transmit(void *data)
- {
- /* Attempt to transmit the frame to the remote peer...
- Called without iaxsl held. */
- struct ast_iax_frame *f = data;
- int freeme=0;
- int callno = f->callno;
- char iabuf[INET_ADDRSTRLEN];
- /* Make sure this call is still active */
- if (callno > -1)
- ast_mutex_lock(&iaxsl[callno]);
- if ((f->callno > -1) && iaxs[f->callno]) {
- if ((f->retries < 0) /* Already ACK'd */ ||
- (f->retries >= max_retries) /* Too many attempts */) {
- /* Record an error if we've transmitted too many times */
- if (f->retries >= max_retries) {
- if (f->transfer) {
- /* Transfer timeout */
- send_command(iaxs[f->callno], AST_FRAME_IAX, AST_IAX_COMMAND_TXREJ, 0, NULL, 0, -1);
- } else if (f->final) {
- if (f->final)
- iax_destroy_nolock(f->callno);
- } else {
- if (iaxs[f->callno]->owner)
- ast_log(LOG_WARNING, "Max retries exceeded to host %s on %s (type = %d, subclass = %d, ts=%d, seqno=%d)\n", ast_inet_ntoa(iabuf, sizeof(iabuf), iaxs[f->callno]->addr.sin_addr),iaxs[f->callno]->owner->name , f->f->frametype, f->f->subclass, f->ts, f->seqno);
- iaxs[f->callno]->error = ETIMEDOUT;
- if (iaxs[f->callno]->owner) {
- struct ast_frame fr = { 0, };
- /* Hangup the fd */
- fr.frametype = AST_FRAME_CONTROL;
- fr.subclass = AST_CONTROL_HANGUP;
- iax_queue_frame(f->callno, &fr);
- } else {
- if (iaxs[f->callno]->reg) {
- memset(&iaxs[f->callno]->reg->us, 0, sizeof(iaxs[f->callno]->reg->us));
- iaxs[f->callno]->reg->regstate = REG_STATE_TIMEOUT;
- iaxs[f->callno]->reg->refresh = AST_DEFAULT_REG_EXPIRE;
- }
- iax_destroy_nolock(f->callno);
- }
- }
- }
- freeme++;
- } else {
- /* Attempt transmission */
- send_packet(f);
- f->retries++;
- /* Try again later after 10 times as long */
- f->retrytime *= 10;
- if (f->retrytime > MAX_RETRY_TIME)
- f->retrytime = MAX_RETRY_TIME;
- /* Transfer messages max out at one second */
- if (f->transfer && (f->retrytime > 1000))
- f->retrytime = 1000;
- f->retrans = ast_sched_add(sched, f->retrytime, attempt_transmit, f);
- }
- } else {
- /* Make sure it gets freed */
- f->retries = -1;
- freeme++;
- }
- if (callno > -1)
- ast_mutex_unlock(&iaxsl[callno]);
- /* Do not try again */
- if (freeme) {
- /* Don't attempt delivery, just remove it from the queue */
- ast_mutex_lock(&iaxq.lock);
- if (f->prev)
- f->prev->next = f->next;
- else
- iaxq.head = f->next;
- if (f->next)
- f->next->prev = f->prev;
- else
- iaxq.tail = f->prev;
- iaxq.count--;
- ast_mutex_unlock(&iaxq.lock);
- /* Free the frame */
- ast_frfree(f->f);
- f->retrans = -1;
- ast_iax_frame_free(f);
- }
- return 0;
- }
- static int iax_set_jitter(int fd, int argc, char *argv[])
- {
- if ((argc != 4) && (argc != 5))
- return RESULT_SHOWUSAGE;
- if (argc == 4) {
- max_jitter_buffer = atoi(argv[3]);
- if (max_jitter_buffer < 0)
- max_jitter_buffer = 0;
- } else {
- if (argc == 5) {
- if ((atoi(argv[3]) >= 0) && (atoi(argv[3]) < AST_IAX_MAX_CALLS)) {
- if (iaxs[atoi(argv[3])]) {
- iaxs[atoi(argv[3])]->jitterbuffer = atoi(argv[4]);
- if (iaxs[atoi(argv[3])]->jitterbuffer < 0)
- iaxs[atoi(argv[3])]->jitterbuffer = 0;
- } else
- ast_cli(fd, "No such call '%d'\n", atoi(argv[3]));
- } else
- ast_cli(fd, "%d is not a valid call number\n", atoi(argv[3]));
- }
- }
- return RESULT_SUCCESS;
- }
- static char jitter_usage[] =
- "Usage: iax set jitter [callid] <value>\n"
- " If used with a callid, it sets the jitter buffer to the given static\n"
- "value (until its next calculation). If used without a callid, the value is used\n"
- "to establish the maximum excess jitter buffer that is permitted before the jitter\n"
- "buffer size is reduced.";
- static int iax_show_stats(int fd, int argc, char *argv[])
- {
- struct ast_iax_frame *cur;
- int cnt = 0, dead=0, final=0;
- if (argc != 3)
- return RESULT_SHOWUSAGE;
- for (cur = iaxq.head; cur ; cur = cur->next) {
- if (cur->retries < 0)
- dead++;
- if (cur->final)
- final++;
- cnt++;
- }
- ast_cli(fd, " IAX Statistics\n");
- ast_cli(fd, "---------------------\n");
- ast_cli(fd, "Outstanding frames: %d (%d ingress, %d outgress)\n", frames, iframes, oframes);
- ast_cli(fd, "Packets in transmit queue: %d dead, %d final, %d total\n", dead, final, cnt);
- return RESULT_SUCCESS;
- }
- static int iax_show_cache(int fd, int argc, char *argv[])
- {
- struct iax_dpcache *dp;
- char tmp[1024] = "", *pc;
- int s;
- int x,y;
- struct timeval tv;
- gettimeofday(&tv, NULL);
- ast_mutex_lock(&dpcache_lock);
- dp = dpcache;
- ast_cli(fd, "%-20.20s %-12.12s %-9.9s %-8.8s %s\n", "Peer/Context", "Exten", "Exp.", "Wait.", "Flags");
- while(dp) {
- s = dp->expirey.tv_sec - tv.tv_sec;
- tmp[0] = '\0';
- if (dp->flags & CACHE_FLAG_EXISTS)
- strncat(tmp, "EXISTS|", sizeof(tmp) - strlen(tmp) - 1);
- if (dp->flags & CACHE_FLAG_NONEXISTANT)
- strncat(tmp, "NONEXISTANT|", sizeof(tmp) - strlen(tmp) - 1);
- if (dp->flags & CACHE_FLAG_CANEXIST)
- strncat(tmp, "CANEXIST|", sizeof(tmp) - strlen(tmp) - 1);
- if (dp->flags & CACHE_FLAG_PENDING)
- strncat(tmp, "PENDING|", sizeof(tmp) - strlen(tmp) - 1);
- if (dp->flags & CACHE_FLAG_TIMEOUT)
- strncat(tmp, "TIMEOUT|", sizeof(tmp) - strlen(tmp) - 1);
- if (dp->flags & CACHE_FLAG_TRANSMITTED)
- strncat(tmp, "TRANSMITTED|", sizeof(tmp) - strlen(tmp) - 1);
- if (dp->flags & CACHE_FLAG_MATCHMORE)
- strncat(tmp, "MATCHMORE|", sizeof(tmp) - strlen(tmp) - 1);
- if (dp->flags & CACHE_FLAG_UNKNOWN)
- strncat(tmp, "UNKNOWN|", sizeof(tmp) - strlen(tmp) - 1);
- /* Trim trailing pipe */
- if (strlen(tmp))
- tmp[strlen(tmp) - 1] = '\0';
- else
- strncpy(tmp, "(none)", sizeof(tmp) - 1);
- y=0;
- pc = strchr(dp->peercontext, '@');
- if (!pc)
- pc = dp->peercontext;
- else
- pc++;
- for (x=0;x<sizeof(dp->waiters) / sizeof(dp->waiters[0]); x++)
- if (dp->waiters[x] > -1)
- y++;
- if (s > 0)
- ast_cli(fd, "%-20.20s %-12.12s %-9d %-8d %s\n", pc, dp->exten, s, y, tmp);
- else
- ast_cli(fd, "%-20.20s %-12.12s %-9.9s %-8d %s\n", pc, dp->exten, "(expired)", y, tmp);
- dp = dp->next;
- }
- ast_mutex_unlock(&dpcache_lock);
- return RESULT_SUCCESS;
- }
- static char show_stats_usage[] =
- "Usage: iax1 show stats\n"
- " Display statistics on IAX channel driver.\n";
- static char show_cache_usage[] =
- "Usage: iax1 show cache\n"
- " Display currently cached IAX Dialplan results.\n";
- static struct ast_cli_entry cli_set_jitter =
- { { "iax1", "set", "jitter", NULL }, iax_set_jitter, "Sets IAX jitter buffer", jitter_usage };
- static struct ast_cli_entry cli_show_stats =
- { { "iax1", "show", "stats", NULL }, iax_show_stats, "Display IAX statistics", show_stats_usage };
- static struct ast_cli_entry cli_show_cache =
- { { "iax1", "show", "cache", NULL }, iax_show_cache, "Display IAX cached dialplan", show_cache_usage };
- static unsigned int calc_rxstamp(struct chan_iax_pvt *p);
- #ifdef BRIDGE_OPTIMIZATION
- static unsigned int calc_fakestamp(struct chan_iax_pvt *from, struct chan_iax_pvt *to, unsigned int ts);
- static int forward_delivery(struct ast_iax_frame *fr)
- {
- struct chan_iax_pvt *p1, *p2;
- p1 = iaxs[fr->callno];
- p2 = iaxs[p1->bridgecallno];
- if (!p1)
- return -1;
- if (!p2)
- return -1;
- /* Fix relative timestamp */
- fr->ts = calc_fakestamp(p1, p2, fr->ts);
- /* Now just send it send on the 2nd one
- with adjusted timestamp */
- return iax_send(p2, fr->f, fr->ts, -1, 0, 0, 0);
- }
- #endif
- static int schedule_delivery(struct ast_iax_frame *fr, int reallydeliver)
- {
- int ms,x;
- int drops[MEMORY_SIZE];
- int min, max=0, maxone=0,y,z, match;
- /* ms is a measure of the "lateness" of the packet relative to the first
- packet we received, which always has a lateness of 1. Called by
- IAX thread, with iaxsl lock held. */
- ms = calc_rxstamp(iaxs[fr->callno]) - fr->ts;
- if (ms > 32767) {
- /* What likely happened here is that our counter has circled but we haven't
- gotten the update from the main packet. We'll just pretend that we did, and
- update the timestamp appropriately. */
- ms -= 65536;
- }
- if (ms < -32768) {
- /* We got this packet out of order. Lets add 65536 to it to bring it into our new
- time frame */
- ms += 65536;
- }
-
- /* Rotate our history queue of "lateness". Don't worry about those initial
- zeros because the first entry will always be zero */
- for (x=0;x<MEMORY_SIZE - 1;x++)
- iaxs[fr->callno]->history[x] = iaxs[fr->callno]->history[x+1];
- /* Add a history entry for this one */
- iaxs[fr->callno]->history[x] = ms;
- /* Initialize the minimum to reasonable values. It's too much
- work to do the same for the maximum, repeatedly */
- min=iaxs[fr->callno]->history[0];
- for (z=0;z < iax_dropcount + 1;z++) {
- /* Start very optimistic ;-) */
- max=-999999999;
- for (x=0;x<MEMORY_SIZE;x++) {
- if (max < iaxs[fr->callno]->history[x]) {
- /* We have a candidate new maximum value. Make
- sure it's not in our drop list */
- match = 0;
- for (y=0;!match && (y<z);y++)
- match |= (drops[y] == x);
- if (!match) {
- /* It's not in our list, use it as the new maximum */
- max = iaxs[fr->callno]->history[x];
- maxone = x;
- }
-
- }
- if (!z) {
- /* On our first pass, find the minimum too */
- if (min > iaxs[fr->callno]->history[x])
- min = iaxs[fr->callno]->history[x];
- }
- }
- #if 1
- drops[z] = maxone;
- #endif
- }
- /* Just for reference, keep the "jitter" value, the difference between the
- earliest and the latest. */
- iaxs[fr->callno]->jitter = max - min;
-
- /* IIR filter for keeping track of historic jitter, but always increase
- historic jitter immediately for increase */
-
- if (iaxs[fr->callno]->jitter > iaxs[fr->callno]->historicjitter )
- iaxs[fr->callno]->historicjitter = iaxs[fr->callno]->jitter;
- else
- iaxs[fr->callno]->historicjitter = GAMMA * (double)iaxs[fr->callno]->jitter + (1-GAMMA) *
- iaxs[fr->callno]->historicjitter;
- /* If our jitter buffer is too big (by a significant margin), then we slowly
- shrink it by about 1 ms each time to avoid letting the change be perceived */
- if (max < iaxs[fr->callno]->jitterbuffer - max_jitter_buffer)
- iaxs[fr->callno]->jitterbuffer -= 2;
- #if 1
- /* Constrain our maximum jitter buffer appropriately */
- if (max > min + maxjitterbuffer) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Constraining buffer from %d to %d + %d\n", max, min , maxjitterbuffer);
- max = min + maxjitterbuffer;
- }
- #endif
- /* If our jitter buffer is smaller than our maximum delay, grow the jitter
- buffer immediately to accomodate it (and a little more). */
- if (max > iaxs[fr->callno]->jitterbuffer)
- iaxs[fr->callno]->jitterbuffer = max
- /* + ((float)iaxs[fr->callno]->jitter) * 0.1 */;
-
- if (option_debug)
- ast_log(LOG_DEBUG, "min = %d, max = %d, jb = %d, lateness = %d\n", min, max, iaxs[fr->callno]->jitterbuffer, ms);
-
- /* Subtract the lateness from our jitter buffer to know how long to wait
- before sending our packet. */
- ms = iaxs[fr->callno]->jitterbuffer - ms;
-
- if (!use_jitterbuffer)
- ms = 0;
- /* If the caller just wanted us to update, return now */
- if (!reallydeliver)
- return 0;
-
- if (ms < 1) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Calculated ms is %d\n", ms);
- /* Don't deliver it more than 4 ms late */
- if ((ms > -4) || (fr->f->frametype != AST_FRAME_VOICE)) {
- __do_deliver(fr);
- } else {
- if (option_debug)
- ast_log(LOG_DEBUG, "Dropping voice packet since %d ms is, too old\n", ms);
- /* Free the packet */
- ast_frfree(fr->f);
- /* And our iax frame */
- ast_iax_frame_free(fr);
- }
- } else {
- if (option_debug)
- ast_log(LOG_DEBUG, "Scheduling delivery in %d ms\n", ms);
- fr->retrans = ast_sched_add(sched, ms, do_deliver, fr);
- }
- return 0;
- }
- static int iax_transmit(struct ast_iax_frame *fr)
- {
- /* Lock the queue and place this packet at the end */
- fr->next = NULL;
- fr->prev = NULL;
- /* By setting this to 0, the network thread will send it for us, and
- queue retransmission if necessary */
- fr->sentyet = 0;
- ast_mutex_lock(&iaxq.lock);
- if (!iaxq.head) {
- /* Empty queue */
- iaxq.head = fr;
- iaxq.tail = fr;
- } else {
- /* Double link */
- iaxq.tail->next = fr;
- fr->prev = iaxq.tail;
- iaxq.tail = fr;
- }
- iaxq.count++;
- ast_mutex_unlock(&iaxq.lock);
- /* Wake up the network thread */
- pthread_kill(netthreadid, SIGURG);
- return 0;
- }
- static int iax_digit(struct ast_channel *c, char digit)
- {
- return send_command(c->pvt->pvt, AST_FRAME_DTMF, digit, 0, NULL, 0, -1);
- }
- static int iax_sendtext(struct ast_channel *c, char *text)
- {
-
- return send_command(c->pvt->pvt, AST_FRAME_TEXT,
- 0, 0, text, strlen(text) + 1, -1);
- }
- static int iax_sendimage(struct ast_channel *c, struct ast_frame *img)
- {
- return send_command(c->pvt->pvt, AST_FRAME_IMAGE, img->subclass, 0, img->data, img->datalen, -1);
- }
- static int iax_sendhtml(struct ast_channel *c, int subclass, char *data, int datalen)
- {
- return send_command(c->pvt->pvt, AST_FRAME_HTML, subclass, 0, data, datalen, -1);
- }
- static int iax_fixup(struct ast_channel *oldchannel, struct ast_channel *newchan)
- {
- struct chan_iax_pvt *pvt = newchan->pvt->pvt;
- pvt->owner = newchan;
- return 0;
- }
- #ifdef MYSQL_FRIENDS
- static void mysql_update_peer(char *peer, struct sockaddr_in *sin)
- {
- if (mysql && (strlen(peer) < 128)) {
- char query[512];
- char *name;
- time_t nowtime;
- name = alloca(strlen(peer) * 2 + 1);
- time(&nowtime);
- mysql_real_escape_string(mysql, name, peer, strlen(peer));
- snprintf(query, sizeof(query), "UPDATE iax1friends SET ipaddr=\"%s\", port=\"%d\", regseconds=\"%ld\" WHERE name=\"%s\"",
- ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port), nowtime, name);
- ast_mutex_lock(&mysqllock);
- if (mysql_real_query(mysql, query, strlen(query)))
- ast_log(LOG_WARNING, "Unable to update database\n");
-
- ast_mutex_unlock(&mysqllock);
- }
- }
- static struct iax_peer *mysql_peer(char *peer)
- {
- struct iax_peer *p;
- int success = 0;
-
- p = malloc(sizeof(struct iax_peer));
- memset(p, 0, sizeof(struct iax_peer));
- if (mysql && (strlen(peer) < 128)) {
- char query[512];
- char *name;
- int numfields, x;
- int port;
- time_t regseconds, nowtime;
- MYSQL_RES *result;
- MYSQL_FIELD *fields;
- MYSQL_ROW rowval;
- name = alloca(strlen(peer) * 2 + 1);
- mysql_real_escape_string(mysql, name, peer, strlen(peer));
- snprintf(query, sizeof(query), "SELECT name, secret, context, ipaddr, port, regseconds FROM iax1friends WHERE name=\"%s\"", name);
- ast_mutex_lock(&mysqllock);
- mysql_query(mysql, query);
- if ((result = mysql_store_result(mysql))) {
- if ((rowval = mysql_fetch_row(result))) {
- numfields = mysql_num_fields(result);
- fields = mysql_fetch_fields(result);
- success = 1;
- for (x=0;x<numfields;x++) {
- if (rowval[x]) {
- if (!strcasecmp(fields[x].name, "secret")) {
- strncpy(p->secret, rowval[x], sizeof(p->secret) - 1);
- } else if (!strcasecmp(fields[x].name, "context")) {
- strncpy(p->context, rowval[x], sizeof(p->context) - 1);
- } else if (!strcasecmp(fields[x].name, "ipaddr")) {
- inet_aton(rowval[x], &p->addr.sin_addr);
- } else if (!strcasecmp(fields[x].name, "port")) {
- if (sscanf(rowval[x], "%i", &port) != 1)
- port = 0;
- p->addr.sin_port = htons(port);
- } else if (!strcasecmp(fields[x].name, "regseconds")) {
- if (sscanf(rowval[x], "%li", ®seconds) != 1)
- regseconds = 0;
- }
- }
- }
- time(&nowtime);
- if ((nowtime - regseconds) > AST_DEFAULT_REG_EXPIRE)
- memset(&p->addr, 0, sizeof(p->addr));
- }
- }
- ast_mutex_unlock(&mysqllock);
- }
- if (!success) {
- free(p);
- p = NULL;
- } else {
- strncpy(p->name, peer, sizeof(p->name) - 1);
- p->dynamic = 1;
- p->delme = 1;
- p->expire = -1;
- p->capability = iax_capability;
- strncpy(p->methods, "md5,plaintext", sizeof(p->methods) - 1);
- }
- return p;
- }
- static struct iax_user *mysql_user(char *user)
- {
- struct iax_user *p;
- struct iax_context *con;
- int success = 0;
-
- p = malloc(sizeof(struct iax_user));
- memset(p, 0, sizeof(struct iax_user));
- con = malloc(sizeof(struct iax_context));
- memset(con, 0, sizeof(struct iax_context));
- strncpy(con->context, "default", sizeof(con->context) - 1);
- p->contexts = con;
- if (mysql && (strlen(user) < 128)) {
- char query[512];
- char *name;
- int numfields, x;
- MYSQL_RES *result;
- MYSQL_FIELD *fields;
- MYSQL_ROW rowval;
- name = alloca(strlen(user) * 2 + 1);
- mysql_real_escape_string(mysql, name, user, strlen(user));
- snprintf(query, sizeof(query), "SELECT name, secret, context, ipaddr, port, regseconds FROM iax1friends WHERE name=\"%s\"", name);
- ast_mutex_lock(&mysqllock);
- mysql_query(mysql, query);
- if ((result = mysql_store_result(mysql))) {
- if ((rowval = mysql_fetch_row(result))) {
- numfields = mysql_num_fields(result);
- fields = mysql_fetch_fields(result);
- success = 1;
- for (x=0;x<numfields;x++) {
- if (rowval[x]) {
- if (!strcasecmp(fields[x].name, "secret")) {
- strncpy(p->secret, rowval[x], sizeof(p->secret) - 1);
- } else if (!strcasecmp(fields[x].name, "context")) {
- strncpy(p->contexts->context, rowval[x], sizeof(p->contexts->context) - 1);
- }
- }
- }
- }
- }
- ast_mutex_unlock(&mysqllock);
- }
- if (!success) {
- if (p->contexts)
- free(p->contexts);
- free(p);
- p = NULL;
- } else {
- strncpy(p->name, user, sizeof(p->name) - 1);
- p->delme = 1;
- strncpy(p->methods, "md5,plaintext", sizeof(p->methods) - 1);
- }
- return p;
- }
- #endif /* MYSQL_FRIENDS */
- static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani, int *maxtime, char *peer, char *context)
- {
- struct ast_hostent ahp; struct hostent *hp;
- struct iax_peer *p;
- int found=0;
- if (sendani)
- *sendani = 0;
- if (maxtime)
- *maxtime = 0;
- sin->sin_family = AF_INET;
- ast_mutex_lock(&peerl.lock);
- p = peerl.peers;
- while(p) {
- if (!strcasecmp(p->name, peer)) {
- break;
- }
- p = p->next;
- }
- #ifdef MYSQL_FRIENDS
- if (!p)
- p = mysql_peer(peer);
- #endif
- if (p) {
- found++;
- if (capability)
- *capability = p->capability;
- if ((p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) &&
- (!p->maxms || ((p->lastms > 0) && (p->lastms <= p->maxms)))) {
- if (sendani)
- *sendani = p->sendani; /* Whether we transmit ANI */
- if (maxtime)
- *maxtime = p->maxms; /* Max time they should take */
- if (context)
- strncpy(context, p->context, AST_MAX_EXTENSION - 1);
- if (p->addr.sin_addr.s_addr) {
- sin->sin_addr = p->addr.sin_addr;
- sin->sin_port = p->addr.sin_port;
- } else {
- sin->sin_addr = p->defaddr.sin_addr;
- sin->sin_port = p->defaddr.sin_port;
- }
- } else {
- if (p->delme)
- free(p);
- p = NULL;
- }
- }
- ast_mutex_unlock(&peerl.lock);
- if (!p && !found) {
- hp = ast_gethostbyname(peer, &ahp);
- if (hp) {
- memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
- sin->sin_port = htons(AST_DEFAULT_IAX_PORTNO);
- return 0;
- } else {
- ast_log(LOG_WARNING, "No such host: %s\n", peer);
- return -1;
- }
- } else if (!p)
- return -1;
- if (p->delme)
- free(p);
- return 0;
- }
- static int auto_congest(void *nothing)
- {
- int callno = (int)(long)(nothing);
- struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_CONGESTION };
- ast_mutex_lock(&iaxsl[callno]);
- if (iaxs[callno]) {
- iaxs[callno]->initid = -1;
- iax_queue_frame(callno, &f);
- ast_log(LOG_NOTICE, "Auto-congesting call due to slow response\n");
- }
- ast_mutex_unlock(&iaxsl[callno]);
- return 0;
- }
- static int iax_call(struct ast_channel *c, char *dest, int timeout)
- {
- struct sockaddr_in sin;
- char host[256];
- char *rdest;
- char *rcontext;
- char *username;
- char *secret = NULL;
- char *hname;
- char requeststr[256] = "";
- char myrdest [5] = "s";
- char context[AST_MAX_EXTENSION] ="";
- char *portno = NULL;
- struct chan_iax_pvt *p = c->pvt->pvt;
- char *stringp=NULL;
- if ((c->_state != AST_STATE_DOWN) && (c->_state != AST_STATE_RESERVED)) {
- ast_log(LOG_WARNING, "Line is already in use (%s)?\n", c->name);
- return -1;
- }
- strncpy(host, dest, sizeof(host)-1);
- stringp=host;
- strsep(&stringp, "/");
- /* If no destination extension specified, use 's' */
- rdest = strsep(&stringp, "/");
- if (!rdest)
- rdest = myrdest;
- stringp=rdest;
- strsep(&stringp, "@");
- rcontext = strsep(&stringp, "@");
- stringp=host;
- strsep(&stringp, "@");
- username = strsep(&stringp, "@");
- if (username) {
- /* Really the second argument is the host, not the username */
- hname = username;
- username = host;
- } else {
- hname = host;
- }
- if (username) {
- stringp=username;
- username = strsep(&stringp, ":");
- secret = strsep(&stringp, ":");
- }
- stringp=hname;
- if (strsep(&stringp, ":")) {
- stringp=hname;
- strsep(&stringp, ":");
- portno = strsep(&stringp, ":");
- }
- if (create_addr(&sin, NULL, NULL, NULL, hname, context)) {
- ast_log(LOG_WARNING, "No address associated with '%s'\n", hname);
- return -1;
- }
- /* Keep track of the context for outgoing calls too */
- strncpy(c->context, context, sizeof(c->context) - 1);
- if (portno) {
- sin.sin_port = htons(atoi(portno));
- }
- /* Now we build our request string */
- #define MYSNPRINTF snprintf(requeststr + strlen(requeststr), sizeof(requeststr) - strlen(requeststr),
- #define MYSNPRINTF2 snprintf(requeststr + strlen(requeststr), reqsize - strlen(requeststr),
- MYSNPRINTF "exten=%s;", rdest);
- if (c->callerid)
- MYSNPRINTF "callerid=%s;", c->callerid);
- if (p->sendani && c->ani)
- MYSNPRINTF "ani=%s;", c->ani);
- if (c->language && strlen(c->language))
- MYSNPRINTF "language=%s;", c->language);
- if (c->dnid)
- MYSNPRINTF "dnid=%s;", c->dnid);
- if (rcontext)
- MYSNPRINTF "context=%s;", rcontext);
- if (username)
- MYSNPRINTF "username=%s;", username);
- if (secret) {
- if (secret[0] == '[') {
- /* This is an RSA key, not a normal secret */
- strncpy(p->outkey, secret + 1, sizeof(p->secret)-1);
- if (strlen(p->outkey)) {
- p->outkey[strlen(p->outkey) - 1] = '\0';
- }
- } else
- strncpy(p->secret, secret, sizeof(p->secret)-1);
- }
- MYSNPRINTF "formats=%d;", c->nativeformats);
- MYSNPRINTF "capability=%d;", p->capability);
- MYSNPRINTF "version=%d;", AST_IAX_PROTO_VERSION);
- MYSNPRINTF "adsicpe=%d;", c->adsicpe);
- /* Trim the trailing ";" */
- if (strlen(requeststr))
- requeststr[strlen(requeststr) - 1] = '\0';
- /* Transmit the string in a "NEW" request */
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Calling using options '%s'\n", requeststr);
- if (p->maxtime) {
- /* Initialize pingtime and auto-congest time */
- p->pingtime = p->maxtime / 2;
- p->initid = ast_sched_add(sched, p->maxtime * 2, auto_congest, (void *)(long)p->callno);
- }
- send_command(p, AST_FRAME_IAX,
- AST_IAX_COMMAND_NEW, 0, requeststr, strlen(requeststr) + 1, -1);
- ast_setstate(c, AST_STATE_RINGING);
- return 0;
- }
- static int iax_hangup(struct ast_channel *c)
- {
- struct chan_iax_pvt *pvt = c->pvt->pvt;
- int alreadygone;
- int callno;
- if (pvt) {
- callno = pvt->callno;
- ast_mutex_lock(&iaxsl[callno]);
- ast_log(LOG_DEBUG, "We're hanging up %s now...\n", c->name);
- alreadygone = pvt->alreadygone;
- /* Send the hangup unless we have had a transmission error or are already gone */
- if (!pvt->error && !alreadygone)
- send_command_final(pvt, AST_FRAME_IAX, AST_IAX_COMMAND_HANGUP, 0, NULL, 0, -1);
- /* Explicitly predestroy it */
- iax_predestroy_nolock(callno);
- /* If we were already gone to begin with, destroy us now */
- if (alreadygone) {
- ast_log(LOG_DEBUG, "Really destroying %s now...\n", c->name);
- iax_destroy_nolock(callno);
- }
- ast_mutex_unlock(&iaxsl[callno]);
- }
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Hungup '%s'\n", c->name);
- return 0;
- }
- static int iax_setoption(struct ast_channel *c, int option, void *data, int datalen)
- {
- struct ast_option_header *h;
- int res;
- h = malloc(datalen + sizeof(struct ast_option_header));
- if (h) {
- h->flag = AST_OPTION_FLAG_REQUEST;
- h->option = htons(option);
- memcpy(h->data, data, datalen);
- res = send_command((struct chan_iax_pvt *)c->pvt->pvt, AST_FRAME_CONTROL,
- AST_CONTROL_OPTION, 0, (char *)h, datalen + sizeof(struct ast_option_header), -1);
- free(h);
- return res;
- } else
- ast_log(LOG_WARNING, "Out of memory\n");
- return -1;
- }
- static struct ast_frame *iax_read(struct ast_channel *c)
- {
- static struct ast_frame f = { AST_FRAME_NULL, };
- ast_log(LOG_NOTICE, "I should never be called!\n");
- return &f;
- }
- static int iax_start_transfer(struct ast_channel *c0, struct ast_channel *c1)
- {
- int res;
- char req0[256];
- char req1[256];
- char iabuf[INET_ADDRSTRLEN];
- struct chan_iax_pvt *p0 = c0->pvt->pvt;
- struct chan_iax_pvt *p1 = c1->pvt->pvt;
- snprintf(req0, sizeof(req0), "remip=%s;remport=%d;remcall=%d;", ast_inet_ntoa(iabuf, sizeof(iabuf), p1->addr.sin_addr), ntohs(p1->addr.sin_port), p1->peercallno);
- snprintf(req1, sizeof(req1), "remip=%s;remport=%d;remcall=%d;", ast_inet_ntoa(iabuf, sizeof(iabuf), p0->addr.sin_addr), ntohs(p0->addr.sin_port), p0->peercallno);
- res = send_command(p0, AST_FRAME_IAX, AST_IAX_COMMAND_TXREQ, 0, req0, strlen(req0) + 1, -1);
- if (res)
- return -1;
- res = send_command(p1, AST_FRAME_IAX, AST_IAX_COMMAND_TXREQ, 0, req1, strlen(req1) + 1, -1);
- if (res)
- return -1;
- p0->transferring = TRANSFER_BEGIN;
- p1->transferring = TRANSFER_BEGIN;
- return 0;
- }
- static int iax_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc)
- {
- struct ast_channel *cs[3];
- struct ast_channel *who;
- int to = -1;
- int res = -1;
- int transferstarted=0;
- struct ast_frame *f;
- struct chan_iax_pvt *p0 = c0->pvt->pvt;
- struct chan_iax_pvt *p1 = c1->pvt->pvt;
- /* Put them in native bridge mode */
- p0->bridgecallno = p1->callno;
- p1->bridgecallno = p0->callno;
- /* If not, try to bridge until we can execute a transfer, if we can */
- cs[0] = c0;
- cs[1] = c1;
- for (/* ever */;;) {
- /* Check in case we got masqueraded into */
- if ((c0->type != type) || (c1->type != type)) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Can't masquerade, we're different...\n");
- return -2;
- }
- if (c0->nativeformats != c1->nativeformats) {
- ast_verbose(VERBOSE_PREFIX_3 "Operating with different codecs, can't native bridge...\n");
- return -2;
- }
- if (!transferstarted) {
- /* Try the transfer */
- if (iax_start_transfer(c0, c1))
- ast_log(LOG_WARNING, "Unable to start the transfer\n");
- transferstarted = 1;
- }
-
- if ((p0->transferring == TRANSFER_RELEASED) && (p1->transferring == TRANSFER_RELEASED)) {
- /* Call has been transferred. We're no longer involved */
- sleep(1);
- c0->_softhangup |= AST_SOFTHANGUP_DEV;
- c1->_softhangup |= AST_SOFTHANGUP_DEV;
- *fo = NULL;
- *rc = c0;
- res = 0;
- break;
- }
- to = 1000;
- who = ast_waitfor_n(cs, 2, &to);
- if (!who) {
- if (ast_check_hangup(c0) || ast_check_hangup(c1)) {
- res = -1;
- break;
- }
- continue;
- }
- f = ast_read(who);
- if (!f) {
- *fo = NULL;
- *rc = who;
- res = 0;
- break;
- }
- if ((f->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) {
- *fo = f;
- *rc = who;
- res = 0;
- break;
- }
- if ((f->frametype == AST_FRAME_VOICE) ||
- (f->frametype == AST_FRAME_TEXT) ||
- (f->frametype == AST_FRAME_VIDEO) ||
- (f->frametype == AST_FRAME_IMAGE) ||
- (f->frametype == AST_FRAME_DTMF)) {
- if ((f->frametype == AST_FRAME_DTMF) &&
- (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))) {
- if ((who == c0)) {
- if ((flags & AST_BRIDGE_DTMF_CHANNEL_0)) {
- *rc = c0;
- *fo = f;
- /* Take out of conference mode */
- res = 0;
- break;
- } else
- goto tackygoto;
- } else
- if ((who == c1)) {
- if (flags & AST_BRIDGE_DTMF_CHANNEL_1) {
- *rc = c1;
- *fo = f;
- res = 0;
- break;
- } else
- goto tackygoto;
- }
- } else {
- #if 0
- ast_log(LOG_DEBUG, "Read from %s\n", who->name);
- if (who == last)
- ast_log(LOG_DEBUG, "Servicing channel %s twice in a row?\n", last->name);
- last = who;
- #endif
- tackygoto:
- if (who == c0)
- ast_write(c1, f);
- else
- ast_write(c0, f);
- }
- ast_frfree(f);
- } else
- ast_frfree(f);
- /* Swap who gets priority */
- cs[2] = cs[0];
- cs[0] = cs[1];
- cs[1] = cs[2];
- }
- p0->bridgecallno = -1;
- p1->bridgecallno = -1;
- return res;
- }
- static int iax_answer(struct ast_channel *c)
- {
- struct chan_iax_pvt *pvt = c->pvt->pvt;
- if (option_debug)
- ast_log(LOG_DEBUG, "Answering\n");
- return send_command(pvt, AST_FRAME_CONTROL, AST_CONTROL_ANSWER, 0, NULL, 0, -1);
- }
- static int iax_indicate(struct ast_channel *c, int condition)
- {
- struct chan_iax_pvt *pvt = c->pvt->pvt;
- if (option_debug)
- ast_log(LOG_DEBUG, "Indicating condition %d\n", condition);
- return send_command(pvt, AST_FRAME_CONTROL, condition, 0, NULL, 0, -1);
- }
-
- static int iax_write(struct ast_channel *c, struct ast_frame *f);
- static int iax_getpeername(struct sockaddr_in sin, char *host, int len)
- {
- struct iax_peer *peer;
- int res = 0;
- ast_mutex_lock(&peerl.lock);
- peer = peerl.peers;
- while(peer) {
- if ((peer->addr.sin_addr.s_addr == sin.sin_addr.s_addr) &&
- (peer->addr.sin_port == sin.sin_port)) {
- strncpy(host, peer->name, len-1);
- res = 1;
- break;
- }
- peer = peer->next;
- }
- ast_mutex_unlock(&peerl.lock);
- return res;
- }
- static struct ast_channel *ast_iax_new(struct chan_iax_pvt *i, int state, int capability)
- {
- char host[256];
- struct ast_channel *tmp;
- char iabuf[INET_ADDRSTRLEN];
- tmp = ast_channel_alloc(1);
- if (tmp) {
- if (!iax_getpeername(i->addr, host, sizeof(host)))
- snprintf(host, sizeof(host), "%s:%d", ast_inet_ntoa(iabuf, sizeof(iabuf), i->addr.sin_addr), ntohs(i->addr.sin_port));
- if (strlen(i->username))
- snprintf(tmp->name, sizeof(tmp->name), "IAX[%s@%s]/%d", i->username, host, i->callno);
- else
- snprintf(tmp->name, sizeof(tmp->name), "IAX[%s]/%d", host, i->callno);
- tmp->type = type;
- /* We can support any format by default, until we get restricted */
- tmp->nativeformats = capability;
- tmp->readformat = 0;
- tmp->writeformat = 0;
- tmp->pvt->pvt = i;
- tmp->pvt->send_digit = iax_digit;
- tmp->pvt->send_text = iax_sendtext;
- tmp->pvt->send_image = iax_sendimage;
- tmp->pvt->send_html = iax_sendhtml;
- tmp->pvt->call = iax_call;
- tmp->pvt->hangup = iax_hangup;
- tmp->pvt->answer = iax_answer;
- tmp->pvt->read = iax_read;
- tmp->pvt->write = iax_write;
- tmp->pvt->indicate = iax_indicate;
- tmp->pvt->setoption = iax_setoption;
- tmp->pvt->bridge = iax_bridge;
- if (strlen(i->callerid))
- tmp->callerid = strdup(i->callerid);
- if (strlen(i->ani))
- tmp->ani = strdup(i->ani);
- if (strlen(i->language))
- strncpy(tmp->language, i->language, sizeof(tmp->language)-1);
- if (strlen(i->dnid))
- tmp->dnid = strdup(i->dnid);
- if (strlen(i->accountcode))
- strncpy(tmp->accountcode, i->accountcode, sizeof(tmp->accountcode)-1);
- if (i->amaflags)
- tmp->amaflags = i->amaflags;
- strncpy(tmp->context, i->context, sizeof(tmp->context)-1);
- strncpy(tmp->exten, i->exten, sizeof(tmp->exten)-1);
- tmp->adsicpe = i->peeradsicpe;
- tmp->pvt->fixup = iax_fixup;
- i->owner = tmp;
- i->capability = capability;
- ast_setstate(tmp, state);
- ast_mutex_lock(&usecnt_lock);
- usecnt++;
- ast_mutex_unlock(&usecnt_lock);
- ast_update_use_count();
- if (state != AST_STATE_DOWN) {
- if (ast_pbx_start(tmp)) {
- ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
- ast_hangup(tmp);
- tmp = NULL;
- }
- }
- }
- return tmp;
- }
- static unsigned int calc_timestamp(struct chan_iax_pvt *p, unsigned int ts)
- {
- struct timeval tv;
- unsigned int ms;
- if (!p->offset.tv_sec && !p->offset.tv_usec)
- gettimeofday(&p->offset, NULL);
- /* If the timestamp is specified, just send it as is */
- if (ts)
- return ts;
- gettimeofday(&tv, NULL);
- ms = (tv.tv_sec - p->offset.tv_sec) * 1000 + (tv.tv_usec - p->offset.tv_usec) / 1000;
- /* We never send the same timestamp twice, so fudge a little if we must */
- if (ms <= p->lastsent)
- ms = p->lastsent + 1;
- p->lastsent = ms;
- return ms;
- }
- #ifdef BRIDGE_OPTIMIZATION
- static unsigned int calc_fakestamp(struct chan_iax_pvt *p1, struct chan_iax_pvt *p2, unsigned int fakets)
- {
- int ms;
- /* Receive from p1, send to p2 */
-
- /* Setup rxcore if necessary on outgoing channel */
- if (!p1->rxcore.tv_sec && !p1->rxcore.tv_usec)
- gettimeofday(&p1->rxcore, NULL);
- /* Setup txcore if necessary on outgoing channel */
- if (!p2->offset.tv_sec && !p2->offset.tv_usec)
- gettimeofday(&p2->offset, NULL);
-
- /* Now, ts is the timestamp of the original packet in the orignal context.
- Adding rxcore to it gives us when we would want the packet to be delivered normally.
- Subtracting txcore of the outgoing channel gives us what we'd expect */
-
- ms = (p1->rxcore.tv_sec - p2->offset.tv_sec) * 1000 + (p1->rxcore.tv_usec - p1->offset.tv_usec) / 1000;
- fakets += ms;
- if (fakets <= p2->lastsent)
- fakets = p2->lastsent + 1;
- p2->lastsent = fakets;
- return fakets;
- }
- #endif
- static unsigned int calc_rxstamp(struct chan_iax_pvt *p)
- {
- /* Returns where in "receive time" we are */
- struct timeval tv;
- unsigned int ms;
- /* Setup rxcore if necessary */
- if (!p->rxcore.tv_sec && !p->rxcore.tv_usec)
- gettimeofday(&p->rxcore, NULL);
- gettimeofday(&tv, NULL);
- ms = (tv.tv_sec - p->rxcore.tv_sec) * 1000 + (tv.tv_usec - p->rxcore.tv_usec) / 1000;
- return ms;
- }
- static int iax_send(struct chan_iax_pvt *pvt, struct ast_frame *f, unsigned int ts, int seqno, int now, int transfer, int final)
- {
- /* Queue a packet for delivery on a given private structure. Use "ts" for
- timestamp, or calculate if ts is 0. Send immediately without retransmission
- or delayed, with retransmission */
- struct ast_iax_full_hdr *fh;
- struct ast_iax_mini_hdr *mh;
- struct ast_iax_frame *fr, fr2;
- int res;
- unsigned int lastsent;
- /* Allocate an ast_iax_frame */
- if (now)
- fr = &fr2;
- else
- fr = ast_iax_frame_new(DIRECTION_OUTGRESS);
- if (!fr) {
- ast_log(LOG_WARNING, "Out of memory\n");
- return -1;
- }
- if (!pvt) {
- ast_log(LOG_WARNING, "No private structure for packet (%d)?\n", fr->callno);
- if (!now)
- ast_iax_frame_free(fr);
- return -1;
- }
- /* Isolate our frame for transmission */
- fr->f = ast_frdup(f);
- if (!fr->f) {
- ast_log(LOG_WARNING, "Out of memory\n");
- if (!now)
- ast_iax_frame_free(fr);
- return -1;
- }
- if (fr->f->offset < sizeof(struct ast_iax_full_hdr)) {
- ast_log(LOG_WARNING, "Packet from '%s' not friendly\n", fr->f->src);
- free(fr);
- return -1;
- }
- lastsent = pvt->lastsent;
- fr->ts = calc_timestamp(pvt, ts);
- if (!fr->ts) {
- ast_log(LOG_WARNING, "timestamp is 0?\n");
- if (!now)
- ast_iax_frame_free(fr);
- return -1;
- }
- fr->callno = pvt->callno;
- fr->transfer = transfer;
- fr->final = final;
- if (((fr->ts & 0xFFFF0000L) != (lastsent & 0xFFFF0000L))
- /* High two bits of timestamp differ */ ||
- (fr->f->frametype != AST_FRAME_VOICE)
- /* or not a voice frame */ ||
- (fr->f->subclass != pvt->svoiceformat)
- /* or new voice format */ ) {
- /* We need a full frame */
- if (seqno > -1)
- fr->seqno = seqno;
- else
- fr->seqno = pvt->oseqno++;
- fh = (struct ast_iax_full_hdr *)(fr->f->data - sizeof(struct ast_iax_full_hdr));
- fh->callno = htons(fr->callno | AST_FLAG_FULL);
- fh->ts = htonl(fr->ts);
- fh->seqno = htons(fr->seqno);
- fh->type = fr->f->frametype & 0xFF;
- fh->csub = compress_subclass(fr->f->subclass);
- if (transfer) {
- fh->dcallno = htons(pvt->transfercallno);
- } else
- fh->dcallno = htons(pvt->peercallno);
- fr->datalen = fr->f->datalen + sizeof(struct ast_iax_full_hdr);
- fr->data = fh;
- fr->retries = 0;
- /* Retry after 2x the ping time has passed */
- fr->retrytime = pvt->pingtime * 2;
- if (fr->retrytime < MIN_RETRY_TIME)
- fr->retrytime = MIN_RETRY_TIME;
- if (fr->retrytime > MAX_RETRY_TIME)
- fr->retrytime = MAX_RETRY_TIME;
- /* Acks' don't get retried */
- if ((f->frametype == AST_FRAME_IAX) && (f->subclass == AST_IAX_COMMAND_ACK))
- fr->retries = -1;
- if (f->frametype == AST_FRAME_VOICE) {
- pvt->svoiceformat = f->subclass;
- }
- if (now) {
- res = send_packet(fr);
- ast_frfree(fr->f);
- } else
- res = iax_transmit(fr);
- } else {
- /* Mini-frames have no sequence number */
- fr->seqno = -1;
- /* Mini frame will do */
- mh = (struct ast_iax_mini_hdr *)(fr->f->data - sizeof(struct ast_iax_mini_hdr));
- mh->callno = htons(fr->callno);
- mh->ts = htons(fr->ts & 0xFFFF);
- fr->datalen = fr->f->datalen + sizeof(struct ast_iax_mini_hdr);
- fr->data = mh;
- fr->retries = -1;
- if (now) {
- res = send_packet(fr);
- ast_frfree(fr->f);
- } else
- res = iax_transmit(fr);
- }
- return res;
- }
- static int iax_show_users(int fd, int argc, char *argv[])
- {
- #define FORMAT "%-15.15s %-15.15s %-15.15s %-15.15s %-5.5s\n"
- struct iax_user *user;
- if (argc != 3)
- return RESULT_SHOWUSAGE;
- ast_mutex_lock(&userl.lock);
- ast_cli(fd, FORMAT, "Username", "Secret", "Authen", "Def.Context", "A/C");
- for(user=userl.users;user;user=user->next) {
- ast_cli(fd, FORMAT, user->name, user->secret, user->methods,
- user->contexts ? user->contexts->context : context,
- user->ha ? "Yes" : "No");
- }
- ast_mutex_unlock(&userl.lock);
- return RESULT_SUCCESS;
- #undef FORMAT
- }
- static int iax_show_peers(int fd, int argc, char *argv[])
- {
- #define FORMAT2 "%-15.15s %-15.15s %s %-15.15s %-8s %-10s\n"
- #define FORMAT "%-15.15s %-15.15s %s %-15.15s %-8d %-10s\n"
- struct iax_peer *peer;
- char name[256] = "";
- char iabuf[INET_ADDRSTRLEN];
- if (argc != 3)
- return RESULT_SHOWUSAGE;
- ast_mutex_lock(&peerl.lock);
- ast_cli(fd, FORMAT2, "Name/Username", "Host", " ", "Mask", "Port", "Status");
- for (peer = peerl.peers;peer;peer = peer->next) {
- char nm[20];
- char status[20] = "";
- if (strlen(peer->username))
- snprintf(name, sizeof(name), "%s/%s", peer->name, peer->username);
- else
- strncpy(name, peer->name, sizeof(name) - 1);
- if (peer->maxms) {
- if (peer->lastms < 0)
- strncpy(status, "UNREACHABLE", sizeof(status) - 1);
- else if (peer->lastms > peer->maxms)
- snprintf(status, sizeof(status), "LAGGED (%d ms)", peer->lastms);
- else if (peer->lastms)
- snprintf(status, sizeof(status), "OK (%d ms)", peer->lastms);
- else
- strncpy(status, "UNKNOWN", sizeof(status) - 1);
- } else
- strncpy(status, "Unmonitored", sizeof(status) - 1);
- strncpy(nm, ast_inet_ntoa(iabuf, sizeof(iabuf), peer->mask), sizeof(nm)-1);
- ast_cli(fd, FORMAT, name,
- peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "(Unspecified)",
- peer->dynamic ? "(D)" : "(S)",
- nm,
- ntohs(peer->addr.sin_port), status);
- }
- ast_mutex_unlock(&peerl.lock);
- return RESULT_SUCCESS;
- #undef FORMAT
- #undef FORMAT2
- }
- /* JDG: callback to display iax peers in manager */
- static int manager_iax_show_peers( struct mansession *s, struct message *m )
- {
- char *a[] = { "iax", "show", "users" };
- int ret;
- ret = iax_show_peers( s->fd, 3, a );
- ast_cli( s->fd, "\r\n" );
- return ret;
- } /* /JDG */
- static char *regstate2str(int regstate)
- {
- switch(regstate) {
- case REG_STATE_UNREGISTERED:
- return "Unregistered";
- case REG_STATE_REGSENT:
- return "Request Sent";
- case REG_STATE_AUTHSENT:
- return "Auth. Sent";
- case REG_STATE_REGISTERED:
- return "Registered";
- case REG_STATE_REJECTED:
- return "Rejected";
- case REG_STATE_TIMEOUT:
- return "Timeout";
- case REG_STATE_NOAUTH:
- return "No Authentication";
- default:
- return "Unknown";
- }
- }
- static int iax_show_registry(int fd, int argc, char *argv[])
- {
- #define FORMAT2 "%-20.20s %-10.10s %-20.20s %8.8s %s\n"
- #define FORMAT "%-20.20s %-10.10s %-20.20s %8d %s\n"
- struct iax_registry *reg;
- char host[80];
- char perceived[80] = "";
- char iabuf[INET_ADDRSTRLEN];
- if (argc != 3)
- return RESULT_SHOWUSAGE;
- ast_mutex_lock(&peerl.lock);
- ast_cli(fd, FORMAT2, "Host", "Username", "Perceived", "Refresh", "State");
- for (reg = registrations;reg;reg = reg->next) {
- snprintf(host, sizeof(host), "%s:%d", ast_inet_ntoa(iabuf, sizeof(iabuf), reg->addr.sin_addr), ntohs(reg->addr.sin_port));
- if (reg->us.sin_addr.s_addr)
- snprintf(perceived, sizeof(perceived), "%s:%d", ast_inet_ntoa(iabuf, sizeof(iabuf), reg->us.sin_addr), ntohs(reg->us.sin_port));
- else
- strncpy(perceived, "<Unregistered>", sizeof(perceived) - 1);
- ast_cli(fd, FORMAT, host,
- reg->username, perceived, reg->refresh, regstate2str(reg->regstate));
- }
- ast_mutex_unlock(&peerl.lock);
- return RESULT_SUCCESS;
- #undef FORMAT
- #undef FORMAT2
- }
- static int iax_show_channels(int fd, int argc, char *argv[])
- {
- #define FORMAT2 "%-15.15s %-10.10s %-11.11s %-11.11s %-7.7s %-6.6s %s\n"
- #define FORMAT "%-15.15s %-10.10s %5.5d/%5.5d %5.5d/%5.5d %-5.5dms %-4.4dms %-6.6s\n"
- int x;
- int numchans = 0;
- char iabuf[INET_ADDRSTRLEN];
- if (argc != 3)
- return RESULT_SHOWUSAGE;
- ast_cli(fd, FORMAT2, "Peer", "Username", "ID (Lo/Rem)", "Seq (Tx/Rx)", "Lag", "Jitter", "Format");
- for (x=0;x<AST_IAX_MAX_CALLS;x++) {
- ast_mutex_lock(&iaxsl[x]);
- if (iaxs[x]) {
- ast_cli(fd, FORMAT, ast_inet_ntoa(iabuf, sizeof(iabuf), iaxs[x]->addr.sin_addr),
- strlen(iaxs[x]->username) ? iaxs[x]->username : "(None)",
- iaxs[x]->callno, iaxs[x]->peercallno,
- iaxs[x]->oseqno, iaxs[x]->iseqno,
- iaxs[x]->lag,
- iaxs[x]->jitter,
- ast_getformatname(iaxs[x]->voiceformat) );
- numchans++;
- }
- ast_mutex_unlock(&iaxsl[x]);
- }
- ast_cli(fd, "%d active IAX channel(s)\n", numchans);
- return RESULT_SUCCESS;
- #undef FORMAT
- #undef FORMAT2
- }
- static int iax_do_debug(int fd, int argc, char *argv[])
- {
- if (argc != 2)
- return RESULT_SHOWUSAGE;
- iaxdebug = 1;
- ast_cli(fd, "IAX Debugging Enabled\n");
- return RESULT_SUCCESS;
- }
- static int iax_no_debug(int fd, int argc, char *argv[])
- {
- if (argc != 3)
- return RESULT_SHOWUSAGE;
- iaxdebug = 0;
- ast_cli(fd, "IAX Debugging Disabled\n");
- return RESULT_SUCCESS;
- }
- static char show_users_usage[] =
- "Usage: iax1 show users\n"
- " Lists all users known to the IAX (Inter-Asterisk eXchange) subsystem.\n";
- static char show_channels_usage[] =
- "Usage: iax1 show channels\n"
- " Lists all currently active IAX channels.\n";
- static char show_peers_usage[] =
- "Usage: iax1 show peers\n"
- " Lists all known IAX peers.\n";
- static char show_reg_usage[] =
- "Usage: iax1 show registry\n"
- " Lists all registration requests and status.\n";
- #ifdef DEBUG_SUPPORT
- static char debug_usage[] =
- "Usage: iax1 debug\n"
- " Enables dumping of IAX packets for debugging purposes\n";
- static char no_debug_usage[] =
- "Usage: iax1 no debug\n"
- " Disables dumping of IAX packets for debugging purposes\n";
- #endif
- static struct ast_cli_entry cli_show_users =
- { { "iax1", "show", "users", NULL }, iax_show_users, "Show defined IAX users", show_users_usage };
- static struct ast_cli_entry cli_show_channels =
- { { "iax1", "show", "channels", NULL }, iax_show_channels, "Show active IAX channels", show_channels_usage };
- static struct ast_cli_entry cli_show_peers =
- { { "iax1", "show", "peers", NULL }, iax_show_peers, "Show defined IAX peers", show_peers_usage };
- static struct ast_cli_entry cli_show_registry =
- { { "iax1", "show", "registry", NULL }, iax_show_registry, "Show IAX registration status", show_reg_usage };
- static struct ast_cli_entry cli_debug =
- { { "iax1", "debug", NULL }, iax_do_debug, "Enable IAX debugging", debug_usage };
- static struct ast_cli_entry cli_no_debug =
- { { "iax1", "no", "debug", NULL }, iax_no_debug, "Disable IAX debugging", no_debug_usage };
- static int iax_write(struct ast_channel *c, struct ast_frame *f)
- {
- struct chan_iax_pvt *i = c->pvt->pvt;
- if (!i)
- return -1;
- /* If there's an outstanding error, return failure now */
- if (i->error) {
- ast_log(LOG_DEBUG, "Write error: %s\n", strerror(errno));
- return -1;
- }
- /* If it's already gone, just return */
- if (i->alreadygone)
- return 0;
- /* Don't waste bandwidth sending null frames */
- if (f->frametype == AST_FRAME_NULL)
- return 0;
- /* If we're quelching voice, don't bother sending it */
- if ((f->frametype == AST_FRAME_VOICE) && i->quelch)
- return 0;
- /* Simple, just queue for transmission */
- return iax_send(i, f, 0, -1, 0, 0, 0);
- }
- static int __send_command(struct chan_iax_pvt *i, char type, int command, unsigned int ts, char *data, int datalen, int seqno,
- int now, int transfer, int final)
- {
- struct ast_frame f;
- f.frametype = type;
- f.subclass = command;
- f.datalen = datalen;
- f.samples = 0;
- f.mallocd = 0;
- f.offset = 0;
- f.src = __FUNCTION__;
- f.data = data;
- return iax_send(i, &f, ts, seqno, now, transfer, final);
- }
- static int send_command(struct chan_iax_pvt *i, char type, int command, unsigned int ts, char *data, int datalen, int seqno)
- {
- return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 0);
- }
- #ifdef BRIDGE_OPTIMIZATION
- static int forward_command(struct chan_iax_pvt *i, char type, int command, unsigned int ts, char *data, int datalen, int seqno)
- {
- return __send_command(iaxs[i->bridgecallno], type, command, ts, data, datalen, seqno, 0, 0, 0);
- }
- #endif
- static int send_command_final(struct chan_iax_pvt *i, char type, int command, unsigned int ts, char *data, int datalen, int seqno)
- {
- /* It is assumed that the callno has already been locked */
- iax_predestroy_nolock(i->callno);
- return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 1);
- }
- static int send_command_immediate(struct chan_iax_pvt *i, char type, int command, unsigned int ts, char *data, int datalen, int seqno)
- {
- return __send_command(i, type, command, ts, data, datalen, seqno, 1, 0, 0);
- }
- static int send_command_transfer(struct chan_iax_pvt *i, char type, int command, unsigned int ts, char *data, int datalen)
- {
- return __send_command(i, type, command, ts, data, datalen, 0, 0, 1, 0);
- }
- static int apply_context(struct iax_context *con, char *context)
- {
- while(con) {
- if (!strcmp(con->context, context))
- return -1;
- con = con->next;
- }
- return 0;
- }
- static int iax_getformats(int callno, char *orequest)
- {
- char *var, *value;
- char request[256];
- char *stringp=NULL;
- strncpy(request, orequest, sizeof(request)-1);
- stringp=request;
- var = strsep(&stringp, ";");
- while(var) {
- value = strchr(var, '=');
- if (value) {
- *value='\0';
- value++;
- if (!strcmp(var, "formats")) {
- iaxs[callno]->peerformat = atoi(value);
- } else
- ast_log(LOG_WARNING, "Unknown variable '%s' with value '%s'\n", var, value);
- }
- var = strsep(&stringp, ";");
- }
- return 0;
- }
- static int check_access(int callno, struct sockaddr_in *sin, char *orequest, int requestl)
- {
- /* Start pessimistic */
- int res = -1;
- int version = 1;
- char *var, *value;
- struct iax_user *user;
- char request[256];
- char iabuf[INET_ADDRSTRLEN];
- int gotcapability=0;
- char *stringp=NULL;
- strncpy(request, orequest, sizeof(request)-1);
- if (!iaxs[callno])
- return res;
- stringp=request;
- var = strsep(&stringp, ";");
- while(var) {
- value = strchr(var, '=');
- if (value) {
- *value='\0';
- value++;
- if (!strcmp(var, "exten"))
- strncpy(iaxs[callno]->exten, value, sizeof(iaxs[callno]->exten)-1);
- else if (!strcmp(var, "callerid"))
- strncpy(iaxs[callno]->callerid, value, sizeof(iaxs[callno]->callerid)-1);
- else if (!strcmp(var, "ani"))
- strncpy(iaxs[callno]->ani, value, sizeof(iaxs[callno]->ani) - 1);
- else if (!strcmp(var, "dnid"))
- strncpy(iaxs[callno]->dnid, value, sizeof(iaxs[callno]->dnid)-1);
- else if (!strcmp(var, "context"))
- strncpy(iaxs[callno]->context, value, sizeof(iaxs[callno]->context)-1);
- else if (!strcmp(var, "language"))
- strncpy(iaxs[callno]->language, value, sizeof(iaxs[callno]->language)-1);
- else if (!strcmp(var, "username"))
- strncpy(iaxs[callno]->username, value, sizeof(iaxs[callno]->username)-1);
- else if (!strcmp(var, "formats"))
- iaxs[callno]->peerformat = atoi(value);
- else if (!strcmp(var, "adsicpe"))
- iaxs[callno]->peeradsicpe = atoi(value);
- else if (!strcmp(var, "capability")) {
- gotcapability = 1;
- iaxs[callno]->peercapability = atoi(value);
- } else if (!strcmp(var, "version"))
- version = atoi(value);
- else
- ast_log(LOG_WARNING, "Unknown variable '%s' with value '%s'\n", var, value);
- }
- var = strsep(&stringp, ";");
- }
- if (!gotcapability)
- iaxs[callno]->peercapability = iaxs[callno]->peerformat;
- if (version > AST_IAX_PROTO_VERSION) {
- ast_log(LOG_WARNING, "Peer '%s' has too new a protocol version (%d) for me\n",
- ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), version);
- return res;
- }
- ast_mutex_lock(&userl.lock);
- /* Search the userlist for a compatible entry, and fill in the rest */
- user = userl.users;
- while(user) {
- if ((!strlen(iaxs[callno]->username) || /* No username specified */
- !strcmp(iaxs[callno]->username, user->name)) /* Or this username specified */
- && ast_apply_ha(user->ha, sin) /* Access is permitted from this IP */
- && (!strlen(iaxs[callno]->context) || /* No context specified */
- apply_context(user->contexts, iaxs[callno]->context))) { /* Context is permitted */
- break;
- }
- user = user->next;
- }
- #ifdef MYSQL_FRIENDS
- if (!user && mysql && strlen(iaxs[callno]->username) && (strlen(iaxs[callno]->username) < 128)) {
- user = mysql_user(iaxs[callno]->username);
- if (user && strlen(iaxs[callno]->context) && /* No context specified */
- !apply_context(user->contexts, iaxs[callno]->context)) { /* Context is permitted */
- if (user->contexts)
- free(user->contexts);
- free(user);
- user = NULL;
- }
- }
- #endif
- ast_mutex_unlock(&userl.lock);
- if (user) {
- /* We found our match (use the first) */
-
- /* Store the requested username if not specified */
- if (!strlen(iaxs[callno]->username))
- strncpy(iaxs[callno]->username, user->name, sizeof(iaxs[callno]->username)-1);
- /* And use the default context */
- if (!strlen(iaxs[callno]->context)) {
- if (user->contexts)
- strncpy(iaxs[callno]->context, user->contexts->context, sizeof(iaxs[callno]->context)-1);
- else
- strncpy(iaxs[callno]->context, context, sizeof(iaxs[callno]->context)-1);
- }
- /* Copy the secret */
- strncpy(iaxs[callno]->secret, user->secret, sizeof(iaxs[callno]->secret)-1);
- /* And any input keys */
- strncpy(iaxs[callno]->inkeys, user->inkeys, sizeof(iaxs[callno]->inkeys) - 1);
- /* And the permitted authentication methods */
- strncpy(iaxs[callno]->methods, user->methods, sizeof(iaxs[callno]->methods)-1);
- /* If they have callerid, override the given caller id. Always store the ANI */
- if (strlen(iaxs[callno]->callerid)) {
- if (user->hascallerid)
- strncpy(iaxs[callno]->callerid, user->callerid, sizeof(iaxs[callno]->callerid)-1);
- strncpy(iaxs[callno]->ani, user->callerid, sizeof(iaxs[callno]->ani)-1);
- }
- if (strlen(user->accountcode))
- strncpy(iaxs[callno]->accountcode, user->accountcode, sizeof(iaxs[callno]->accountcode)-1);
- if (user->amaflags)
- iaxs[callno]->amaflags = user->amaflags;
- res = 0;
- }
- return res;
- }
- static int raw_hangup(struct sockaddr_in *sin, short src, short dst)
- {
- struct ast_iax_full_hdr fh;
- char iabuf[INET_ADDRSTRLEN];
- fh.callno = htons(src | AST_FLAG_FULL);
- fh.dcallno = htons(dst);
- fh.ts = 0;
- fh.seqno = 0;
- fh.type = AST_FRAME_IAX;
- fh.csub = compress_subclass(AST_IAX_COMMAND_INVAL);
- #if 0
- if (option_debug)
- #endif
- ast_log(LOG_DEBUG, "Raw Hangup %s:%d, src=%d, dst=%d\n",
- ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port), src, dst);
- return sendto(netsocket, &fh, sizeof(fh), 0, (struct sockaddr *)sin, sizeof(*sin));
- }
- static int authenticate_request(struct chan_iax_pvt *p)
- {
- char requeststr[256] = "";
- MYSNPRINTF "methods=%s;", p->methods);
- if (strstr(p->methods, "md5") || strstr(p->methods, "rsa")) {
- /* Build the challenge */
- snprintf(p->challenge, sizeof(p->challenge), "%d", rand());
- MYSNPRINTF "challenge=%s;", p->challenge);
- }
- MYSNPRINTF "username=%s;", p->username);
- if (strlen(requeststr))
- requeststr[strlen(requeststr) - 1] = '\0';
- return send_command(p, AST_FRAME_IAX, AST_IAX_COMMAND_AUTHREQ, 0, requeststr, strlen(requeststr) + 1, -1);
- }
- static int authenticate_verify(struct chan_iax_pvt *p, char *orequest)
- {
- char requeststr[256] = "";
- char *var, *value, request[256];
- char md5secret[256] = "";
- char secret[256] = "";
- char rsasecret[256] = "";
- int res = -1;
- int x;
- char *stringp=NULL;
-
- if (!(p->state & IAX_STATE_AUTHENTICATED))
- return res;
- strncpy(request, orequest, sizeof(request)-1);
- stringp=request;
- var = strsep(&stringp, ";");
- while(var) {
- value = strchr(var, '=');
- if (value) {
- *value='\0';
- value++;
- if (!strcmp(var, "secret"))
- strncpy(secret, value, sizeof(secret)-1);
- else if (!strcmp(var, "md5secret"))
- strncpy(md5secret, value, sizeof(md5secret)-1);
- else if (!strcmp(var, "rsasecret"))
- strncpy(rsasecret, value, sizeof(rsasecret)-1);
- else
- ast_log(LOG_WARNING, "Unknown variable '%s' with value '%s'\n", var, value);
- }
- var = strsep(&stringp, ";");
- }
- if (strstr(p->methods, "rsa") && strlen(rsasecret) && strlen(p->inkeys)) {
- struct ast_key *key;
- char *keyn;
- char tmpkey[256] = "";
- char *stringp=NULL;
- strncpy(tmpkey, p->inkeys, sizeof(tmpkey) - 1);
- stringp=tmpkey;
- keyn = strsep(&stringp, ":");
- while(keyn) {
- key = ast_key_get(keyn, AST_KEY_PUBLIC);
- if (key && !ast_check_signature(key, p->challenge, rsasecret)) {
- res = 0;
- break;
- } else if (!key)
- ast_log(LOG_WARNING, "requested inkey '%s' for RSA authentication does not exist\n", keyn);
- keyn = strsep(&stringp, ":");
- }
- } else if (strstr(p->methods, "md5")) {
- struct MD5Context md5;
- unsigned char digest[16];
- MD5Init(&md5);
- MD5Update(&md5, p->challenge, strlen(p->challenge));
- MD5Update(&md5, p->secret, strlen(p->secret));
- MD5Final(digest, &md5);
- /* If they support md5, authenticate with it. */
- for (x=0;x<16;x++)
- MYSNPRINTF "%2.2x", digest[x]);
- if (!strcasecmp(requeststr, md5secret))
- res = 0;
- } else if (strstr(p->methods, "plaintext")) {
- if (!strcmp(secret, p->secret))
- res = 0;
- }
- return res;
- }
- static int register_verify(int callno, struct sockaddr_in *sin, char *orequest)
- {
- char request[256];
- char requeststr[256] = "";
- char peer[256] = "";
- char md5secret[256] = "";
- char rsasecret[256] = "";
- char secret[256] = "";
- char iabuf[INET_ADDRSTRLEN];
- struct iax_peer *p;
- struct ast_key *key;
- char *var;
- char *value;
- char *keyn;
- int x;
- int expire = 0;
- char *stringp=NULL;
- iaxs[callno]->state &= ~IAX_STATE_AUTHENTICATED;
- iaxs[callno]->peer[0] = '\0';
- if (!orequest)
- return -1;
- strncpy(request, orequest, sizeof(request)-1);
- stringp=request;
- var = strsep(&stringp, ";");
- while(var) {
- value = strchr(var, '=');
- if (value) {
- *value='\0';
- value++;
- if (!strcmp(var, "peer"))
- strncpy(peer, value, sizeof(peer)-1);
- else if (!strcmp(var, "md5secret"))
- strncpy(md5secret, value, sizeof(md5secret)-1);
- else if (!strcmp(var, "rsasecret"))
- strncpy(rsasecret, value, sizeof(rsasecret)-1);
- else if (!strcmp(var, "secret"))
- strncpy(secret, value, sizeof(secret)-1);
- else if (!strcmp(var, "refresh"))
- expire = atoi(value);
- else
- ast_log(LOG_WARNING, "Unknown variable '%s' with value '%s'\n", var, value);
- }
- var = strsep(&stringp, ";");
- }
- if (!strlen(peer)) {
- ast_log(LOG_NOTICE, "Empty registration from %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr));
- return -1;
- }
- for (p = peerl.peers; p ; p = p->next)
- if (!strcasecmp(p->name, peer))
- break;
- #ifdef MYSQL_FRIENDS
- if (!p)
- p = mysql_peer(peer);
- #endif
- if (!p) {
- ast_log(LOG_NOTICE, "No registration for peer '%s' (from %s)\n", peer, ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr));
- return -1;
- }
- if (!p->dynamic) {
- ast_log(LOG_NOTICE, "Peer '%s' is not dynamic (from %s)\n", peer, ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr));
- if (p->delme)
- free(p);
- return -1;
- }
- if (!ast_apply_ha(p->ha, sin)) {
- ast_log(LOG_NOTICE, "Host %s denied access to register peer '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), p->name);
- if (p->delme)
- free(p);
- return -1;
- }
- strncpy(iaxs[callno]->secret, p->secret, sizeof(iaxs[callno]->secret)-1);
- strncpy(iaxs[callno]->inkeys, p->inkeys, sizeof(iaxs[callno]->inkeys)-1);
- /* Check secret against what we have on file */
- if (strlen(rsasecret) && strstr(p->methods, "rsa") && strlen(iaxs[callno]->challenge)) {
- if (strlen(p->inkeys)) {
- char tmpkeys[256];
- char *stringp=NULL;
- strncpy(tmpkeys, p->inkeys, sizeof(tmpkeys) - 1);
- stringp=tmpkeys;
- keyn = strsep(&stringp, ":");
- while(keyn) {
- key = ast_key_get(keyn, AST_KEY_PUBLIC);
- if (key && !ast_check_signature(key, iaxs[callno]->challenge, rsasecret)) {
- iaxs[callno]->state |= IAX_STATE_AUTHENTICATED;
- break;
- } else if (!key)
- ast_log(LOG_WARNING, "requested inkey '%s' does not exist\n", keyn);
- keyn = strsep(&stringp, ":");
- }
- if (!keyn) {
- ast_log(LOG_NOTICE, "Host %s failed RSA authentication with inkeys '%s'\n", peer, p->inkeys);
- if (p->delme)
- free(p);
- return -1;
- }
- } else {
- ast_log(LOG_NOTICE, "Host '%s' trying to do RSA authentication, but we have no inkeys\n", peer);
- if (p->delme)
- free(p);
- return -1;
- }
- } else if (strlen(secret) && strstr(p->methods, "plaintext")) {
- /* They've provided a plain text password and we support that */
- if (strcmp(secret, p->secret)) {
- ast_log(LOG_NOTICE, "Host %s did not provide proper plaintext password for '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), p->name);
- if (p->delme)
- free(p);
- return -1;
- } else
- iaxs[callno]->state |= IAX_STATE_AUTHENTICATED;
- } else if (strlen(md5secret) && strstr(p->methods, "md5") && strlen(iaxs[callno]->challenge)) {
- struct MD5Context md5;
- unsigned char digest[16];
- MD5Init(&md5);
- MD5Update(&md5, iaxs[callno]->challenge, strlen(iaxs[callno]->challenge));
- MD5Update(&md5, p->secret, strlen(p->secret));
- MD5Final(digest, &md5);
- for (x=0;x<16;x++)
- MYSNPRINTF "%2.2x", digest[x]);
- if (strcasecmp(requeststr, md5secret)) {
- ast_log(LOG_NOTICE, "Host %s failed MD5 authentication for '%s' (%s != %s)\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), p->name, requeststr, md5secret);
- if (p->delme)
- free(p);
- return -1;
- } else
- iaxs[callno]->state |= IAX_STATE_AUTHENTICATED;
- } else if (strlen(md5secret) || strlen(secret)) {
- ast_log(LOG_NOTICE, "Inappropriate authentication received\n");
- if (p->delme)
- free(p);
- return -1;
- }
- strncpy(iaxs[callno]->peer, peer, sizeof(iaxs[callno]->peer)-1);
- /* Choose lowest expirey number */
- if (expire && (expire < iaxs[callno]->expirey))
- iaxs[callno]->expirey = expire;
- if (p->delme)
- free(p);
- return 0;
-
- }
- static int authenticate(char *challenge, char *secret, char *keyn, char *methods, char *requeststr, int reqsize, struct sockaddr_in *sin)
- {
- int res = -1;
- int x;
- char iabuf[INET_ADDRSTRLEN];
- if (keyn && strlen(keyn)) {
- if (!strstr(methods, "rsa")) {
- if (!secret || !strlen(secret))
- ast_log(LOG_NOTICE, "Asked to authenticate to %s with an RSA key, but they don't allow RSA authentication\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr));
- } else if (!strlen(challenge)) {
- ast_log(LOG_NOTICE, "No challenge provided for RSA authentication to %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr));
- } else {
- char sig[256];
- struct ast_key *key;
- key = ast_key_get(keyn, AST_KEY_PRIVATE);
- if (!key) {
- ast_log(LOG_NOTICE, "Unable to find private key '%s'\n", keyn);
- } else {
- if (ast_sign(key, challenge, sig)) {
- ast_log(LOG_NOTICE, "Unable to sign challenge withy key\n");
- res = -1;
- } else {
- MYSNPRINTF2 "rsasecret=%s;", sig);
- res = 0;
- }
- }
- }
- }
- /* Fall back */
- if (res && secret && strlen(secret)) {
- if (strstr(methods, "md5") && strlen(challenge)) {
- struct MD5Context md5;
- unsigned char digest[16];
- MD5Init(&md5);
- MD5Update(&md5, challenge, strlen(challenge));
- MD5Update(&md5, secret, strlen(secret));
- MD5Final(digest, &md5);
- /* If they support md5, authenticate with it. */
- MYSNPRINTF2 "md5secret=");
- for (x=0;x<16;x++)
- MYSNPRINTF2 "%2.2x", digest[x]);
- MYSNPRINTF2 ";");
- res = 0;
- } else if (strstr(methods, "plaintext")) {
- MYSNPRINTF2 "secret=%s;", secret);
- res = 0;
- } else
- ast_log(LOG_NOTICE, "No way to send secret to peer '%s' (their methods: %s)\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), methods);
- }
- return res;
- }
- static int authenticate_reply(struct chan_iax_pvt *p, struct sockaddr_in *sin, char *orequest, char *override, char *okey)
- {
- struct iax_peer *peer;
- /* Start pessimistic */
- int res = -1;
- char request[256];
- char methods[80] = "";
- char requeststr[256] = "";
- char *var, *value;
- char *stringp=NULL;
-
- strncpy(request, orequest, sizeof(request)-1);
- stringp=request;
- var = strsep(&stringp, ";");
- while(var) {
- value = strchr(var, '=');
- if (value) {
- *value='\0';
- value++;
- if (!strcmp(var, "username"))
- strncpy(p->username, value, sizeof(p->username)-1);
- else if (!strcmp(var, "challenge"))
- strncpy(p->challenge, value, sizeof(p->challenge)-1);
- else if (!strcmp(var, "methods"))
- strncpy(methods, value, sizeof(methods)-1);
- else
- ast_log(LOG_WARNING, "Unknown variable '%s' with value '%s'\n", var, value);
- }
- var = strsep(&stringp, ";");
- }
- /* Check for override RSA authentication first */
- if ((override && strlen(override)) || (okey && strlen(okey))) {
- /* Normal password authentication */
- res = authenticate(p->challenge, override, okey, methods, requeststr, sizeof(requeststr), sin);
- } else {
- ast_mutex_lock(&peerl.lock);
- peer = peerl.peers;
- while(peer) {
- if ((!strlen(p->peer) || !strcmp(p->peer, peer->name))
- /* No peer specified at our end, or this is the peer */
- && (!strlen(peer->username) || (!strcmp(peer->username, p->username)))
- /* No username specified in peer rule, or this is the right username */
- && (!peer->addr.sin_addr.s_addr || ((sin->sin_addr.s_addr & peer->mask.s_addr) == (peer->addr.sin_addr.s_addr & peer->mask.s_addr)))
- /* No specified host, or this is our host */
- ) {
- res = authenticate(p->challenge, peer->secret, peer->outkey, methods, requeststr, sizeof(requeststr), sin);
- if (!res)
- break;
- }
- peer = peer->next;
- }
- ast_mutex_unlock(&peerl.lock);
- }
- if (strlen(requeststr))
- requeststr[strlen(requeststr)-1] = '\0';
- if (!res)
- res = send_command(p, AST_FRAME_IAX, AST_IAX_COMMAND_AUTHREP, 0, requeststr, strlen(requeststr) + 1, -1);
- return res;
- }
- static int iax_do_register(struct iax_registry *reg);
- static int iax_do_register_s(void *data)
- {
- struct iax_registry *reg = data;
- reg->expire = -1;
- iax_do_register(reg);
- return 0;
- }
- static int try_transfer(struct chan_iax_pvt *pvt, char *orequest)
- {
- int newport = 0;
- int newcall = 0;
- char newip[256] = "";
- char request[256] = "";
- char *var, *value;
-
- struct sockaddr_in new;
- char *stringp=NULL;
-
- if (!orequest)
- return -1;
- strncpy(request, orequest, sizeof(request)-1);
- stringp=request;
- var = strsep(&stringp, ";");
- while(var) {
- value = strchr(var, '=');
- if (value) {
- *value='\0';
- value++;
- if (!strcmp(var, "remip"))
- strncpy(newip, value, sizeof(newip)-1);
- else if (!strcmp(var, "remport"))
- newport = atoi(value);
- else if (!strcmp(var, "remcall"))
- newcall = atoi(value);
- else
- ast_log(LOG_WARNING, "Unknown variable '%s' with value '%s'\n", var, value);
- }
- var = strsep(&stringp, ";");
- }
- if (!newcall || !inet_aton(newip, &new.sin_addr) || !newport) {
- ast_log(LOG_WARNING, "Invalid transfer request\n");
- return -1;
- }
- pvt->transfercallno = newcall;
- inet_aton(newip, &pvt->transfer.sin_addr);
- pvt->transfer.sin_port = htons(newport);
- pvt->transfer.sin_family = AF_INET;
- pvt->transferring = TRANSFER_BEGIN;
- send_command_transfer(pvt, AST_FRAME_IAX, AST_IAX_COMMAND_TXCNT, 0, NULL, 0);
- return 0;
- }
- static int complete_dpreply(struct chan_iax_pvt *pvt, char *orequest)
- {
- char *var, *value;
- char request[256] = "";
- char exten[256] = "";
- int status = CACHE_FLAG_UNKNOWN;
- int expirey = iaxdefaultdpcache;
- int x;
- int matchmore = 0;
- struct iax_dpcache *dp, *prev;
- char *stringp=NULL;
-
- strncpy(request, orequest, sizeof(request)-1);
- stringp=request;
- var = strsep(&stringp, ";");
- while(var) {
- value = strchr(var, '=');
- if (value) {
- *value='\0';
- value++;
- if (!strcmp(var, "number"))
- strncpy(exten, value, sizeof(exten)-1);
- else if (!strcmp(var, "status")) {
- if (!strcasecmp(value, "exists"))
- status = CACHE_FLAG_EXISTS;
- else if (!strcasecmp(value, "nonexistant"))
- status = CACHE_FLAG_NONEXISTANT;
- else if (!strcasecmp(value, "canexist"))
- status = CACHE_FLAG_CANEXIST;
- else
- ast_log(LOG_WARNING, "Unknown status '%s'\n", value);
- } else if (!strcmp(var, "expirey"))
- expirey = atoi(value);
- else if (!strcmp(var, "ignorepat")) {
- /* Don' really do much with it */
- } else if (!strcmp(var, "matchmore")) {
- matchmore = CACHE_FLAG_MATCHMORE;
- } else
- ast_log(LOG_WARNING, "Unknown variable '%s' with value '%s'\n", var, value);
- }
- var = strsep(&stringp, ";");
- }
- ast_mutex_lock(&dpcache_lock);
- prev = NULL;
- dp = pvt->dpentries;
- while(dp) {
- if (!strcmp(dp->exten, exten)) {
- /* Let them go */
- if (prev)
- prev->peer = dp->peer;
- else
- pvt->dpentries = dp->peer;
- dp->peer = NULL;
- dp->callno = -1;
- dp->expirey.tv_sec = dp->orig.tv_sec + expirey;
- if (dp->flags & CACHE_FLAG_PENDING) {
- dp->flags &= ~CACHE_FLAG_PENDING;
- dp->flags |= status;
- dp->flags |= CACHE_FLAG_MATCHMORE;
- }
- /* Wake up waiters */
- for (x=0;x<sizeof(dp->waiters) / sizeof(dp->waiters[0]); x++)
- if (dp->waiters[x] > -1)
- write(dp->waiters[x], "asdf", 4);
- }
- prev = dp;
- dp = dp->peer;
- }
- ast_mutex_unlock(&dpcache_lock);
- return 0;
- }
- static int complete_transfer(int callno, char *orequest)
- {
- int peercallno = -1;
- char request[256] = "";
- char *var, *value;
- struct chan_iax_pvt *pvt = iaxs[callno];
- struct ast_iax_frame *cur;
- char *stringp=NULL;
- if (!orequest)
- return -1;
- strncpy(request, orequest, sizeof(request)-1);
- stringp=request;
- var = strsep(&stringp, ";");
- while(var) {
- value = strchr(var, '=');
- if (value) {
- *value='\0';
- value++;
- if (!strcmp(var, "peercallno"))
- peercallno = atoi(value);
- else
- ast_log(LOG_WARNING, "Unknown variable '%s' with value '%s'\n", var, value);
- }
- var = strsep(&stringp, ";");
- }
- if (peercallno < 0) {
- ast_log(LOG_WARNING, "Invalid transfer request\n");
- return -1;
- }
- memcpy(&pvt->addr, &pvt->transfer, sizeof(pvt->addr));
- memset(&pvt->transfer, 0, sizeof(pvt->transfer));
- /* Reset sequence numbers */
- pvt->oseqno = 0;
- pvt->iseqno = 0;
- pvt->peercallno = peercallno;
- pvt->transferring = TRANSFER_NONE;
- pvt->svoiceformat = -1;
- pvt->voiceformat = 0;
- pvt->transfercallno = -1;
- memset(&pvt->rxcore, 0, sizeof(pvt->rxcore));
- memset(&pvt->offset, 0, sizeof(pvt->offset));
- memset(&pvt->history, 0, sizeof(pvt->history));
- pvt->jitterbuffer = 0;
- pvt->jitter = 0;
- pvt->historicjitter = 0;
- pvt->lag = 0;
- pvt->last = 0;
- pvt->lastsent = 0;
- pvt->pingtime = DEFAULT_RETRY_TIME;
- ast_mutex_lock(&iaxq.lock);
- for (cur = iaxq.head; cur ; cur = cur->next) {
- /* We must cancel any packets that would have been transmitted
- because now we're talking to someone new. It's okay, they
- were transmitted to someone that didn't care anyway. */
- if (callno == cur->callno)
- cur->retries = -1;
- }
- ast_mutex_unlock(&iaxq.lock);
- return 0;
- }
- static int iax_ack_registry(char *orequest, struct sockaddr_in *sin, int callno)
- {
- struct iax_registry *reg;
- /* Start pessimistic */
- char request[256] = "";
- char peer[256] = "";
- int ourport = 0;
- int refresh = 0;
- char ourip[256] = "<Unspecified>";
- char iabuf[INET_ADDRSTRLEN];
- struct sockaddr_in oldus;
- char *var, *value;
- char *stringp=NULL;
- if (!orequest)
- return -1;
- strncpy(request, orequest, sizeof(request)-1);
- stringp=request;
- var = strsep(&stringp, ";");
- while(var) {
- value = strchr(var, '=');
- if (value) {
- *value='\0';
- value++;
- if (!strcmp(var, "yourip"))
- strncpy(ourip, value, sizeof(ourip)-1);
- else if (!strcmp(var, "peer"))
- strncpy(peer, value, sizeof(peer)-1);
- else if (!strcmp(var, "yourport"))
- ourport = atoi(value);
- else if (!strcmp(var, "refresh"))
- refresh = atoi(value);
- else if (!strcmp(var, "callerid")) {
- /* We don't really care about suggested Caller*ID, that's more for phones */
- } else
- ast_log(LOG_WARNING, "Unknown variable '%s' with value '%s'\n", var, value);
- }
- var = strsep(&stringp, ";");
- }
- reg = iaxs[callno]->reg;
- memcpy(&oldus, ®->us, sizeof(oldus));
- if (memcmp(®->addr, sin, sizeof(®->addr))) {
- ast_log(LOG_WARNING, "Received unsolicited registry ack from '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr));
- return -1;
- }
- if (!inet_aton(ourip, ®->us.sin_addr)) {
- ast_log(LOG_WARNING, "Registry ack from '%s' contains invalid IP '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ourip);
- return -1;
- }
- reg->us.sin_port = htons(ourport);
- if (refresh && (reg->refresh < refresh)) {
- /* Refresh faster if necessary */
- reg->refresh = refresh;
- if (reg->expire > -1)
- ast_sched_del(sched, reg->expire);
- reg->expire = ast_sched_add(sched, (5 * reg->refresh / 6) * 1000, iax_do_register_s, reg);
- }
- if (memcmp(&oldus, ®->us, sizeof(oldus)) && (option_verbose > 2)) {
- snprintf(ourip, sizeof(ourip), "%s:%d", ast_inet_ntoa(iabuf, sizeof(iabuf), reg->us.sin_addr), ntohs(reg->us.sin_port));
- ast_verbose(VERBOSE_PREFIX_3 "Registered to '%s', who sees us as %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ourip);
- }
- reg->regstate = REG_STATE_REGISTERED;
- return 0;
- ast_log(LOG_WARNING, "Registry acknowledge on unknown registery '%s'\n", peer);
- return -1;
- }
- static int iax_register(char *value, int lineno)
- {
- struct iax_registry *reg;
- char copy[256];
- char *username, *hostname, *secret;
- char *porta;
- char *stringp=NULL;
-
- struct ast_hostent ahp; struct hostent *hp;
- if (!value)
- return -1;
- strncpy(copy, value, sizeof(copy)-1);
- stringp=copy;
- username = strsep(&stringp, "@");
- hostname = strsep(&stringp, "@");
- if (!hostname) {
- ast_log(LOG_WARNING, "Format for registration is user[:secret]@host[:port] at line %d", lineno);
- return -1;
- }
- stringp=username;
- username = strsep(&stringp, ":");
- secret = strsep(&stringp, ":");
- stringp=hostname;
- hostname = strsep(&stringp, ":");
- porta = strsep(&stringp, ":");
-
- if (porta && !atoi(porta)) {
- ast_log(LOG_WARNING, "%s is not a valid port number at line %d\n", porta, lineno);
- return -1;
- }
- hp = ast_gethostbyname(hostname, &ahp);
- if (!hp) {
- ast_log(LOG_WARNING, "Host '%s' not found at line %d\n", hostname, lineno);
- return -1;
- }
- reg = malloc(sizeof(struct iax_registry));
- if (reg) {
- memset(reg, 0, sizeof(struct iax_registry));
- strncpy(reg->username, username, sizeof(reg->username)-1);
- if (secret)
- strncpy(reg->secret, secret, sizeof(reg->secret)-1);
- reg->expire = -1;
- reg->refresh = AST_DEFAULT_REG_EXPIRE;
- reg->addr.sin_family = AF_INET;
- memcpy(®->addr.sin_addr, hp->h_addr, sizeof(®->addr.sin_addr));
- reg->addr.sin_port = porta ? htons(atoi(porta)) : htons(AST_DEFAULT_IAX_PORTNO);
- reg->next = registrations;
- reg->callno = -1;
- registrations = reg;
- } else {
- ast_log(LOG_ERROR, "Out of memory\n");
- return -1;
- }
- return 0;
- }
- static int expire_registry(void *data)
- {
- struct iax_peer *p = data;
- /* Reset the address */
- memset(&p->addr, 0, sizeof(p->addr));
- /* Reset expire notice */
- p->expire = -1;
- /* Reset expirey value */
- p->expirey = expirey;
- if (iax_regfunk)
- iax_regfunk(p->name, 0);
- return 0;
- }
- static int iax_poke_peer(struct iax_peer *peer);
- static int update_registry(char *name, struct sockaddr_in *sin, int callno)
- {
- /* Called from IAX thread only, with proper iaxsl lock */
- char requeststr[256] = "";
- struct iax_peer *p;
- char iabuf[INET_ADDRSTRLEN];
- for (p = peerl.peers;p;p = p->next) {
- if (!strcasecmp(name, p->name)) {
- break;
- }
- }
- #ifdef MYSQL_FRIENDS
- if (!p)
- p = mysql_peer(name);
- #endif
- if (p) {
- #ifdef MYSQL_FRIENDS
- if (p->delme)
- mysql_update_peer(name, sin);
- #endif
- if (memcmp(&p->addr, sin, sizeof(p->addr))) {
- if (iax_regfunk)
- iax_regfunk(p->name, 1);
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Registered '%s' (%s) at %s:%d\n", p->name,
- iaxs[callno]->state & IAX_STATE_AUTHENTICATED ? "AUTHENTICATED" : "UNAUTHENTICATED", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), htons(sin->sin_port));
- iax_poke_peer(p);
- }
- /* Update the host */
- memcpy(&p->addr, sin, sizeof(p->addr));
- /* Setup the expirey */
- if (p->expire > -1)
- ast_sched_del(sched, p->expire);
- if (p->expirey)
- p->expire = ast_sched_add(sched, p->expirey * 1000, expire_registry, (void *)p);
- MYSNPRINTF "peer=%s;yourip=%s;yourport=%d;refresh=%d;",
- p->name, ast_inet_ntoa(iabuf, sizeof(iabuf), p->addr.sin_addr), ntohs(p->addr.sin_port), p->expirey);
- if (p->hascallerid)
- MYSNPRINTF "callerid=%s;", p->callerid);
- requeststr[strlen(requeststr)-1] = '\0';
- if (p->delme)
- free(p);
- return send_command_final(iaxs[callno], AST_FRAME_IAX, AST_IAX_COMMAND_REGACK, 0, requeststr, strlen(requeststr) + 1, -1);;
- }
- ast_log(LOG_WARNING, "No such peer '%s'\n", name);
- return -1;
- }
- static int registry_authrequest(char *name, int callno)
- {
- char requeststr[256] = "";
- struct iax_peer *p;
- for (p = peerl.peers;p;p = p->next) {
- if (!strcasecmp(name, p->name)) {
- break;
- }
- }
- #ifdef MYSQL_FRIENDS
- if (!p)
- p = mysql_peer(name);
- #endif
- if (p) {
- MYSNPRINTF "methods=%s;", p->methods);
- if (strstr(p->methods, "md5") || strstr(p->methods, "rsa")) {
- /* Build the challenge */
- snprintf(iaxs[callno]->challenge, sizeof(iaxs[callno]->challenge), "%d", rand());
- MYSNPRINTF "challenge=%s;", iaxs[callno]->challenge);
- }
- MYSNPRINTF "peer=%s;", name);
- requeststr[strlen(requeststr)-1] = '\0';
- if (p->delme)
- free(p);
- return send_command(iaxs[callno], AST_FRAME_IAX, AST_IAX_COMMAND_REGAUTH, 0, requeststr, strlen(requeststr) + 1, -1);
- }
- ast_log(LOG_WARNING, "No such peer '%s'\n", name);
- return 0;
- }
- static int registry_rerequest(char *orequest, int callno, struct sockaddr_in *sin)
- {
- struct iax_registry *reg;
- /* Start pessimistic */
- char request[256] = "";
- char requeststr[256] = "";
- char peer[256] = "";
- char methods[256] = "";
- char challenge[256] = "";
- char iabuf[INET_ADDRSTRLEN];
- char *var, *value;
- int res;
- char *stringp=NULL;
- if (!orequest)
- return -1;
- strncpy(request, orequest, sizeof(request)-1);
- stringp=request;
- var = strsep(&stringp, ";");
- while(var) {
- value = strchr(var, '=');
- if (value) {
- *value='\0';
- value++;
- if (!strcmp(var, "methods"))
- strncpy(methods, value, sizeof(methods)-1);
- else if (!strcmp(var, "peer"))
- strncpy(peer, value, sizeof(peer)-1);
- else if (!strcmp(var, "challenge"))
- strncpy(challenge, value, sizeof(challenge)-1);
- else
- ast_log(LOG_WARNING, "Unknown variable '%s' with value '%s'\n", var, value);
- }
- var = strsep(&stringp, ";");
- }
- reg = iaxs[callno]->reg;
- if (memcmp(®->addr, sin, sizeof(®->addr))) {
- ast_log(LOG_WARNING, "Received unsolicited registry authenticate request from '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr));
- return -1;
- }
- if (!strlen(reg->secret)) {
- ast_log(LOG_NOTICE, "No secret associated with peer '%s'\n", reg->username);
- reg->regstate = REG_STATE_NOAUTH;
- return -1;
- }
- MYSNPRINTF "peer=%s;refresh=%d;", reg->username, reg->refresh);
- if (reg->secret[0] == '[') {
- char tmpkey[256];
- strncpy(tmpkey, reg->secret + 1, sizeof(tmpkey) - 1);
- tmpkey[strlen(tmpkey) - 1] = '\0';
- res = authenticate(challenge, NULL, tmpkey, methods, requeststr, sizeof(requeststr), sin);
- } else
- res = authenticate(challenge, reg->secret, NULL, methods, requeststr, sizeof(requeststr), sin);
- if (!res) {
- reg->regstate = REG_STATE_AUTHSENT;
- return send_command(iaxs[callno], AST_FRAME_IAX, AST_IAX_COMMAND_REGREQ, 0, requeststr, strlen(requeststr) + 1, -1);
- } else
- return -1;
- ast_log(LOG_WARNING, "Registry acknowledge on unknown registery '%s'\n", peer);
- return -1;
- }
- static int stop_stuff(int callno)
- {
- if (iaxs[callno]->lagid > -1)
- ast_sched_del(sched, iaxs[callno]->lagid);
- iaxs[callno]->lagid = -1;
- if (iaxs[callno]->pingid > -1)
- ast_sched_del(sched, iaxs[callno]->pingid);
- iaxs[callno]->pingid = -1;
- if (iaxs[callno]->autoid > -1)
- ast_sched_del(sched, iaxs[callno]->autoid);
- iaxs[callno]->autoid = -1;
- if (iaxs[callno]->initid > -1)
- ast_sched_del(sched, iaxs[callno]->initid);
- iaxs[callno]->initid = -1;
- return 0;
- }
- static int auto_hangup(void *nothing)
- {
- /* Called from IAX thread only, without iaxs lock */
- int callno = (int)(long)(nothing);
- ast_mutex_lock(&iaxsl[callno]);
- if (iaxs[callno]) {
- iaxs[callno]->autoid = -1;
- send_command_final(iaxs[callno], AST_FRAME_IAX, AST_IAX_COMMAND_HANGUP, 0, "Timeout", strlen("Timeout") + 1, -1);
- }
- ast_mutex_unlock(&iaxsl[callno]);
- return 0;
- }
- static void iax_dprequest(struct iax_dpcache *dp, int callno)
- {
- /* Auto-hangup with 30 seconds of inactivity */
- if (iaxs[callno]->autoid > -1)
- ast_sched_del(sched, iaxs[callno]->autoid);
- iaxs[callno]->autoid = ast_sched_add(sched, 30000, auto_hangup, (void *)(long)callno);
- send_command(iaxs[callno], AST_FRAME_IAX, AST_IAX_COMMAND_DPREQ, 0, dp->exten, strlen(dp->exten) + 1, -1);
- dp->flags |= CACHE_FLAG_TRANSMITTED;
- }
- static int iax_vnak(int callno)
- {
- return send_command_immediate(iaxs[callno], AST_FRAME_IAX, AST_IAX_COMMAND_VNAK, 0, NULL, 0, iaxs[callno]->iseqno);
- }
- static void vnak_retransmit(int callno, int last)
- {
- struct ast_iax_frame *f;
- ast_mutex_lock(&iaxq.lock);
- f = iaxq.head;
- while(f) {
- /* Send a copy immediately */
- if ((f->callno == callno) && iaxs[f->callno] &&
- (f->seqno >= last)) {
- send_packet(f);
- }
- f = f->next;
- }
- ast_mutex_unlock(&iaxq.lock);
- }
- static int iax_poke_peer_s(void *data)
- {
- struct iax_peer *peer = data;
- peer->pokeexpire = -1;
- iax_poke_peer(peer);
- return 0;
- }
- static int socket_read(int *id, int fd, short events, void *cbdata)
- {
- struct sockaddr_in sin;
- int res;
- int new = NEW_PREVENT;
- char buf[4096];
- char src[80];
- int len = sizeof(sin);
- int dcallno = -1;
- struct ast_iax_full_hdr *fh = (struct ast_iax_full_hdr *)buf;
- struct ast_iax_mini_hdr *mh = (struct ast_iax_mini_hdr *)buf;
- struct ast_iax_frame fr, *cur;
- struct ast_frame f;
- struct ast_channel *c;
- struct iax_dpcache *dp;
- struct iax_peer *peer;
- int format;
- int exists;
- int mm;
- char iabuf[INET_ADDRSTRLEN];
- char rel0[256] = "";
- char rel1[255];
- char empty[32]=""; /* Safety measure */
- res = recvfrom(netsocket, buf, sizeof(buf), 0,(struct sockaddr *) &sin, &len);
- if (res < 0) {
- if (errno != ECONNREFUSED)
- ast_log(LOG_WARNING, "Error: %s\n", strerror(errno));
- handle_error();
- return 1;
- }
- if (res < sizeof(struct ast_iax_mini_hdr)) {
- ast_log(LOG_WARNING, "midget packet received (%d of %d min)\n", res, (int)sizeof(struct ast_iax_mini_hdr));
- return 1;
- }
- #ifdef DEBUG_SUPPORT
- if (iaxdebug)
- showframe(NULL, fh, 1, &sin);
- #endif
- if (ntohs(mh->callno) & AST_FLAG_FULL) {
- /* Get the destination call number */
- dcallno = ntohs(fh->dcallno);
- /* Retrieve the type and subclass */
- f.frametype = fh->type;
- f.subclass = uncompress_subclass(fh->csub);
- #if 0
- f.subclass = fh->subclasshigh << 16;
- f.subclass += ntohs(fh->subclasslow);
- #endif
- if ((f.frametype == AST_FRAME_IAX) && ((f.subclass == AST_IAX_COMMAND_NEW) || (f.subclass == AST_IAX_COMMAND_REGREQ)
- || (f.subclass == AST_IAX_COMMAND_POKE)))
- new = NEW_ALLOW;
- } else {
- /* Don't know anything about it yet */
- f.frametype = AST_FRAME_NULL;
- f.subclass = 0;
- }
- fr.callno = find_callno(ntohs(mh->callno) & ~AST_FLAG_FULL, dcallno, &sin, new);
- if (fr.callno > 0)
- ast_mutex_lock(&iaxsl[fr.callno]);
- if ((fr.callno < 0) || !iaxs[fr.callno]) {
- /* A call arrived for a non-existant destination. Unless it's an "inval"
- frame, reply with an inval */
- if (ntohs(mh->callno) & AST_FLAG_FULL) {
- /* We can only raw hangup control frames */
- if (((f.subclass != AST_IAX_COMMAND_INVAL) &&
- (f.subclass != AST_IAX_COMMAND_TXCNT) &&
- (f.subclass != AST_IAX_COMMAND_TXACC))||
- (f.frametype != AST_FRAME_IAX))
- raw_hangup(&sin, ntohs(fh->dcallno), ntohs(mh->callno) & ~AST_FLAG_FULL
- );
- }
- if (fr.callno > 0)
- ast_mutex_unlock(&iaxsl[fr.callno]);
- return 1;
- }
- if (((f.subclass != AST_IAX_COMMAND_TXCNT) &&
- (f.subclass != AST_IAX_COMMAND_TXACC)) || (f.frametype != AST_FRAME_IAX))
- iaxs[fr.callno]->peercallno = (short)(ntohs(mh->callno) & ~AST_FLAG_FULL);
- if (ntohs(mh->callno) & AST_FLAG_FULL) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Received packet %d, (%d, %d)\n", ntohs(fh->seqno), f.frametype, f.subclass);
- /* Check if it's out of order (and not an ACK or INVAL) */
- fr.seqno = ntohs(fh->seqno);
- fr.ts = ntohl(fh->ts);
- if ((iaxs[fr.callno]->iseqno != fr.seqno) &&
- (iaxs[fr.callno]->iseqno ||
- ((f.subclass != AST_IAX_COMMAND_TXCNT) &&
- (f.subclass != AST_IAX_COMMAND_TXACC)) ||
- (f.subclass != AST_FRAME_IAX))) {
- if (
- ((f.subclass != AST_IAX_COMMAND_ACK) &&
- (f.subclass != AST_IAX_COMMAND_INVAL) &&
- (f.subclass != AST_IAX_COMMAND_TXCNT) &&
- (f.subclass != AST_IAX_COMMAND_TXACC) &&
- (f.subclass != AST_IAX_COMMAND_VNAK)) ||
- (f.frametype != AST_FRAME_IAX)) {
- /* If it's not an ACK packet, it's out of order. */
- if (option_debug)
- ast_log(LOG_DEBUG, "Packet arrived out of order (expecting %d, got %d) (frametype = %d, subclass = %d)\n",
- iaxs[fr.callno]->iseqno, fr.seqno, f.frametype, f.subclass);
- if (iaxs[fr.callno]->iseqno > fr.seqno) {
- /* If we've already seen it, ack it XXX There's a border condition here XXX */
- if ((f.frametype != AST_FRAME_IAX) ||
- ((f.subclass != AST_IAX_COMMAND_ACK) && (f.subclass != AST_IAX_COMMAND_INVAL))) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Acking anyway\n");
- send_command_immediate(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_ACK, fr.ts, NULL, 0,fr.seqno);
- }
- } else {
- /* Send a VNAK requesting retransmission */
- iax_vnak(fr.callno);
- }
- ast_mutex_unlock(&iaxsl[fr.callno]);
- return 1;
- }
- } else {
- /* Increment unless it's an ACK or VNAK */
- if (((f.subclass != AST_IAX_COMMAND_ACK) &&
- (f.subclass != AST_IAX_COMMAND_INVAL) &&
- (f.subclass != AST_IAX_COMMAND_TXCNT) &&
- (f.subclass != AST_IAX_COMMAND_TXACC) &&
- (f.subclass != AST_IAX_COMMAND_VNAK)) ||
- (f.frametype != AST_FRAME_IAX))
- iaxs[fr.callno]->iseqno++;
- }
- /* A full frame */
- if (res < sizeof(struct ast_iax_full_hdr)) {
- ast_log(LOG_WARNING, "midget packet received (%d of %d min)\n", res, (int)sizeof(struct ast_iax_full_hdr));
- ast_mutex_unlock(&iaxsl[fr.callno]);
- return 1;
- }
- f.datalen = res - sizeof(struct ast_iax_full_hdr);
- if (f.datalen)
- f.data = buf + sizeof(struct ast_iax_full_hdr);
- else
- f.data = empty;
- /* Unless this is an ACK or INVAL frame, ack it */
- if ((f.frametype != AST_FRAME_IAX) ||
- ((f.subclass != AST_IAX_COMMAND_ACK) &&
- (f.subclass != AST_IAX_COMMAND_TXCNT) &&
- (f.subclass != AST_IAX_COMMAND_TXACC) &&
- (f.subclass != AST_IAX_COMMAND_INVAL) &&
- (f.subclass != AST_IAX_COMMAND_VNAK)))
- send_command_immediate(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_ACK, fr.ts, NULL, 0,fr.seqno);
- if (f.frametype == AST_FRAME_VOICE) {
- if (f.subclass != iaxs[fr.callno]->voiceformat) {
- iaxs[fr.callno]->voiceformat = f.subclass;
- ast_log(LOG_DEBUG, "Ooh, voice format changed to %s\n", ast_getformatname(f.subclass));
- if (iaxs[fr.callno]->owner) {
- int orignative;
- retryowner:
- if (ast_mutex_trylock(&iaxs[fr.callno]->owner->lock)) {
- ast_mutex_unlock(&iaxsl[fr.callno]);
- usleep(1);
- ast_mutex_lock(&iaxsl[fr.callno]);
- if (iaxs[fr.callno] && iaxs[fr.callno]->owner) goto retryowner;
- }
- orignative = iaxs[fr.callno]->owner->nativeformats;
- iaxs[fr.callno]->owner->nativeformats = f.subclass;
- if (iaxs[fr.callno]->owner->readformat)
- ast_set_read_format(iaxs[fr.callno]->owner, iaxs[fr.callno]->owner->readformat);
- iaxs[fr.callno]->owner->nativeformats = orignative;
- ast_mutex_unlock(&iaxs[fr.callno]->owner->lock);
- }
- }
- }
- if (f.frametype == AST_FRAME_IAX) {
- if (iaxs[fr.callno]->initid > -1) {
- /* Don't auto congest anymore since we've gotten something usefulb ack */
- ast_sched_del(sched, iaxs[fr.callno]->initid);
- iaxs[fr.callno]->initid = -1;
- }
- /* Handle the IAX pseudo frame itself */
- if (option_debug)
- ast_log(LOG_DEBUG, "IAX subclass %d received\n", f.subclass);
- /* Go through the motions of delivering the packet without actually doing so,
- unless this is a lag request since it will be done for real */
- if (f.subclass != AST_IAX_COMMAND_LAGRQ)
- schedule_delivery(&fr, 0);
- switch(f.subclass) {
- case AST_IAX_COMMAND_ACK:
- /* Ack the packet with the given timestamp */
- ast_mutex_lock(&iaxq.lock);
- for (cur = iaxq.head; cur ; cur = cur->next) {
- /* If it's our call, and our timestamp, mark -1 retries */
- if ((fr.callno == cur->callno) && (fr.seqno == cur->seqno)) {
- cur->retries = -1;
- /* Destroy call if this is the end */
- if (cur->final) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Really destroying %d, having been acked on final message\n", fr.callno);
- iax_destroy_nolock(fr.callno);
- }
- }
- }
- ast_mutex_unlock(&iaxq.lock);
- break;
- case AST_IAX_COMMAND_QUELCH:
- if (iaxs[fr.callno]->state & IAX_STATE_STARTED)
- iaxs[fr.callno]->quelch = 1;
- break;
- case AST_IAX_COMMAND_UNQUELCH:
- if (iaxs[fr.callno]->state & IAX_STATE_STARTED)
- iaxs[fr.callno]->quelch = 0;
- break;
- case AST_IAX_COMMAND_TXACC:
- if (iaxs[fr.callno]->transferring == TRANSFER_BEGIN) {
- /* Ack the packet with the given timestamp */
- ast_mutex_lock(&iaxq.lock);
- for (cur = iaxq.head; cur ; cur = cur->next) {
- /* Cancel any outstanding txcnt's */
- if ((fr.callno == cur->callno) && (cur->transfer))
- cur->retries = -1;
- }
- ast_mutex_unlock(&iaxq.lock);
- snprintf(rel1, sizeof(rel1), "callno=%d;", iaxs[fr.callno]->callno);
- send_command(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_TXREADY, 0, rel1, strlen(rel1) + 1, -1);
- iaxs[fr.callno]->transferring = TRANSFER_READY;
- }
- break;
- case AST_IAX_COMMAND_NEW:
- /* Ignore if it's already up */
- if (iaxs[fr.callno]->state & (IAX_STATE_STARTED | IAX_STATE_TBD))
- break;
- ((char *)f.data)[f.datalen] = '\0';
- if (check_access(fr.callno, &sin, f.data, f.datalen)) {
- /* They're not allowed on */
- send_command_final(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_REJECT, 0, "No authority found", strlen("No authority found"), -1);
- ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), (char *)f.data);
- break;
- }
- /* This might re-enter the IAX code and need the lock */
- exists = ast_exists_extension(NULL, iaxs[fr.callno]->context, iaxs[fr.callno]->exten, 1, iaxs[fr.callno]->callerid);
- if (!strlen(iaxs[fr.callno]->secret) && !strlen(iaxs[fr.callno]->inkeys)) {
- if (strcmp(iaxs[fr.callno]->exten, "TBD") && !exists) {
- send_command_final(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_REJECT, 0, "No such context/extension", strlen("No such context/extension"), -1);
- ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s@%s' does not exist\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), iaxs[fr.callno]->exten, iaxs[fr.callno]->context);
- } else {
- /* Select an appropriate format */
- format = iaxs[fr.callno]->peerformat & iax_capability;
- if (!format) {
- format = iaxs[fr.callno]->peercapability & iax_capability;
- if (!format) {
- send_command_final(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_REJECT, 0, "Unable to negotiate codec", strlen("Unable to negotiate codec"), -1);
- ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability 0x%x/0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), iaxs[fr.callno]->peerformat, iaxs[fr.callno]->peercapability, iax_capability);
- } else {
- /* Pick one... */
- format = ast_best_codec(iaxs[fr.callno]->peercapability & iax_capability);
- if (!format) {
- ast_log(LOG_ERROR, "No best format in 0x%x???\n", iaxs[fr.callno]->peercapability & iax_capability);
- send_command_final(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_REJECT, 0, "Unable to negotiate codec", strlen("Unable to negotiate codec"), -1);
- ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability 0x%x/0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), iaxs[fr.callno]->peerformat, iaxs[fr.callno]->peercapability, iax_capability);
- iaxs[fr.callno]->alreadygone = 1;
- break;
- }
- }
- }
- if (format) {
- /* No authentication required, let them in */
- snprintf(rel1, sizeof(rel1), "formats=%d;", format);
- send_command(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_ACCEPT, 0, rel1, strlen(rel1) + 1, -1);
- if (strcmp(iaxs[fr.callno]->exten, "TBD")) {
- iaxs[fr.callno]->state |= IAX_STATE_STARTED;
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Accepting unauthenticated call from %s, requested format = %d, actual format = %d\n",
- ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), iaxs[fr.callno]->peerformat,format);
- if(!(c = ast_iax_new(iaxs[fr.callno], AST_STATE_RING, format)))
- iax_destroy_nolock(fr.callno);
- } else {
- iaxs[fr.callno]->state |= IAX_STATE_TBD;
- /* If this is a TBD call, we're ready but now what... */
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Accepted unauthenticated TBD call from %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr));
- }
- }
- }
- break;
- }
- authenticate_request(iaxs[fr.callno]);
- iaxs[fr.callno]->state |= IAX_STATE_AUTHENTICATED;
- break;
- case AST_IAX_COMMAND_DPREQ:
- /* Request status in the dialplan */
- ((char *)f.data)[f.datalen] = '\0';
- if ((iaxs[fr.callno]->state & IAX_STATE_TBD) &&
- !(iaxs[fr.callno]->state & IAX_STATE_STARTED) && f.datalen) {
- mm = ast_matchmore_extension(NULL, iaxs[fr.callno]->context, (char *)f.data, 1, iaxs[fr.callno]->callerid);
- /* Must be started */
- if (ast_exists_extension(NULL, iaxs[fr.callno]->context, (char *)f.data, 1, iaxs[fr.callno]->callerid)) {
- strncpy(rel0, "exists", sizeof(rel0) - 1);
- } else if (ast_canmatch_extension(NULL, iaxs[fr.callno]->context, (char *)f.data, 1, iaxs[fr.callno]->callerid)) {
- strncpy(rel0, "canexist", sizeof(rel0) - 1);
- } else {
- strncpy(rel0, "nonexistant", sizeof(rel0) - 1);
- }
- snprintf(rel1, sizeof(rel1), "number=%s;status=%s;ignorepat=%s;expirey=%d;matchmore=%s;",
- (char *)f.data, rel0,
- ast_ignore_pattern(iaxs[fr.callno]->context, (char *)f.data) ? "yes" : "no",
- iaxdefaultdpcache, mm ? "yes" : "no");
- send_command(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_DPREP, 0, rel1, strlen(rel1) + 1, -1);
- }
- break;
- case AST_IAX_COMMAND_HANGUP:
- iaxs[fr.callno]->alreadygone = 1;
- ast_log(LOG_DEBUG, "Immediately destroying %d, having received hangup\n", fr.callno);
- iax_destroy_nolock(fr.callno);
- break;
- case AST_IAX_COMMAND_REJECT:
- if (f.data)
- ((char *)f.data)[f.datalen] = '\0';
- if (iaxs[fr.callno]->owner)
- ast_log(LOG_WARNING, "Call rejected by %s: %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), iaxs[fr.callno]->addr.sin_addr), (char *)f.data);
- iaxs[fr.callno]->error = EPERM;
- ast_log(LOG_DEBUG, "Immediately destroying %d, having received reject\n", fr.callno);
- iax_destroy_nolock(fr.callno);
- break;
- case AST_IAX_COMMAND_ACCEPT:
- /* Ignore if call is already up or needs authentication or is a TBD */
- if (iaxs[fr.callno]->state & (IAX_STATE_STARTED | IAX_STATE_TBD | IAX_STATE_AUTHENTICATED))
- break;
- if (f.data && f.datalen) {
- ((char *)f.data)[f.datalen]='\0';
- iax_getformats(fr.callno, (char *)f.data);
- } else {
- if (iaxs[fr.callno]->owner)
- iaxs[fr.callno]->peerformat = iaxs[fr.callno]->owner->nativeformats;
- else
- iaxs[fr.callno]->peerformat = iax_capability;
- }
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Call accepted by %s (format %s)\n", ast_inet_ntoa(iabuf, sizeof(iabuf), iaxs[fr.callno]->addr.sin_addr), ast_getformatname(iaxs[fr.callno]->peerformat));
- if (!(iaxs[fr.callno]->peerformat & iaxs[fr.callno]->capability)) {
- send_command_final(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_REJECT, 0, "Unable to negotiate codec", strlen("Unable to negotiate codec"), -1);
- ast_log(LOG_NOTICE, "Rejected call to %s, format 0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), iaxs[fr.callno]->peerformat, iaxs[fr.callno]->capability);
- } else {
- iaxs[fr.callno]->state |= IAX_STATE_STARTED;
- if (iaxs[fr.callno]->owner) {
- /* Switch us to use a compatible format */
- iaxs[fr.callno]->owner->nativeformats = iaxs[fr.callno]->peerformat;
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Format for call is %s\n", ast_getformatname(iaxs[fr.callno]->owner->nativeformats));
- /* Setup read/write formats properly. */
- if (iaxs[fr.callno]->owner->writeformat)
- ast_set_write_format(iaxs[fr.callno]->owner, iaxs[fr.callno]->owner->writeformat);
- if (iaxs[fr.callno]->owner->readformat)
- ast_set_read_format(iaxs[fr.callno]->owner, iaxs[fr.callno]->owner->readformat);
- }
- }
- ast_mutex_lock(&dpcache_lock);
- dp = iaxs[fr.callno]->dpentries;
- while(dp) {
- if (!(dp->flags & CACHE_FLAG_TRANSMITTED)) {
- iax_dprequest(dp, fr.callno);
- }
- dp = dp->peer;
- }
- ast_mutex_unlock(&dpcache_lock);
- break;
- case AST_IAX_COMMAND_POKE:
- /* Send back a pong packet with the original timestamp */
- send_command_final(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_PONG, fr.ts, NULL, 0, -1);
- break;
- case AST_IAX_COMMAND_PING:
- #ifdef BRIDGE_OPTIMIZATION
- if (iaxs[fr.callno]->bridgecallno > -1) {
- /* If we're in a bridged call, just forward this */
- forward_command(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_PING, fr.ts, NULL, 0, -1);
- } else {
- /* Send back a pong packet with the original timestamp */
- send_command(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_PONG, fr.ts, NULL, 0, -1);
- }
- #else
- /* Send back a pong packet with the original timestamp */
- send_command(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_PONG, fr.ts, NULL, 0, -1);
- #endif
- break;
- case AST_IAX_COMMAND_PONG:
- #ifdef BRIDGE_OPTIMIZATION
- if (iaxs[fr.callno]->bridgecallno > -1) {
- /* Forward to the other side of the bridge */
- forward_command(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_PONG, fr.ts, NULL, 0, -1);
- } else {
- /* Calculate ping time */
- iaxs[fr.callno]->pingtime = calc_timestamp(iaxs[fr.callno], 0) - fr.ts;
- }
- #else
- /* Calculate ping time */
- iaxs[fr.callno]->pingtime = calc_timestamp(iaxs[fr.callno], 0) - fr.ts;
- #endif
- if (iaxs[fr.callno]->peerpoke) {
- peer = iaxs[fr.callno]->peerpoke;
- if ((peer->lastms < 0) || (peer->lastms > peer->maxms)) {
- if (iaxs[fr.callno]->pingtime <= peer->maxms)
- ast_log(LOG_NOTICE, "Peer '%s' is now REACHABLE!\n", peer->name);
- } else if ((peer->lastms > 0) && (peer->lastms <= peer->maxms)) {
- if (iaxs[fr.callno]->pingtime > peer->maxms)
- ast_log(LOG_NOTICE, "Peer '%s' is now TOO LAGGED (%d ms)!\n", peer->name, iaxs[fr.callno]->pingtime);
- }
- peer->lastms = iaxs[fr.callno]->pingtime;
- peer->callno = -1;
- if (peer->pokeexpire > -1)
- ast_sched_del(sched, peer->pokeexpire);
- iax_destroy_nolock(fr.callno);
- /* Try again eventually */
- if ((peer->lastms < 0) || (peer->lastms > peer->maxms))
- peer->pokeexpire = ast_sched_add(sched, DEFAULT_FREQ_NOTOK, iax_poke_peer_s, peer);
- else
- peer->pokeexpire = ast_sched_add(sched, DEFAULT_FREQ_OK, iax_poke_peer_s, peer);
- }
- break;
- case AST_IAX_COMMAND_LAGRQ:
- case AST_IAX_COMMAND_LAGRP:
- #ifdef BRIDGE_OPTIMIZATION
- if (iaxs[fr.callno]->bridgecallno > -1) {
- forward_command(iaxs[fr.callno], AST_FRAME_IAX, f.subclass, fr.ts, NULL, 0, -1);
- } else {
- #endif
- /* A little strange -- We have to actually go through the motions of
- delivering the packet. In the very last step, it will be properly
- handled by do_deliver */
- snprintf(src, sizeof(src), "LAGRQ-IAX/%s/%d", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr),fr.callno);
- f.src = src;
- f.mallocd = 0;
- f.offset = 0;
- fr.f = &f;
- f.samples = 0;
- schedule_delivery(iaxfrdup2(&fr, 0), 1);
- #ifdef BRIDGE_OPTIMIZATION
- }
- #endif
- break;
- case AST_IAX_COMMAND_AUTHREQ:
- if (iaxs[fr.callno]->state & (IAX_STATE_STARTED | IAX_STATE_TBD)) {
- ast_log(LOG_WARNING, "Call on %s is already up, can't start on it\n", iaxs[fr.callno]->owner ? iaxs[fr.callno]->owner->name : "<Unknown>");
- break;
- }
- ((char *)f.data)[f.datalen] = '\0';
- if (authenticate_reply(iaxs[fr.callno], &iaxs[fr.callno]->addr, (char *)f.data, iaxs[fr.callno]->secret, iaxs[fr.callno]->outkey)) {
- ast_log(LOG_WARNING,
- "I don't know how to authenticate %s to %s\n",
- (char *)f.data, ast_inet_ntoa(iabuf, sizeof(iabuf), iaxs[fr.callno]->addr.sin_addr));
- }
- break;
- case AST_IAX_COMMAND_AUTHREP:
- /* Ignore once we've started */
- if (iaxs[fr.callno]->state & (IAX_STATE_STARTED | IAX_STATE_TBD)) {
- ast_log(LOG_WARNING, "Call on %s is already up, can't start on it\n", iaxs[fr.callno]->owner ? iaxs[fr.callno]->owner->name : "<Unknown>");
- break;
- }
- ((char *)f.data)[f.datalen] = '\0';
- if (authenticate_verify(iaxs[fr.callno], (char *)f.data)) {
- ast_log(LOG_NOTICE, "Host %s failed to authenticate as %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), iaxs[fr.callno]->addr.sin_addr), iaxs[fr.callno]->username);
- send_command_final(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_REJECT, 0, "No authority found", strlen("No authority found"), -1);
- break;
- }
- /* This might re-enter the IAX code and need the lock */
- exists = ast_exists_extension(NULL, iaxs[fr.callno]->context, iaxs[fr.callno]->exten, 1, iaxs[fr.callno]->callerid);
- if (strcmp(iaxs[fr.callno]->exten, "TBD") && !exists) {
- ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s@%s' does not exist\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), iaxs[fr.callno]->exten, iaxs[fr.callno]->context);
- send_command_final(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_REJECT, 0, "No such context/extension", strlen("No such context/extension"), -1);
- } else {
- /* Select an appropriate format */
- format = iaxs[fr.callno]->peerformat & iax_capability;
- if (!format) {
- ast_log(LOG_DEBUG, "We don't do requested format %s, falling back to peer capability %d\n", ast_getformatname(iaxs[fr.callno]->peerformat), iaxs[fr.callno]->peercapability);
- format = iaxs[fr.callno]->peercapability & iax_capability;
- if (!format) {
- ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability 0x%x/0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), iaxs[fr.callno]->peerformat, iaxs[fr.callno]->peercapability, iax_capability);
- send_command_final(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_REJECT, 0, "Unable to negotiate codec", strlen("Unable to negotiate codec"), -1);
- } else {
- /* Pick one... */
- format = ast_best_codec(iaxs[fr.callno]->peercapability & iax_capability);
- if (!format) {
- ast_log(LOG_ERROR, "No best format in 0x%x???\n", iaxs[fr.callno]->peercapability & iax_capability);
- ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability 0x%x/0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), iaxs[fr.callno]->peerformat, iaxs[fr.callno]->peercapability, iax_capability);
- send_command_final(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_REJECT, 0, "Unable to negotiate codec", strlen("Unable to negotiate codec"), -1);
- }
- }
- }
- if (format) {
- /* Authentication received */
- snprintf(rel1, sizeof(rel1), "formats=%d;", format);
- send_command(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_ACCEPT, 0, rel1, strlen(rel1) + 1, -1);
- if (strcmp(iaxs[fr.callno]->exten, "TBD")) {
- iaxs[fr.callno]->state |= IAX_STATE_STARTED;
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Accepting AUTHENTICATED call from %s, requested format = %d, actual format = %d\n",
- ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), iaxs[fr.callno]->peerformat,format);
- iaxs[fr.callno]->state |= IAX_STATE_STARTED;
- if(!(c = ast_iax_new(iaxs[fr.callno], AST_STATE_RING, format)))
- iax_destroy_nolock(fr.callno);
- } else {
- iaxs[fr.callno]->state |= IAX_STATE_TBD;
- /* If this is a TBD call, we're ready but now what... */
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Accepted AUTHENTICATED TBD call from %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr));
- }
- }
- }
- break;
- case AST_IAX_COMMAND_DIAL:
- ((char *)f.data)[f.datalen] = '\0';
- if (iaxs[fr.callno]->state & IAX_STATE_TBD) {
- iaxs[fr.callno]->state &= ~IAX_STATE_TBD;
- strncpy(iaxs[fr.callno]->exten, (char *)f.data, sizeof(iaxs[fr.callno]->exten)-1);
- if (!ast_exists_extension(NULL, iaxs[fr.callno]->context, iaxs[fr.callno]->exten, 1, iaxs[fr.callno]->callerid)) {
- ast_log(LOG_NOTICE, "Rejected dial attempt from %s, request '%s@%s' does not exist\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), iaxs[fr.callno]->exten, iaxs[fr.callno]->context);
- send_command_final(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_REJECT, 0, "No such context/extension", strlen("No such context/extension"), -1);
- } else {
- iaxs[fr.callno]->state |= IAX_STATE_STARTED;
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Accepting DIAL from %s, formats = 0x%x\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), iaxs[fr.callno]->peerformat);
- iaxs[fr.callno]->state |= IAX_STATE_STARTED;
- if(!(c = ast_iax_new(iaxs[fr.callno], AST_STATE_RING, iaxs[fr.callno]->peerformat)))
- iax_destroy_nolock(fr.callno);
- }
- }
- break;
- case AST_IAX_COMMAND_INVAL:
- iaxs[fr.callno]->error = ENOTCONN;
- ast_log(LOG_DEBUG, "Immediately destroying %d, having received INVAL\n", fr.callno);
- iax_destroy_nolock(fr.callno);
- if (option_debug)
- ast_log(LOG_DEBUG, "Destroying call %d\n", fr.callno);
- break;
- case AST_IAX_COMMAND_VNAK:
- ast_log(LOG_DEBUG, "Sending VNAK\n");
- /* Force retransmission */
- vnak_retransmit(fr.callno, fr.seqno);
- break;
- case AST_IAX_COMMAND_REGREQ:
- if (f.data)
- ((char *)f.data)[f.datalen]='\0';
- if (register_verify(fr.callno, &sin, (char *)f.data)) {
- send_command_final(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_REGREJ, 0, "Registration Refused", strlen("Registration Refused"), -1);
- break;
- }
- if ((!strlen(iaxs[fr.callno]->secret) && !strlen(iaxs[fr.callno]->inkeys)) || (iaxs[fr.callno]->state & IAX_STATE_AUTHENTICATED)) {
- if (update_registry(iaxs[fr.callno]->peer, &sin, fr.callno))
- ast_log(LOG_WARNING, "Registry error\n");
- break;
- }
- registry_authrequest(iaxs[fr.callno]->peer, fr.callno);
- break;
- case AST_IAX_COMMAND_REGACK:
- if (f.data)
- ((char *)f.data)[f.datalen] = '\0';
- if (iax_ack_registry(f.data, &sin, fr.callno))
- ast_log(LOG_WARNING, "Registration failure\n");
- iax_destroy_nolock(fr.callno);
- break;
- case AST_IAX_COMMAND_REGREJ:
- if (f.data)
- ((char *)f.data)[f.datalen] = '\0';
- if (iaxs[fr.callno]->reg) {
- ast_log(LOG_NOTICE, "Registration of '%s' rejected: %s\n", iaxs[fr.callno]->reg->username, (char *)f.data);
- iaxs[fr.callno]->reg->regstate = REG_STATE_REJECTED;
- }
- iax_destroy_nolock(fr.callno);
- break;
- case AST_IAX_COMMAND_REGAUTH:
- /* Authentication request */
- if (f.data)
- ((char *)f.data)[f.datalen] = '\0';
- if (registry_rerequest(f.data, fr.callno, &sin))
- send_command_final(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_REJECT, 0, "No authority found", strlen("No authority found"), -1);
- break;
- case AST_IAX_COMMAND_TXREJ:
- iaxs[fr.callno]->transferring = 0;
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Channel '%s' unable to transfer\n", iaxs[fr.callno]->owner ? iaxs[fr.callno]->owner->name : "<Unknown>");
- memset(&iaxs[fr.callno]->transfer, 0, sizeof(iaxs[fr.callno]->transfer));
- if (iaxs[fr.callno]->bridgecallno > -1) {
- if (iaxs[iaxs[fr.callno]->bridgecallno]->transferring) {
- iaxs[iaxs[fr.callno]->bridgecallno]->transferring = 0;
- send_command(iaxs[iaxs[fr.callno]->bridgecallno], AST_FRAME_IAX, AST_IAX_COMMAND_TXREJ, 0, NULL, 0, -1);
- }
- }
- break;
- case AST_IAX_COMMAND_TXREADY:
- if (iaxs[fr.callno]->transferring == TRANSFER_BEGIN) {
- iaxs[fr.callno]->transferring = TRANSFER_READY;
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Channel '%s' ready to transfer\n", iaxs[fr.callno]->owner ? iaxs[fr.callno]->owner->name : "<Unknown>");
- if (iaxs[fr.callno]->bridgecallno > -1) {
- if (iaxs[iaxs[fr.callno]->bridgecallno]->transferring == TRANSFER_READY) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Releasing %s and %s\n", iaxs[fr.callno]->owner ? iaxs[fr.callno]->owner->name : "<Unknown>",
- iaxs[iaxs[fr.callno]->bridgecallno]->owner ? iaxs[iaxs[fr.callno]->bridgecallno]->owner->name : "<Unknown>");
- /* They're both ready, now release them. */
- iaxs[iaxs[fr.callno]->bridgecallno]->transferring = TRANSFER_RELEASED;
- iaxs[fr.callno]->transferring = TRANSFER_RELEASED;
- iaxs[iaxs[fr.callno]->bridgecallno]->alreadygone = 1;
- iaxs[fr.callno]->alreadygone = 1;
- /* Stop doing lag & ping requests */
- stop_stuff(fr.callno);
- stop_stuff(iaxs[fr.callno]->bridgecallno);
- /* Send the release message */
- snprintf(rel0, sizeof(rel0), "peercallno=%d;", iaxs[iaxs[fr.callno]->bridgecallno]->peercallno);
- snprintf(rel1, sizeof(rel1), "peercallno=%d;", iaxs[fr.callno]->peercallno);
- send_command(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_TXREL, 0, rel0, strlen(rel0)+1, -1);
- send_command(iaxs[iaxs[fr.callno]->bridgecallno], AST_FRAME_IAX, AST_IAX_COMMAND_TXREL, 0, rel1, strlen(rel1)+1, -1);
- }
- }
- }
- break;
- case AST_IAX_COMMAND_TXREQ:
- if (f.data)
- ((char *)f.data)[f.datalen] = '\0';
- try_transfer(iaxs[fr.callno], (char *)f.data);
- break;
- case AST_IAX_COMMAND_TXCNT:
- if (iaxs[fr.callno]->transferring)
- send_command_transfer(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_TXACC, 0, NULL, 0);
- break;
- case AST_IAX_COMMAND_TXREL:
- if (f.data)
- ((char *)f.data)[f.datalen] = '\0';
- complete_transfer(fr.callno, (char *)f.data);
- break;
- case AST_IAX_COMMAND_DPREP:
- if (f.data)
- ((char *)f.data)[f.datalen] = '\0';
- complete_dpreply(iaxs[fr.callno], (char *)f.data);
- break;
- default:
- ast_log(LOG_DEBUG, "Unknown IAX command %d on %d/%d\n", f.subclass, fr.callno, iaxs[fr.callno]->peercallno);
- }
- /* Don't actually pass these frames along */
- ast_mutex_unlock(&iaxsl[fr.callno]);
- return 1;
- }
- } else {
- /* A mini frame */
- f.frametype = AST_FRAME_VOICE;
- if (iaxs[fr.callno]->voiceformat > 0)
- f.subclass = iaxs[fr.callno]->voiceformat;
- else {
- ast_log(LOG_WARNING, "Received mini frame before first full voice frame\n ");
- iax_vnak(fr.callno);
- ast_mutex_unlock(&iaxsl[fr.callno]);
- return 1;
- }
- f.datalen = res - sizeof(struct ast_iax_mini_hdr);
- if (f.datalen < 0) {
- ast_log(LOG_WARNING, "Datalen < 0?\n");
- ast_mutex_unlock(&iaxsl[fr.callno]);
- return 1;
- }
- if (f.datalen)
- f.data = buf + sizeof(struct ast_iax_mini_hdr);
- else
- f.data = NULL;
- fr.ts = (iaxs[fr.callno]->last & 0xFFFF0000L) | ntohs(mh->ts);
- }
- /* Don't pass any packets until we're started */
- if (!(iaxs[fr.callno]->state & IAX_STATE_STARTED)) {
- ast_mutex_unlock(&iaxsl[fr.callno]);
- return 1;
- }
- /* Common things */
- snprintf(src, sizeof(src), "IAX/%s/%d", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr),fr.callno); f.src = src;
- f.mallocd = 0;
- f.offset = 0;
- fr.f = &f;
- if (f.datalen && (f.frametype == AST_FRAME_VOICE))
- f.samples = get_samples(&f);
- else
- f.samples = 0;
- /* If this is our most recent packet, use it as our basis for timestamping */
- if (iaxs[fr.callno]->last < fr.ts) {
- iaxs[fr.callno]->last = fr.ts;
- fr.outoforder = 0;
- } else {
- if (option_debug)
- ast_log(LOG_DEBUG, "Received out of order packet... (type=%d, subclass %d, ts = %d, last = %d)\n", f.frametype, f.subclass, fr.ts, iaxs[fr.callno]->last);
- fr.outoforder = -1;
- }
- #ifdef BRIDGE_OPTIMIZATION
- if (iaxs[fr.callno]->bridgecallno > -1) {
- forward_delivery(&fr);
- } else {
- schedule_delivery(iaxfrdup2(&fr, 0), 1);
- }
- #else
- schedule_delivery(iaxfrdup2(&fr, 0), 1);
- #endif
- /* Always run again */
- ast_mutex_unlock(&iaxsl[fr.callno]);
- return 1;
- }
- static int iax_do_register(struct iax_registry *reg)
- {
- char requeststr[256] = "";
- if (option_debug)
- ast_log(LOG_DEBUG, "Sending registration request for '%s'\n", reg->username);
- if (reg->callno < 0) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Allocate call number\n");
- reg->callno = find_callno(-1, -1, ®->addr, NEW_FORCE);
- if (reg->callno < 0) {
- ast_log(LOG_WARNING, "Unable to create call for registration\n");
- return -1;
- } else if (option_debug)
- ast_log(LOG_DEBUG, "Registration created on call %d\n", reg->callno);
- iaxs[reg->callno]->reg = reg;
- }
- /* Schedule the next registration attempt */
- if (reg->expire > -1)
- ast_sched_del(sched, reg->expire);
- /* Setup the registration a little early */
- reg->expire = ast_sched_add(sched, (5 * reg->refresh / 6) * 1000, iax_do_register_s, reg);
- /* Send the request */
- MYSNPRINTF "peer=%s;refresh=%d;", reg->username, reg->refresh);
- send_command(iaxs[reg->callno],AST_FRAME_IAX, AST_IAX_COMMAND_REGREQ, 0, requeststr, strlen(requeststr) + 1, -1);
- reg->regstate = REG_STATE_REGSENT;
- return 0;
- }
- static int iax_poke_noanswer(void *data)
- {
- struct iax_peer *peer = data;
- peer->pokeexpire = -1;
- if (peer->lastms > -1)
- ast_log(LOG_NOTICE, "Peer '%s' is now UNREACHABLE!\n", peer->name);
- if (peer->callno > 0)
- iax_destroy(peer->callno);
- peer->callno = 0;
- peer->lastms = -1;
- /* Try again quickly */
- peer->pokeexpire = ast_sched_add(sched, DEFAULT_FREQ_NOTOK, iax_poke_peer_s, peer);
- return 0;
- }
- static int iax_poke_peer(struct iax_peer *peer)
- {
- if (!peer->maxms || !peer->addr.sin_addr.s_addr) {
- /* IF we have no IP, or this isn't to be monitored, return
- imeediately after clearing things out */
- peer->lastms = 0;
- peer->pokeexpire = -1;
- peer->callno = 0;
- return 0;
- }
- if (peer->callno > 0) {
- ast_log(LOG_NOTICE, "Still have a callno...\n");
- iax_destroy(peer->callno);
- }
- peer->callno = find_callno(-1, -1, &peer->addr, NEW_FORCE);
- if (peer->callno < 0) {
- ast_log(LOG_WARNING, "Unable to allocate call for poking peer '%s'\n", peer->name);
- return -1;
- }
- if (peer->pokeexpire > -1)
- ast_sched_del(sched, peer->pokeexpire);
- /* Speed up retransmission times */
- iaxs[peer->callno]->pingtime = peer->maxms / 4 + 1;
- iaxs[peer->callno]->peerpoke = peer;
- send_command(iaxs[peer->callno], AST_FRAME_IAX, AST_IAX_COMMAND_POKE, 0, NULL, 0, -1);
- peer->pokeexpire = ast_sched_add(sched, DEFAULT_MAXMS * 2, iax_poke_noanswer, peer);
- return 0;
- }
- static void free_context(struct iax_context *con)
- {
- struct iax_context *conl;
- while(con) {
- conl = con;
- con = con->next;
- free(conl);
- }
- }
- static struct ast_channel *iax_request(char *type, int format, void *data)
- {
- int callno;
- int res;
- int sendani;
- int maxtime;
- int fmt, native;
- struct sockaddr_in sin;
- char s[256];
- char *st;
- struct ast_channel *c;
- char *stringp=NULL;
- int capability = iax_capability;
- strncpy(s, (char *)data, sizeof(s)-1);
- /* FIXME The next two lines seem useless */
- stringp=s;
- strsep(&stringp, "/");
- stringp=s;
- strsep(&stringp, "@");
- st = strsep(&stringp, "@");
- if (!st)
- st = s;
- /* Populate our address from the given */
- if (create_addr(&sin, &capability, &sendani, &maxtime, st, NULL)) {
- return NULL;
- }
- callno = find_callno(-1, -1, &sin, NEW_FORCE);
- if (callno < 0) {
- ast_log(LOG_WARNING, "Unable to create call\n");
- return NULL;
- }
- ast_mutex_lock(&iaxsl[callno]);
- /* Keep track of sendani flag */
- iaxs[callno]->sendani = sendani;
- iaxs[callno]->maxtime = maxtime;
- c = ast_iax_new(iaxs[callno], AST_STATE_DOWN, capability);
- ast_mutex_unlock(&iaxsl[callno]);
- if (c) {
- /* Choose a format we can live with */
- if (c->nativeformats & format)
- c->nativeformats &= format;
- else {
- native = c->nativeformats;
- fmt = format;
- res = ast_translator_best_choice(&fmt, &native);
- if (res < 0) {
- ast_log(LOG_WARNING, "Unable to create translator path for %s to %s on %s\n", ast_getformatname(c->nativeformats), ast_getformatname(fmt), c->name);
- ast_hangup(c);
- return NULL;
- }
- c->nativeformats = native;
- }
- }
- return c;
- }
- static void *network_thread(void *ignore)
- {
- /* Our job is simple: Send queued messages, retrying if necessary. Read frames
- from the network, and queue them for delivery to the channels */
- int res;
- struct ast_iax_frame *f, *freeme;
- /* Establish I/O callback for socket read */
- ast_io_add(io, netsocket, socket_read, AST_IO_IN, NULL);
- for(;;) {
- /* Go through the queue, sending messages which have not yet been
- sent, and scheduling retransmissions if appropriate */
- ast_mutex_lock(&iaxq.lock);
- f = iaxq.head;
- while(f) {
- freeme = NULL;
- if (!f->sentyet) {
- f->sentyet++;
- /* Send a copy immediately -- errors here are ok, so don't bother locking */
- if (iaxs[f->callno]) {
- send_packet(f);
- }
- if (f->retries < 0) {
- /* This is not supposed to be retransmitted */
- if (f->prev)
- f->prev->next = f->next;
- else
- iaxq.head = f->next;
- if (f->next)
- f->next->prev = f->prev;
- else
- iaxq.tail = f->prev;
- iaxq.count--;
- /* Free the frame */
- ast_frfree(f->f);
- f->f = NULL;
- /* Free the iax frame */
- freeme = f;
- } else {
- /* We need reliable delivery. Schedule a retransmission */
- f->retries++;
- f->retrans = ast_sched_add(sched, f->retrytime, attempt_transmit, f);
- }
- }
- f = f->next;
- if (freeme)
- ast_iax_frame_free(freeme);
- }
- ast_mutex_unlock(&iaxq.lock);
- res = ast_sched_wait(sched);
- if ((res > 1000) || (res < 0))
- res = 1000;
- res = ast_io_wait(io, res);
- if (res >= 0) {
- ast_sched_runq(sched);
- }
- }
- return NULL;
- }
- static int start_network_thread(void)
- {
- return ast_pthread_create(&netthreadid, NULL, network_thread, NULL);
- }
- static struct iax_context *build_context(char *context)
- {
- struct iax_context *con = malloc(sizeof(struct iax_context));
- if (con) {
- strncpy(con->context, context, sizeof(con->context)-1);
- con->next = NULL;
- }
- return con;
- }
- static struct iax_peer *build_peer(char *name, struct ast_variable *v)
- {
- struct iax_peer *peer;
- struct iax_peer *prev;
- int maskfound=0;
- int format;
- int found=0;
- prev = NULL;
- ast_mutex_lock(&peerl.lock);
- peer = peerl.peers;
- while(peer) {
- if (!strcasecmp(peer->name, name)) {
- break;
- }
- prev = peer;
- peer = peer->next;
- }
- if (peer) {
- found++;
- /* Already in the list, remove it and it will be added back (or FREE'd) */
- if (prev) {
- prev->next = peer->next;
- } else {
- peerl.peers = peer->next;
- }
- ast_mutex_unlock(&peerl.lock);
- } else {
- ast_mutex_unlock(&peerl.lock);
- peer = malloc(sizeof(struct iax_peer));
- memset(peer, 0, sizeof(struct iax_peer));
- peer->expire = -1;
- peer->pokeexpire = -1;
- }
- if (peer) {
- if (!found) {
- strncpy(peer->name, name, sizeof(peer->name)-1);
- peer->addr.sin_port = htons(AST_DEFAULT_IAX_PORTNO);
- peer->expirey = expirey;
- }
- peer->capability = iax_capability;
- while(v) {
- if (!strcasecmp(v->name, "secret"))
- strncpy(peer->secret, v->value, sizeof(peer->secret)-1);
- else if (!strcasecmp(v->name, "auth"))
- strncpy(peer->methods, v->value, sizeof(peer->methods)-1);
- else if (!strcasecmp(v->name, "host")) {
- if (!strcasecmp(v->value, "dynamic")) {
- /* They'll register with us */
- peer->dynamic = 1;
- if (!found) {
- /* Initialize stuff iff we're not found, otherwise
- we keep going with what we had */
- memset(&peer->addr.sin_addr, 0, 4);
- if (peer->addr.sin_port) {
- /* If we've already got a port, make it the default rather than absolute */
- peer->defaddr.sin_port = peer->addr.sin_port;
- peer->addr.sin_port = 0;
- }
- }
- } else {
- /* Non-dynamic. Make sure we become that way if we're not */
- if (peer->expire > -1)
- ast_sched_del(sched, peer->expire);
- peer->expire = -1;
- peer->dynamic = 0;
- if (ast_get_ip(&peer->addr, v->value)) {
- free(peer);
- return NULL;
- }
- }
- if (!maskfound)
- inet_aton("255.255.255.255", &peer->mask);
- } else if (!strcasecmp(v->name, "defaultip")) {
- if (ast_get_ip(&peer->defaddr, v->value)) {
- free(peer);
- return NULL;
- }
- } else if (!strcasecmp(v->name, "permit") ||
- !strcasecmp(v->name, "deny")) {
- peer->ha = ast_append_ha(v->name, v->value, peer->ha);
- } else if (!strcasecmp(v->name, "mask")) {
- maskfound++;
- inet_aton(v->value, &peer->mask);
- } else if (!strcasecmp(v->name, "context")) {
- if (!strlen(peer->context))
- strncpy(peer->context, v->value, sizeof(peer->context) - 1);
- } else if (!strcasecmp(v->name, "port")) {
- if (peer->dynamic)
- peer->defaddr.sin_port = htons(atoi(v->value));
- else
- peer->addr.sin_port = htons(atoi(v->value));
- } else if (!strcasecmp(v->name, "username")) {
- strncpy(peer->username, v->value, sizeof(peer->username)-1);
- } else if (!strcasecmp(v->name, "allow")) {
- format = ast_getformatbyname(v->value);
- if (format < 1)
- ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
- else
- peer->capability |= format;
- } else if (!strcasecmp(v->name, "disallow")) {
- format = ast_getformatbyname(v->value);
- if (format < 1)
- ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value);
- else
- peer->capability &= ~format;
- } else if (!strcasecmp(v->name, "callerid")) {
- strncpy(peer->callerid, v->value, sizeof(peer->callerid)-1);
- peer->hascallerid=1;
- } else if (!strcasecmp(v->name, "sendani")) {
- peer->sendani = ast_true(v->value);
- } else if (!strcasecmp(v->name, "inkeys")) {
- strncpy(peer->inkeys, v->value, sizeof(peer->inkeys) - 1);
- } else if (!strcasecmp(v->name, "outkey")) {
- strncpy(peer->outkey, v->value, sizeof(peer->outkey) - 1);
- } else if (!strcasecmp(v->name, "qualify")) {
- if (!strcasecmp(v->value, "no")) {
- peer->maxms = 0;
- } else if (!strcasecmp(v->value, "yes")) {
- peer->maxms = DEFAULT_MAXMS;
- } else if (sscanf(v->value, "%d", &peer->maxms) != 1) {
- ast_log(LOG_WARNING, "Qualification of peer '%s' should be 'yes', 'no', or a number of milliseconds at line %d of " IAX_CONF_FILE "\n", peer->name, v->lineno);
- peer->maxms = 0;
- }
- } //else if (strcasecmp(v->name,"type"))
- // ast_log(LOG_WARNING, "Ignoring %s\n", v->name);
- v=v->next;
- }
- if (!strlen(peer->methods))
- strncpy(peer->methods, "md5,plaintext", sizeof(peer->methods) - 1);
- peer->delme = 0;
- }
- return peer;
- }
- static struct iax_user *build_user(char *name, struct ast_variable *v)
- {
- struct iax_user *user;
- struct iax_context *con, *conl = NULL;
- int format;
- user = (struct iax_user *)malloc(sizeof(struct iax_user));
- if (user) {
- memset(user, 0, sizeof(struct iax_user));
- strncpy(user->name, name, sizeof(user->name)-1);
- while(v) {
- if (!strcasecmp(v->name, "context")) {
- con = build_context(v->value);
- if (con) {
- if (conl)
- conl->next = con;
- else
- user->contexts = con;
- conl = con;
- }
- } else if (!strcasecmp(v->name, "permit") ||
- !strcasecmp(v->name, "deny")) {
- user->ha = ast_append_ha(v->name, v->value, user->ha);
- } else if (!strcasecmp(v->name, "auth")) {
- strncpy(user->methods, v->value, sizeof(user->methods)-1);
- } else if (!strcasecmp(v->name, "secret")) {
- strncpy(user->secret, v->value, sizeof(user->secret)-1);
- } else if (!strcasecmp(v->name, "callerid")) {
- strncpy(user->callerid, v->value, sizeof(user->callerid)-1);
- user->hascallerid=1;
- } else if (!strcasecmp(v->name, "accountcode")) {
- strncpy(user->accountcode, v->value, sizeof(user->accountcode)-1);
- } else if (!strcasecmp(v->name, "amaflags")) {
- format = ast_cdr_amaflags2int(v->value);
- if (format < 0) {
- ast_log(LOG_WARNING, "Invalid AMA Flags: %s at line %d\n", v->value, v->lineno);
- } else {
- user->amaflags = format;
- }
- } else if (!strcasecmp(v->name, "inkeys")) {
- strncpy(user->inkeys, v->value, sizeof(user->inkeys) - 1);
- } //else if (strcasecmp(v->name,"type"))
- // ast_log(LOG_WARNING, "Ignoring %s\n", v->name);
- v = v->next;
- }
- }
- if (!strlen(user->methods)) {
- if (strlen(user->secret)) {
- strncpy(user->methods, "md5,plaintext", sizeof(user->methods) - 1);
- if (strlen(user->inkeys))
- strncat(user->methods, ",rsa", sizeof(user->methods) - 1);
- } else if (strlen(user->inkeys)) {
- strncpy(user->methods, "rsa", sizeof(user->methods) - 1);
- } else
- strncpy(user->methods, "md5,plaintext", sizeof(user->methods) -1);
- }
- return user;
- }
- static void delete_users(void){
- struct iax_user *user, *userlast;
- struct iax_peer *peer;
- struct iax_registry *reg, *regl;
- /* Delete all users */
- ast_mutex_lock(&userl.lock);
- for (user=userl.users;user;) {
- ast_free_ha(user->ha);
- free_context(user->contexts);
- userlast = user;
- user=user->next;
- free(userlast);
- }
- userl.users=NULL;
- ast_mutex_unlock(&userl.lock);
- for (reg = registrations;reg;) {
- regl = reg;
- reg = reg->next;
- if (regl->expire > -1)
- ast_sched_del(sched, regl->expire);
- free(regl);
- }
- registrations = NULL;
- ast_mutex_lock(&peerl.lock);
- for (peer=peerl.peers;peer;) {
- /* Assume all will be deleted, and we'll find out for sure later */
- peer->delme = 1;
- peer = peer->next;
- }
- ast_mutex_unlock(&peerl.lock);
- }
- static void prune_peers(void){
- /* Prune peers who still are supposed to be deleted */
- struct iax_peer *peer, *peerlast, *peernext;
- int x;
- ast_mutex_lock(&peerl.lock);
- peerlast = NULL;
- for (peer=peerl.peers;peer;) {
- peernext = peer->next;
- if (peer->delme) {
- for (x=0;x<AST_IAX_MAX_CALLS;x++) {
- ast_mutex_lock(&iaxsl[x]);
- if (iaxs[x] && (iaxs[x]->peerpoke == peer)) {
- iax_destroy(x);
- }
- ast_mutex_unlock(&iaxsl[x]);
- }
- /* Delete it, it needs to disappear */
- if (peer->expire > -1)
- ast_sched_del(sched, peer->expire);
- if (peer->pokeexpire > -1)
- ast_sched_del(sched, peer->pokeexpire);
- if (peer->callno > 0)
- iax_destroy(peer->callno);
- free(peer);
- if (peerlast)
- peerlast->next = peernext;
- else
- peerl.peers = peernext;
- } else
- peerlast = peer;
- peer=peernext;
- }
- ast_mutex_unlock(&peerl.lock);
- }
- static int set_config(char *config_file, struct sockaddr_in* sin){
- struct ast_config *cfg;
- int capability=iax_capability;
- struct ast_variable *v;
- char *cat;
- char *utype;
- int format;
- struct iax_user *user;
- struct iax_peer *peer;
- static unsigned short int last_port=0;
- cfg = ast_load(config_file);
-
- if (!cfg) {
- ast_log(LOG_ERROR, "Unable to load config %s\n", config_file);
- return -1;
- }
- v = ast_variable_browse(cfg, "general");
- while(v) {
- if (!strcasecmp(v->name, "port")){
- sin->sin_port = ntohs(atoi(v->value));
- if(last_port==0){
- last_port=sin->sin_port;
- #if 0
- ast_verbose("setting last port\n");
- #endif
- }
- else if(sin->sin_port != last_port)
- ast_log(LOG_WARNING, "change to port ignored until next asterisk re-start\n");
- }
- else if (!strcasecmp(v->name, "pingtime"))
- ping_time = atoi(v->value);
- else if (!strcasecmp(v->name, "maxjitterbuffer"))
- maxjitterbuffer = atoi(v->value);
- else if (!strcasecmp(v->name, "maxexcessbuffer"))
- max_jitter_buffer = atoi(v->value);
- else if (!strcasecmp(v->name, "lagrqtime"))
- lagrq_time = atoi(v->value);
- else if (!strcasecmp(v->name, "dropcount"))
- iax_dropcount = atoi(v->value);
- else if (!strcasecmp(v->name, "bindaddr"))
- inet_aton(v->value, &sin->sin_addr);
- else if (!strcasecmp(v->name, "jitterbuffer"))
- use_jitterbuffer = ast_true(v->value);
- else if (!strcasecmp(v->name, "bandwidth")) {
- if (!strcasecmp(v->value, "low")) {
- capability = IAX_CAPABILITY_LOWBANDWIDTH;
- } else if (!strcasecmp(v->value, "medium")) {
- capability = IAX_CAPABILITY_MEDBANDWIDTH;
- } else if (!strcasecmp(v->value, "high")) {
- capability = IAX_CAPABILITY_FULLBANDWIDTH;
- } else
- ast_log(LOG_WARNING, "bandwidth must be either low, medium, or high\n");
- } else if (!strcasecmp(v->name, "allow")) {
- format = ast_getformatbyname(v->value);
- if (format < 1)
- ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
- else
- capability |= format;
- } else if (!strcasecmp(v->name, "disallow")) {
- format = ast_getformatbyname(v->value);
- if (format < 1)
- ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value);
- else
- capability &= ~format;
- } else if (!strcasecmp(v->name, "register")) {
- iax_register(v->value, v->lineno);
- } else if (!strcasecmp(v->name, "tos")) {
- if (sscanf(v->value, "%i", &format) == 1)
- tos = format & 0xff;
- else if (!strcasecmp(v->value, "lowdelay"))
- tos = IPTOS_LOWDELAY;
- else if (!strcasecmp(v->value, "throughput"))
- tos = IPTOS_THROUGHPUT;
- else if (!strcasecmp(v->value, "reliability"))
- tos = IPTOS_RELIABILITY;
- else if (!strcasecmp(v->value, "mincost"))
- tos = IPTOS_MINCOST;
- else if (!strcasecmp(v->value, "none"))
- tos = 0;
- else
- ast_log(LOG_WARNING, "Invalid tos value at line %d, should be 'lowdelay', 'throughput', 'reliability', 'mincost', or 'none'\n", v->lineno);
- } else if (!strcasecmp(v->name, "accountcode")) {
- strncpy(accountcode, v->value, sizeof(accountcode)-1);
- } else if (!strcasecmp(v->name, "amaflags")) {
- format = ast_cdr_amaflags2int(v->value);
- if (format < 0) {
- ast_log(LOG_WARNING, "Invalid AMA Flags: %s at line %d\n", v->value, v->lineno);
- } else {
- amaflags = format;
- }
-
- #ifdef MYSQL_FRIENDS
- } else if (!strcasecmp(v->name, "dbuser")) {
- strncpy(mydbuser, v->value, sizeof(mydbuser) - 1);
- } else if (!strcasecmp(v->name, "dbpass")) {
- strncpy(mydbpass, v->value, sizeof(mydbpass) - 1);
- } else if (!strcasecmp(v->name, "dbhost")) {
- strncpy(mydbhost, v->value, sizeof(mydbhost) - 1);
- } else if (!strcasecmp(v->name, "dbname")) {
- strncpy(mydbname, v->value, sizeof(mydbname) - 1);
- #endif
- } //else if (strcasecmp(v->name,"type"))
- // ast_log(LOG_WARNING, "Ignoring %s\n", v->name);
- v = v->next;
- }
- iax_capability = capability;
- cat = ast_category_browse(cfg, NULL);
- while(cat) {
- if (strcasecmp(cat, "general")) {
- utype = ast_variable_retrieve(cfg, cat, "type");
- if (utype) {
- if (!strcasecmp(utype, "user") || !strcasecmp(utype, "friend")) {
- user = build_user(cat, ast_variable_browse(cfg, cat));
- if (user) {
- ast_mutex_lock(&userl.lock);
- user->next = userl.users;
- userl.users = user;
- ast_mutex_unlock(&userl.lock);
- }
- }
- if (!strcasecmp(utype, "peer") || !strcasecmp(utype, "friend")) {
- peer = build_peer(cat, ast_variable_browse(cfg, cat));
- if (peer) {
- ast_mutex_lock(&peerl.lock);
- peer->next = peerl.peers;
- peerl.peers = peer;
- ast_mutex_unlock(&peerl.lock);
- }
- } else if (strcasecmp(utype, "user")) {
- ast_log(LOG_WARNING, "Unknown type '%s' for '%s' in %s\n", utype, cat, config_file);
- }
- } else
- ast_log(LOG_WARNING, "Section '%s' lacks type\n", cat);
- }
- cat = ast_category_browse(cfg, cat);
- }
- ast_destroy(cfg);
- #ifdef MYSQL_FRIENDS
- /* Connect to db if appropriate */
- if (!mysql && strlen(mydbname)) {
- mysql = mysql_init(NULL);
- if (!mysql_real_connect(mysql, mydbhost[0] ? mydbhost : NULL, mydbuser, mydbpass, mydbname, 0, NULL, 0)) {
- memset(mydbpass, '*', strlen(mydbpass));
- ast_log(LOG_WARNING, "Database connection failed (db=%s, host=%s, user=%s, pass=%s)!\n",
- mydbname, mydbhost, mydbuser, mydbpass);
- free(mysql);
- mysql = NULL;
- } else
- ast_verbose(VERBOSE_PREFIX_1 "Connected to database '%s' on '%s' as '%s'\n",
- mydbname, mydbhost, mydbuser);
- }
- #endif
- return capability;
- }
- static int reload_config(void)
- {
- char *config = IAX_CONF_FILE;
- struct iax_registry *reg;
- struct sockaddr_in dead_sin;
- strncpy(accountcode, "", sizeof(accountcode)-1);
- amaflags = 0;
- srand(time(NULL));
- delete_users();
- if (set_config(config,&dead_sin) == -1) {
- config = IAX_OLD_CONF_FILE;
- set_config(config,&dead_sin);
- }
- prune_peers();
- for (reg = registrations; reg; reg = reg->next)
- iax_do_register(reg);
- return 0;
- }
- int reload(void)
- {
- return reload_config();
- }
- static int cache_get_callno(char *data)
- {
- struct sockaddr_in sin;
- int x;
- char st[256], *s;
- char *host;
- char *username=NULL;
- char *password=NULL;
- char *context=NULL;
- char requeststr[256] = "";
- int callno;
- for (x=0;x<AST_IAX_MAX_CALLS; x++) {
- /* Look for an *exact match* call. Once a call is negotiated, it can only
- look up entries for a single context */
- if (!ast_mutex_trylock(&iaxsl[x])) {
- if (iaxs[x] && !strcasecmp(data, iaxs[x]->dproot)) {
- ast_mutex_unlock(&iaxsl[x]);
- return x;
- }
- ast_mutex_unlock(&iaxsl[x]);
- }
- }
- /* No match found, we need to create a new one */
- strncpy(st, data, sizeof(st)-1);
- /* Grab the host */
- s = strchr(st, '/');
- if (s) {
- *s = '\0';
- s++;
- context = s;
- }
- s = strchr(st, '@');
- if (s) {
- /* Get username/password if there is one */
- *s='\0';
- username=st;
- password = strchr(username, ':');
- if (password) {
- *password = '\0';
- password++;
- }
- s++;
- host = s;
- } else {
- /* Just a hostname */
- host = st;
- }
- /* Populate our address from the given */
- if (create_addr(&sin, NULL, NULL, NULL, host, NULL)) {
- return -1;
- }
- ast_log(LOG_DEBUG, "host: %s, user: %s, password: %s, context: %s\n", host, username, password, context);
- callno = find_callno(-1, -1, &sin, NEW_FORCE);
- if (callno < 0) {
- ast_log(LOG_WARNING, "Unable to create call\n");
- return -1;
- }
- ast_mutex_lock(&iaxsl[callno]);
- strncpy(iaxs[callno]->dproot, data, sizeof(iaxs[callno]->dproot)-1);
- iaxs[callno]->capability = IAX_CAPABILITY_FULLBANDWIDTH;
- MYSNPRINTF "exten=TBD;");
- if (context)
- MYSNPRINTF "context=%s;", context);
- if (username)
- MYSNPRINTF "username=%s;", username);
- /* Remember, codec is irrelevent */
- MYSNPRINTF "formats=%d;", IAX_CAPABILITY_FULLBANDWIDTH);
- MYSNPRINTF "capability=%d;", IAX_CAPABILITY_FULLBANDWIDTH);
- MYSNPRINTF "version=%d;", AST_IAX_PROTO_VERSION);
- if (strlen(requeststr))
- requeststr[strlen(requeststr) -1 ] = '\0';
- /* Keep password handy */
- if (password)
- strncpy(iaxs[callno]->secret, password, sizeof(iaxs[callno]->secret)-1);
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Calling TBD using options '%s'\n", requeststr);
- /* Start the call going */
- send_command(iaxs[callno], AST_FRAME_IAX, AST_IAX_COMMAND_NEW, 0, requeststr, strlen(requeststr) + 1, -1);
- ast_mutex_unlock(&iaxsl[callno]);
- return callno;
- }
- static struct iax_dpcache *find_cache(struct ast_channel *chan, char *data, char *context, char *exten, int priority)
- {
- struct iax_dpcache *dp, *prev = NULL, *next;
- struct timeval tv;
- int x;
- int com[2];
- int timeout;
- int old=0;
- int outfd;
- int abort;
- int callno;
- struct ast_channel *c;
- struct ast_frame *f;
- gettimeofday(&tv, NULL);
- dp = dpcache;
- while(dp) {
- next = dp->next;
- /* Expire old caches */
- if ((tv.tv_sec > dp->expirey.tv_sec) ||
- ((tv.tv_sec == dp->expirey.tv_sec) && (tv.tv_usec > dp->expirey.tv_usec))) {
- /* It's expired, let it disappear */
- if (prev)
- prev->next = dp->next;
- else
- dpcache = dp->next;
- if (!dp->peer && !(dp->flags & CACHE_FLAG_PENDING) && (dp->callno == -1)) {
- /* Free memory and go again */
- free(dp);
- } else {
- ast_log(LOG_WARNING, "DP still has peer field or pending or callno (flags = %d, peer = %p callno = %d)\n", dp->flags, dp->peer, dp->callno);
- }
- dp = next;
- continue;
- }
- /* We found an entry that matches us! */
- if (!strcmp(dp->peercontext, data) && !strcmp(dp->exten, exten))
- break;
- prev = dp;
- dp = next;
- }
- if (!dp) {
- /* No matching entry. Create a new one. */
- /* First, can we make a callno? */
- callno = cache_get_callno(data);
- if (callno < 0) {
- ast_log(LOG_WARNING, "Unable to generate call for '%s'\n", data);
- return NULL;
- }
- dp = malloc(sizeof(struct iax_dpcache));
- if (!dp)
- return NULL;
- memset(dp, 0, sizeof(struct iax_dpcache));
- dp->callno = -1;
- strncpy(dp->peercontext, data, sizeof(dp->peercontext)-1);
- strncpy(dp->exten, exten, sizeof(dp->exten)-1);
- gettimeofday(&dp->expirey, NULL);
- dp->orig = dp->expirey;
- /* Expires in 30 mins by default */
- dp->expirey.tv_sec += iaxdefaultdpcache;
- dp->next = dpcache;
- dp->flags = CACHE_FLAG_PENDING;
- for (x=0;x<sizeof(dp->waiters) / sizeof(dp->waiters[0]); x++)
- dp->waiters[x] = -1;
- dpcache = dp;
- dp->peer = iaxs[callno]->dpentries;
- iaxs[callno]->dpentries = dp;
- /* Send the request if we're already up */
- if (iaxs[callno]->state & IAX_STATE_STARTED)
- iax_dprequest(dp, callno);
- }
- /* By here we must have a dp */
- if (dp->flags & CACHE_FLAG_PENDING) {
- /* Okay, here it starts to get nasty. We need a pipe now to wait
- for a reply to come back so long as it's pending */
- for (x=0;x<sizeof(dp->waiters) / sizeof(dp->waiters[0]); x++) {
- /* Find an empty slot */
- if (dp->waiters[x] < 0)
- break;
- }
- if (x >= sizeof(dp->waiters) / sizeof(dp->waiters[0])) {
- ast_log(LOG_WARNING, "No more waiter positions available\n");
- return NULL;
- }
- if (pipe(com)) {
- ast_log(LOG_WARNING, "Unable to create pipe for comm\n");
- return NULL;
- }
- dp->waiters[x] = com[1];
- /* Okay, now we wait */
- timeout = iaxdefaulttimeout * 1000;
- /* Temporarily unlock */
- ast_mutex_unlock(&dpcache_lock);
- /* Defer any dtmf */
- if (chan)
- old = ast_channel_defer_dtmf(chan);
- abort = 0;
- while(timeout) {
- c = ast_waitfor_nandfds(&chan, chan ? 1 : 0, &com[0], 1, NULL, &outfd, &timeout);
- if (outfd > -1) {
- break;
- }
- if (c) {
- f = ast_read(c);
- if (f)
- ast_frfree(f);
- else {
- /* Got hung up on, abort! */
- break;
- abort = 1;
- }
- }
- }
- if (!timeout) {
- ast_log(LOG_WARNING, "Timeout waiting for %s exten %s\n", data, exten);
- }
- ast_mutex_lock(&dpcache_lock);
- dp->waiters[x] = -1;
- close(com[1]);
- close(com[0]);
- if (abort) {
- /* Don't interpret anything, just abort. Not sure what th epoint
- of undeferring dtmf on a hung up channel is but hey whatever */
- if (!old && chan)
- ast_channel_undefer_dtmf(chan);
- return NULL;
- }
- if (!(dp->flags & CACHE_FLAG_TIMEOUT)) {
- /* Now to do non-independent analysis the results of our wait */
- if (dp->flags & CACHE_FLAG_PENDING) {
- /* Still pending... It's a timeout. Wake everybody up. Consider it no longer
- pending. Don't let it take as long to timeout. */
- dp->flags &= ~CACHE_FLAG_PENDING;
- dp->flags |= CACHE_FLAG_TIMEOUT;
- /* Expire after only 60 seconds now. This is designed to help reduce backlog in heavily loaded
- systems without leaving it unavailable once the server comes back online */
- dp->expirey.tv_sec = dp->orig.tv_sec + 60;
- for (x=0;x<sizeof(dp->waiters) / sizeof(dp->waiters[0]); x++)
- if (dp->waiters[x] > -1)
- write(dp->waiters[x], "asdf", 4);
- }
- }
- /* Our caller will obtain the rest */
- if (!old && chan)
- ast_channel_undefer_dtmf(chan);
- }
- return dp;
- }
- static int iax_exists(struct ast_channel *chan, char *context, char *exten, int priority, char *callerid, char *data)
- {
- struct iax_dpcache *dp;
- int res = 0;
- #if 0
- ast_log(LOG_NOTICE, "iax_exists: con: %s, exten: %s, pri: %d, cid: %s, data: %s\n", context, exten, priority, callerid ? callerid : "<unknown>", data);
- #endif
- if (priority != 1)
- return 0;
- ast_mutex_lock(&dpcache_lock);
- dp = find_cache(chan, data, context, exten, priority);
- if (dp) {
- if (dp->flags & CACHE_FLAG_EXISTS)
- res= 1;
- }
- ast_mutex_unlock(&dpcache_lock);
- if (!dp) {
- ast_log(LOG_WARNING, "Unable to make DP cache\n");
- }
- return res;
- }
- static int iax_canmatch(struct ast_channel *chan, char *context, char *exten, int priority, char *callerid, char *data)
- {
- int res = 0;
- struct iax_dpcache *dp;
- #if 0
- ast_log(LOG_NOTICE, "iax_canmatch: con: %s, exten: %s, pri: %d, cid: %s, data: %s\n", context, exten, priority, callerid ? callerid : "<unknown>", data);
- #endif
- if (priority != 1)
- return 0;
- ast_mutex_lock(&dpcache_lock);
- dp = find_cache(chan, data, context, exten, priority);
- if (dp) {
- if (dp->flags & CACHE_FLAG_CANEXIST)
- res= 1;
- }
- ast_mutex_unlock(&dpcache_lock);
- if (!dp) {
- ast_log(LOG_WARNING, "Unable to make DP cache\n");
- }
- return res;
- }
- static int iax_matchmore(struct ast_channel *chan, char *context, char *exten, int priority, char *callerid, char *data)
- {
- int res = 0;
- struct iax_dpcache *dp;
- #if 0
- ast_log(LOG_NOTICE, "iax_matchmore: con: %s, exten: %s, pri: %d, cid: %s, data: %s\n", context, exten, priority, callerid ? callerid : "<unknown>", data);
- #endif
- if (priority != 1)
- return 0;
- ast_mutex_lock(&dpcache_lock);
- dp = find_cache(chan, data, context, exten, priority);
- if (dp) {
- if (dp->flags & CACHE_FLAG_MATCHMORE)
- res= 1;
- }
- ast_mutex_unlock(&dpcache_lock);
- if (!dp) {
- ast_log(LOG_WARNING, "Unable to make DP cache\n");
- }
- return res;
- }
- static int iax_exec(struct ast_channel *chan, char *context, char *exten, int priority, char *callerid, int newstack, char *data)
- {
- char odata[256];
- char req[256];
- char *ncontext;
- struct iax_dpcache *dp;
- struct ast_app *dial;
- #if 0
- ast_log(LOG_NOTICE, "iax_exec: con: %s, exten: %s, pri: %d, cid: %s, data: %s, newstack: %d\n", context, exten, priority, callerid ? callerid : "<unknown>", data, newstack);
- #endif
- if (priority != 1)
- return -1;
- ast_mutex_lock(&dpcache_lock);
- dp = find_cache(chan, data, context, exten, priority);
- if (dp) {
- if (dp->flags & CACHE_FLAG_EXISTS) {
- strncpy(odata, data, sizeof(odata)-1);
- ncontext = strchr(odata, '/');
- if (ncontext) {
- *ncontext = '\0';
- ncontext++;
- snprintf(req, sizeof(req), "IAX/%s/%s@%s", odata, exten, ncontext);
- } else {
- snprintf(req, sizeof(req), "IAX/%s/%s", odata, exten);
- }
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Executing Dial('%s')\n", req);
- } else {
- ast_mutex_unlock(&dpcache_lock);
- ast_log(LOG_WARNING, "Can't execute non-existant extension '%s[@%s]' in data '%s'\n", exten, context, data);
- return -1;
- }
- }
- ast_mutex_unlock(&dpcache_lock);
- dial = pbx_findapp("Dial");
- if (dial) {
- pbx_exec(chan, dial, req, newstack);
- } else {
- ast_log(LOG_WARNING, "No dial application registered\n");
- }
- return -1;
- }
- static struct ast_switch iax_switch =
- {
- name: "IAX",
- description: "IAX Remote Dialplan Switch",
- exists: iax_exists,
- canmatch: iax_canmatch,
- exec: iax_exec,
- matchmore: iax_matchmore,
- };
- static int __unload_module(void)
- {
- int x;
- /* Cancel the network thread, close the net socket */
- if (netthreadid != AST_PTHREADT_NULL) {
- pthread_cancel(netthreadid);
- pthread_join(netthreadid, NULL);
- }
- close(netsocket);
- for (x=0;x<AST_IAX_MAX_CALLS;x++)
- if (iaxs[x])
- iax_destroy(x);
- ast_manager_unregister( "IAX1peers" );
- ast_cli_unregister(&cli_show_users);
- ast_cli_unregister(&cli_show_channels);
- ast_cli_unregister(&cli_show_peers);
- ast_cli_unregister(&cli_show_registry);
- ast_cli_unregister(&cli_debug);
- ast_cli_unregister(&cli_no_debug);
- ast_cli_unregister(&cli_set_jitter);
- ast_cli_unregister(&cli_show_stats);
- ast_cli_unregister(&cli_show_cache);
- ast_unregister_switch(&iax_switch);
- ast_channel_unregister(type);
- ast_channel_unregister(ctype);
- delete_users();
- return 0;
- }
- int unload_module()
- {
- int x;
- for (x=0;x<AST_IAX_MAX_CALLS;x++)
- ast_mutex_destroy(&iaxsl[x]);
- ast_mutex_destroy(&iaxq.lock);
- ast_mutex_destroy(&userl.lock);
- ast_mutex_destroy(&peerl.lock);
- return __unload_module();
- }
- int load_module(void)
- {
- char *config = IAX_CONF_FILE;
- int res = 0;
- int x;
- struct iax_registry *reg;
- struct iax_peer *peer;
- char iabuf[INET_ADDRSTRLEN];
-
- struct sockaddr_in sin;
-
- /* Seed random number generator */
- srand(time(NULL));
-
- sin.sin_family = AF_INET;
- sin.sin_port = ntohs(AST_DEFAULT_IAX_PORTNO);
- sin.sin_addr.s_addr = INADDR_ANY;
- for (x=0;x<AST_IAX_MAX_CALLS;x++)
- ast_mutex_init(&iaxsl[x]);
-
- io = io_context_create();
- sched = sched_context_create();
-
- if (!io || !sched) {
- ast_log(LOG_ERROR, "Out of memory\n");
- return -1;
- }
- ast_mutex_init(&iaxq.lock);
- ast_mutex_init(&userl.lock);
- ast_mutex_init(&peerl.lock);
- ast_cli_register(&cli_show_users);
- ast_cli_register(&cli_show_channels);
- ast_cli_register(&cli_show_peers);
- ast_cli_register(&cli_show_registry);
- ast_cli_register(&cli_debug);
- ast_cli_register(&cli_no_debug);
- ast_cli_register(&cli_set_jitter);
- ast_cli_register(&cli_show_stats);
- ast_cli_register(&cli_show_cache);
- ast_manager_register( "IAX1peers", 0, manager_iax_show_peers, "List IAX Peers" );
- if (set_config(config,&sin) == -1) {
- config = IAX_OLD_CONF_FILE;
- set_config(config,&sin);
- }
- /* Make a UDP socket */
- netsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
-
- if (netsocket < 0) {
- ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno));
- return -1;
- }
- if (bind(netsocket,(struct sockaddr *)&sin, sizeof(sin))) {
- ast_log(LOG_ERROR, "Unable to bind to %s port %d: %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port), strerror(errno));
- close(netsocket);
- netsocket = -1;
- return -1;
- }
- if (option_verbose > 1)
- ast_verbose(VERBOSE_PREFIX_2 "Using TOS bits %d\n", tos);
- if (setsockopt(netsocket, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)))
- ast_log(LOG_WARNING, "Unable to set TOS to %d\n", tos);
-
- if (ast_channel_register(type, tdesc, iax_capability, iax_request)) {
- ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
- __unload_module();
- return -1;
- }
- if (ast_channel_register(ctype, tdesc, iax_capability, iax_request)) {
- ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
- __unload_module();
- return -1;
- }
- if (ast_register_switch(&iax_switch))
- ast_log(LOG_ERROR, "Unable to register IAX switch\n");
-
- if (!res) {
- res = start_network_thread();
- if (option_verbose > 1)
- ast_verbose(VERBOSE_PREFIX_2 "IAX Ready and Listening on %s port %d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port));
- } else {
- ast_log(LOG_ERROR, "Unable to start network thread\n");
- close(netsocket);
- }
- for (reg = registrations; reg; reg = reg->next)
- iax_do_register(reg);
- ast_mutex_lock(&peerl.lock);
- for (peer = peerl.peers; peer; peer = peer->next)
- iax_poke_peer(peer);
- ast_mutex_unlock(&peerl.lock);
- return res;
- }
- char *description()
- {
- return desc;
- }
- int usecount()
- {
- int res;
- ast_mutex_lock(&usecnt_lock);
- res = usecnt;
- ast_mutex_unlock(&usecnt_lock);
- return res;
- }
- char *key()
- {
- return ASTERISK_GPL_KEY;
- }
|