ϪfH dZddlZddlZddlZddlmZddlmZmZddl m Z m Z ddl m Z ddlmZmZmZddlmZdd lmZd Zd d d ddddddd ZiZej3D] \ZZeee< [[idddddddddddd d!d"d#d$d%d&d'd(d)d*d+d,d-d.d/d0d1d2d3d4d5d6id7d8d9d:d;d<d=d>d?d@dAdBdCdDdEdFdGdHdIdJdKdLdMdNdOdPdQdRdSdTdUdVdWdXidYdZd[d\d]d^d_d`dadbdcdddedfdgdhdidjdkdldmdndodpdqdrdsdtdudvdwdxdydzd{d:d|Zd}d~ddZdZdZe Z!GddZ"dZ#GddZ$ddZ%dZ&ddZ'Gdde(Z)Gdde)Z*GddZ+Gdde+Z,Gdde+Z-Gddej\Z/Gddej`Z1Gdde Z2GddZ3Gdde Z4Gdde Z5Gdde1Z6Gdde Z7Gdde6Z8e e4e5GddZ9y)zP Session Initialization Protocol. Documented in RFC 2543. [Superseded by 3261] N) OrderedDict)DictList) Interface implementer)cred)deferprotocolreactor)basic)logiimelcfstv) call-idcontactzcontent-encodingcontent-lengthz content-typefromsubjecttoviadTryingRingingzCall Is Being ForwardedQueuedzSession ProgressOKi,zMultiple Choicesi-zMoved Permanentlyi.zMoved Temporarilyi/z See Otheri1z Use Proxyi|zAlternative Servicez Bad Request UnauthorizedizPayment Requiredi Forbiddenz Not FoundizMethod Not AllowedizNot AcceptableizProxy Authentication RequiredizRequest TimeoutiConflictiGoneizLength RequiredizRequest Entity Too LargeizRequest-URI Too LargeizUnsupported Media TypeizUnsupported URI Schemeiz Bad ExtensionizExtension RequiredizInterval Too BriefizTemporarily UnavailableizCall/Transaction Does Not Existiz Loop Detectediz Too Many HopsizAddress Incompletei Ambiguousiz Busy HereizRequest TerminatedizNot Acceptable HereizRequest PendingiUndecipherablezInternal Server ErrorzNot Implementediz Bad GatewayizService UnavailableizServer Time-outizSIP Version not supportedizMessage Too LargeiXzBusy Everywherei[DeclinezDoes not exist anywhere)i\i^CSeqzCall-IDzWWW-Authenticate)cseqrwww-authenticatecdj|jdDcgc]}|jc}Scc}w)zK Capitalize a string, making sure to treat '-' as a word separator -)joinsplit capitalize)rxs 7/usr/lib/python3/dist-packages/twisted/protocols/sip.pydashCapitalizer>ls/ 88QWWS\:Q\\^: ;;:s=c:|d|dcxk(rdk(r n|S|ddS|S)Nr")rs r=unqrDss.tqu H2w HcbeZdZdZeddddeddfdZedZejdZdZ y) Viaa A L{Via} is a SIP Via header, representing a segment of the path taken by the request. See RFC 3261, sections 8.1.1.7, 18.2.2, and 20.42. @ivar transport: Network protocol used for this leg. (Probably either "TCP" or "UDP".) @type transport: C{str} @ivar branch: Unique identifier for this request. @type branch: C{str} @ivar host: Hostname or IP for this leg. @type host: C{str} @ivar port: Port used for this leg. @type port C{int}, or None. @ivar rportRequested: Whether to request RFC 3581 client processing or not. @type rportRequested: C{bool} @ivar rportValue: Servers wishing to honor requests for RFC 3581 processing should set this parameter to the source port the request was received from. @type rportValue: C{int}, or None. @ivar ttl: Time-to-live for requests on multicast paths. @type ttl: C{int}, or None. @ivar maddr: The destination multicast address, if any. @type maddr: C{str}, or None. @ivar hidden: Obsolete in SIP 2.0. @type hidden: C{bool} @ivar otherParams: Any other parameters in the header. @type otherParams: C{dict} UDPNFc  L||_||_||_||_||_||_|dur+t jdtdd|_ d|_ n6|d|_ d|_ n%|turd|_ d|_ n||_ d|_ ||_ | |_ | |_y)a( Set parameters of this Via header. All arguments correspond to attributes of the same name. To maintain compatibility with old SIP code, the 'rport' argument is used to determine the values of C{rportRequested} and C{rportValue}. If None, C{rportRequested} is set to True. (The deprecated method for doing this is to pass True.) If an integer, C{rportValue} is set to the given value. Any arguments not explicitly named here are collected into the C{otherParams} dict. Tz+rport=True is deprecated since Twisted 9.0.) stacklevelNF) transporthostportttlhiddenreceivedwarningswarnDeprecationWarning rportValuerportRequested_absentbranchmaddr otherParams) selfrMrNrLrOrPrQrportrXrYkws r=__init__z Via.__init__s4#     D= MM="  #DO"&D  ]"DO"&D  g "DO"'D #DO"'D   rEcT|jdk(ry|j |jSy)zG Returns the rport value expected by the old SIP code. TN)rVrUr[s r=r\z Via.rports,   $ & __ (?? "rEc ||_d|_y)z L{Base._fixupNAT} sets C{rport} directly, so this method sets C{rportValue} based on that. @param newRPort: The new rport value. @type newRPort: C{int} FN)rUrV)r[newRPorts r=r\z Via.rports##rEcd|jd|jd|j}|jr|dz }dD]}t ||}||d|d|z }|j r|dz }n|j |d |jz }t|jj}|D]\}}| |d|zz }|d|d|z }|S) zI Serialize this header for use in a request or response. zSIP/2.0/ :z;hidden)rOrXrYrQ;=z;rportz;rport=) rLrMrNrPgetattrrVrUr\sortedrZitems)r[rnvalueetckrs r=toStringz Via.toStringst~~&a {!DII; ? ;; NA5 %AD!$E q1UG_$ %    MA __ ( 74::,' 'AT%%++-. !DAqyS1W q1QC[   ! rE) __name__ __module__ __qualname____doc__PORTrWr^propertyr\setterrorCrEr=rGrG|sYF 4l   \\ $ $rErGc~|jd}|d|dd}}|jdd\}}|j}i}|jd\}}} |dk7s|dk7rtd || |d <d |vr(|jd \} } t| |d <| |d <n||d <|D]} | jjdd} t | dk(r| dd} } n| \} } | dk(rd|d<I| jdd}t |dk(r|dd}}n|\}}|dvr t|}|||<t di|S)za Parse a Via header. @return: The parsed version of this header. @rtype: L{Via} rfrrBNrd/SIPz2.0zwrong protocol or version: rLrerNrMrPTrg)r\rOrC)r:strip ValueErrorintlenrG)rlpartssentparams protocolinfobyresultpnamepversionrLrMrNpcommentnames r=parseViaHeaderrsv KK E8U12Y&Dzz#q)L" B F!-!3!3C!8E8Y ~U*6ui@AA#F; byXXc] dTvvv  GGIOOC # q6Q;1rwAJAw =#F8  Q u:?(D%DKD%''E t #$ ==rEcReZdZdZ ddZdefdZdefdZdefdZy) URLz A SIP URL. Nc ||_||_||_||_||_||_||_| |_||_| |_ | dk(rg|_ n| |_ | dk(ri|_ y| |_ yN) usernamerMpasswordrNrLusertypemethodtagrOrYotherheaders) r[rMrrrNrLrrrOrYrrrs r=r^z URL.__init__4st!     "    D=DJDJ d?DL"DLrEreturnc &g}|j}|d|jdk7r>||j|jdk7r|d|jz|d||j|jdk7r|d|jz|j dk7r|d|j zdD]"}t ||}|dk7s|d|d|$|jD] }|d |z|jro|d |d j|jjDcgc],\}}tj|xs t|d|.c}}d j|Scc}}w) Nsip:z:%s@z:%dz;user=%srLrOrYrrrfrgz;%s?&rz)appendrrrMrNrrhrrr9rj specialCasesgetr>)r[rwrkrhs r=roz URL.toStringVsn HH & ==D dmm }}$%$--'( cF $)) 99  edii ==D j4==( )? Aa ADyAaS!+  A eaiL  << cF '+ll&8&8&:"Q),,Q/D>!3DEQqcJ wwqz s?1F c"|jSr)ror`s r=__str__z URL.__str__vs}}rEcdj|j|j|j|j|j S)Nz)formatrrrMrNrLr`s r=__repr__z URL.__repr__ys8'.. MM MM II II NN   rE) NNNNNNNNNNN) rprqrrrsr^strrorrrCrEr=rr/sU    #D#@ # rErci}|jdstd|ddz|ddjd}|d|dd}}|jdd}t|d k(r?|\}} |jd d} t| dk(r | d|d <n| d|d <| d|d <n|d} | jd d} t| dk(r | d|d <n| d|d <t | d|d<|dk7r||d <|dk7r||d<|D]} | |dk(rOd| vrKix|d<} | jdd\} }|jdD]}|jd\}}|| |<| jdd}t|dk(r"|j dgj | |\}}|dk(r||d<|dvr|dk(r t |}|||<|j dgj | tdi|S)zV Return string into URL object. URIs are of form 'sip:user@example.com'. rzunsupported scheme: NrfrrBrrJrerrrMrNr@rrrrgruserrrrOrC) startswithr|r:r~r} setdefaultrr)urlrMrNdr userdomainrudpartsuserpasshostportuppartshppartsrrrheaderrnrnvrrls r=parseURLrs; A >>& !/#bq'9:: GMM# Eq59JsA&G 7|q$(..a( w<1 #AJAjM#AJAjM#AJAjM1:nnS!$G 7|qAJ& AJ&  O&  t|&  t|& 0 r ?sax! !AiL1aJAw!--, ||C(1! WWS!_ r7a< LL" % , ,Q /  e 6>!AjM C Cu}E AdG LL" % , ,Q /'0( 88OrEc<d|_d|_d|_i|_y)z* Clean a URL from a Request line. N)rLrYrOr)rs r=cleanRequestURLrs CMCICGCKrEc |j}|jdrdt|||ifSi}|jdd\}}|j}|jdr|dd}|j dr|dd}|jd d\}}t|||}|j}|r2|jd D]}|s|jd \} } | || < |rd|_i|_d|_d|_|||fS) z Return (name, uri, params) for From/To/Contact header. @param clean: remove unnecessary info, usually for From and To headers. rrzrMrNrfrg) r{rrr:endswithrOrrLrY) addressrMrNcleanrrr paramstringrrnrs r= parseAddressrs! mmoG&!8G$T:B>> F c1%ID# :: &F4!5v!FG  rErrprqrrr^rCrEr=rrsrErceZdZdZy)RegistrationErrorz( Registration was not possible. NrprqrrrsrCrEr=rrrErc8eZdZdZdZdZdZdZdZdZ dZ y) Messagez A SIP message. Nc>t|_d|_d|_y)Nrzr)rrbodyfinishedr`s r=r^zMessage.__init__s"}   rEc|j}tj||}|dk(rt||_|j j |gj|y)Nr)lower longHeadersrr}lengthrrr)r[rrls r= addHeaderzMessage.addHeadersPzz|tT* # #e*DK b)007rEc.|xj|z c_yr)rr[datas r=bodyDataReceivedzMessage.bodyDataReceived s T rEc|jdk7r-|jt|jk7r tdd|_y)Nzwrong body lengthrB)rr~rr|rr`s r=creationFinishedzMessage.creationFinished s4 KK4 dkkS^&C01 1 rEcd|jz}|jjD]7\}}|D]-}|tj |xs t |d|dz }/9|dz }||j z }|S)Nz%s z: z )_getHeaderLinerrjrrr>r)r[rrkvsrs r=rozMessage.toStrings t**, ,\\'') LEAr L ((+@~a/@AA3dKK L L V  TYYrEctrNotImplementedErrorr`s r=rzMessage._getHeaderLines!!rE) rprqrrrsrr^rrrrorrCrEr=rrs,F 8 "rErc*eZdZdZddZdefdZdZy)Requestz A Request for a URI ctj|||_t|tr||_yt ||_t|j yr)rr^r isinstancerurirr)r[rrversions r=r^zRequest.__init__#s? c3 DH}DH DHH %rErchdt||j|jjfzS)Nz)idrrror`s r=rzRequest.__repr__,s)'2d8T[[$((BSBSBU*VVVrEcV|jd|jjdS)Nrdz SIP/2.0)rrror`s r=rzRequest._getHeaderLine/s'++a 1 1 34H==rEN)SIP/2.0rprqrrrsr^rrrrCrEr=rrs&W#W>rErc*eZdZdZddZdefdZdZy)Responsez% A Response to a URI Request Ncftj|||_|dk(r t|}||_yr)rr^rrr)r[rrrs r=r^zResponse.__init__8s/ T> &F rErc6dt||jfzS)Nz)rrr`s r=rzResponse.__repr__?s%D499(===rEc:d|jd|jS)NzSIP/2.0 rd)rrr`s r=rzResponse._getHeaderLineBs$))Adkk]33rE)NrrrCrEr=rr3s>#>4rErcdeZdZdZdZdZdZdZdZdZ ddZ dZ d Z d Z d Zd Zd ZddZdZy)MessagesParserz A SIP messages parser. Expects dataReceived, dataDone repeatedly, in that order. Shouldn't be connected to actual transport. rrB firstlinerc2||_|jyr)messageReceivedreset)r[messageReceivedCallbacks r=r^zMessagesParser.__init__Us6 rEcld|_d|_d|_d|_d|_|j |y)Nrr)stater bodyReceivedmessager setLineModer[ remainingDatas r=rzMessagesParser.resetYs4      'rEc2d|_|jy)Ninvalid)r setRawModer`s r=invalidMessagezMessagesParser.invalidMessageas  rEc,|j|jdk(ry|jdk7r|jy|jdk(r|j y|j|j kr|jyt d)zI Clear out any buffered data that may be hanging around. rNrzthis should never happen)clearLineBufferrrr messageDoner RuntimeErrorr`s r=dataDonezMessagesParser.dataDoneesx  :: $  ::  JJL  ;;$      [[4,, , JJL9: :rEc t|tr|jd}tjj ||y#t $r'tj|jYywxYw)Nutf-8) rrencoder LineReceiver dataReceivedrr errrrs r=rzMessagesParser.dataReceivedysY "$${{7+    + +D$ 7 " GGI    ! "sAA-A43A4ct)z2 Expected to create self.message. rr[lines r=handleFirstLinezMessagesParser.handleFirstLines "!rEc$|jyr)rrs r=lineLengthExceededz!MessagesParser.lineLengthExceededs rEct|tr|jd}|jdk(r|j ds|j dr)|dd}|j dr|j dr)|sy |j dd\}}}|dk(r1|jr% t|}t|||_ d |_y|dk(r%|jrt|||_ d |_y|jy|jd k(sJ|r|j ds|j d r*|j\}}|||jzf|_y|jr*|jj |jd|_ |j d d\}}||jf|_|j#d k(r t|j|_yyd |_|jr*|jj |jd|_|j$dk(r|j'y|j)y#t $r|jYywxYw#t $r|jYywxYw#t $r|jYywxYw#t $r|jYywxYw)Nr r  rBrdrJrr rerrr)rbytesdecoderrr:r|racceptResponsesr}rracceptRequestsrrlstriprrrr r)r[rabrrrrls r= lineReceivedzMessagesParser.lineReceiveds dE ";;w'D :: $//$'4??4+@ABx//$'4??4+@ **S!,1aI~$"6"6q6D (a0 #DJ  iD$7$7&q!} #DJ ##%::* ** s#tt'<"kk e"UT[[]%:; ;;*DLL**DKK8"&DK"&**S!"4KD%#ELLN2 ::<#33&)%,,.&9 4 DJ{{& && 4" {{a  " OO m ##% "'')2"'')&++-sHI+( J J)K+JJ J&%J&)KKK$#K$c|jdk(sJ|jj|j|j|j |y)Nr)rrrrrrs r=r zMessagesParser.messageDonesBzzV### %%' T\\* =!rEcH|jdvsJt|tr|jd}|jdk(ry|jdk(r|j j |yt|}|j|jz }||kDr3|j j |d||j||dy|xj|z c_|j j ||j|jk(r|jyy)N)rrr r) rrrrrrrr~rr )r[rdataLen expectedLens r=rawDataReceivedzMessagesParser.rawDataReceivedszz0000 dE ";;w'D :: "  ;;$  LL ) )$ /$iG++(9(99K$ --d||_|j|k7r||_|j |jdd<y|j dk(r/||_||_|j |jdd<yy)NrrT)rrrMrQrNr\ro)r[r sourcePeersrcHostsrcPort senderVias r=r3zBase._fixupNATs''"7??5#9!#<= >>W $!(I ~~(") (1(:(:(< FD%,__%8%8r%B1%EH  T " FrEc|jdvr td|jr)tjd|j d||j }t |tr|jd}|jj||j|jxs |jfy)z Send a message. @param destURL: C{URL}. This should be a *physical* URL, not a logical one. @param message: The message to send. )udpNzonly UDP currently supportedzSending z to r N) rLr r)r r1rorrrwriterMrNrt)r[destURLrrs r=r@zBase.sendMessage+s   M 1=> > :: GGhw//14D D E! dC ;;w'D TGLL',,2K$))#LMrEct)z Override to define behavior for requests received @type message: C{Message} @type addr: C{tuple} rr[rr6s r=r4zBase.handle_request; "!rEct)z Override to define behavior for responses received. @type message: C{Message} @type addr: C{tuple} rrRs r=r5zBase.handle_responseDrSrEN)rprqrrrsrtr)r^r.r7r3rErLr@r4r5rCrEr=r+r+sA D E6"  = 4N ""rEr+ceZdZdZy)IContactz( A user of a registrar or proxy NrrCrEr=rVrVNrrErVceZdZdZy) Registrationc ||_||_yr)secondsToExpiry contactURL)r[rZr[s r=r^zRegistration.__init__Us.$rENrrCrEr=rXrXTs%rErXc"eZdZdZdZdZdZy) IRegistryz? Allows registration of logical->physical URL mapping. cy)z Register the physical address of a logical URL. @return: Deferred of C{Registration} or failure with RegistrationError. NrC domainURL logicalURL physicalURLs r=registerAddresszIRegistry.registerAddress_rEcy)z Unregister the physical address of a logical URL. @return: Deferred of C{Registration} or failure with RegistrationError. NrCr_s r=unregisterAddresszIRegistry.unregisterAddressfrdrEcy)z Get registration info for logical URL. @return: Deferred of C{Registration} object or failure of LookupError. NrCras r=getRegistrationInfozIRegistry.getRegistrationInfomrdrEN)rprqrrrsrcrfrirCrEr=r]r]Zs   rEr]ceZdZdZdZy)ILocatorz< Allow looking up physical address for logical URL. cy)z Return physical URL of server for logical URL of user. @param logicalURL: a logical C{URL}. @return: Deferred which becomes URL or fails with LookupError. NrCrhs r= getAddresszILocator.getAddresszrdrEN)rprqrrrsrmrCrEr=rkrkus  rErkcTeZdZdZeZdZdefdZdZdZdZ dZ dZ d Z d Z d Zy) Proxyz SIP proxy. Ncv|xstj|_||_tj |y)z Create new instance. @param host: our hostname/IP as set in Via headers. @param port: our port as set in Via headers. N)socketgetfqdnrMrNr+r^)r[rMrNs r=r^zProxy.__init__s*,FNN,   drEcDt|j|jS)z< Return value of Via header for this proxy. r)rGrMrNr`s r=getViaz Proxy.getVias  22rEctdjzd}| j} ||}||jfdyy#t$r5}j j |jYd}~yd}~wt$r8tjj j dYywxYw)Nzhandle_%s_requestcZjj|jSr)rErLr)rrr[s r=z&Proxy.handle_request..s&d2200ArEr1) rhrhandle_request_default addErrbackrrErLr BaseExceptionr r)r[rr6rrrs`` r=r4zProxy.handle_requests D-> E 9++A '4 A}   L  !9!9!&&'!J K K I GGI  !9!9#w!G H Is A C +BAC  C c|\}}fd}j}|j|jdvrtjdy|jdj d|jt |jddd\}}} jj|} | jj|| jj|y) z Default request handler. Default behaviour for OPTIONS and unknown methods for proxies is to forward message on to the client. Since at the moment we are stateless proxy, that's basically everything. ch|j|jdd<j||S)Nrr)rorr@)rrr[s r=_mungContactHeaderz8Proxy.handle_request_default.._mungContactHeaders/,/LLNGOOI &q )##C1 1rErzDropping looped message.NrrrBr) rtrorr r1insertrlocatorrm addCallbackr@ry_cantForwardRequest) r[rr9r:r;r} viaHeaderrrtagsrs ` r=rxzProxy.handle_request_defaults(' 2KKM    7??5#9 9 GG. / %%a););)=>&wt'r?rAs r=rEzProxy.deliverResponsesi !!8!8!?!BC/7<<}}9 9 Dt, ?3rEct|}dD].}|jj|gdd|j|<0|SrGrHrIs r=rLzProxy.responseFromRequestsID>< FD%,__%8%8r%B1%EH  T " FrEcNt|jdd}|j|jf|j|jfk7rt j dy|jdd=|jds|j ||y|j|y)z+ Default response handler. rrz&Dropping incorrectly addressed messageN)rrrMrNr r1 gotResponserE)r[rr6rs r=r5zProxy.handle_responses 7??51!4 5 FFAFF  4995 5 GG< =  OOE "1 %u%   Wd +  W%rEcy)zJ Called with responses that are addressed at this server. NrCrRs r=rzProxy.gotResponses rE)rprqrrrsrtrr^rtr4rxrrErLr5rrCrEr=rorosF DG t 3 *8<E 4&$ rEroceZdZdZdZy) IAuthorizercy)z Generate a challenge the client may respond to. @type peer: C{tuple} @param peer: The client's address @rtype: C{str} @return: The challenge string NrC)peers r= getChallengezIAuthorizer.getChallengerdrEcy)zf Create a credentials object from the given response. @type response: C{str} NrC)rKs r=rzIAuthorizer.decoderdrEN)rprqrrrrrCrEr=rrs    rErceZdZUdZdZdZiZeee fe d<dZ dZ dZ dZdZd Zd Zd Zd Zd ZdZdZdZy) RegisterProxyzk A proxy that allows registration for a specific domain. Unregistered users won't be handled. N authorizerscDtj|g|i|i|_yr)ror^liveChallenges)r[argsr]s r=r^zRegisterProxy.__init__&s  t)d)b) rEc|\}}yrrCr[r host_portrMrNs r=handle_ACK_requestz RegisterProxy.handle_ACK_request*s ! t rEc|\}}|j|j|||yd|jvr|j|||S|j |||S)z` Handle a registration request. Currently registration is not proxied. N authorization)portalregisterr unauthorizedloginrs r=handle_REGISTER_requestz%RegisterProxy.handle_REGISTER_request3s] ! t ;;  MM'4 .goo5(($==zz'466rEc|jd|}|jjD]\}}|j||f}|!|j d|j d}n#|j d|d|j d}|j jdgj||j|y)Nr)z realm="rArdz,realm="r6) rLrrjrtitlerMrrrrE) r[rrMrNrschemeauthchalrls r=rzRegisterProxy.unauthorizedDs  $ $S' 2 ,,224 GLFD$$dD\2D|!<<>*(499+Q?!<<>*!D6$))AF II !3R 8 ? ? F  G QrEc|jddjdd}|jj|dj }|r |j |d}|xj d|jzz c_|jj|dtj|j|||j|j|||jtj y|j'|j)d|y#t"$rt$$r8tj |j'|j)d|YywxYw)NrrrBrr1r2)rr:rrrrrrMrrrVr_cbLoginry_ebLoginr rrrzrErL)r[rrMrNrr!rs r=rzRegisterProxy.loginOs"0399$B    q!1 2  UHHU1X& cDIIo-  !!!T84@@MM7D$*T]]GT4@CGGAT  !9!9#w!G H   M $$T%=%=c7%KL MsD!!AE+*E+c6|\}}}|j|||yr)r)r[i_a_lrrMrNrr!rs r=rzRegisterProxy._cbLoginbs Aq gtT*rEc||jtjj|j |||yr)rrrUnauthorizedLoginr)r[failurerrMrNs r=rzRegisterProxy._ebLogings* TZZ112 '4.rEct|jddd\}}}d}d|jvr|jdd}|jjddgddk(r|j|||y|:t||| \}}}|jj |j ||} n|jj|} | j|j|j|f|f y) z- Allow all users to register rrrBr~Nrexpires0r) callbackArgs errbackArgs) rrr unregisterregistryrcrri addCallbacks _cbRegister _ebRegister) r[rrMrNrtoURLrrr[rs r=rzRegisterProxy.registerks+7??4+@+C1MeV  'ooi03G ??  y4& 1! 4 ; OOGUG 4"+7dQU+V(j&MM11'++ujQMM55e< NN    %Z$J  rEc|jd|}|jdk7rI|jd|jj|jdd|jz|jdd|j |y)Nr&rrz%drr)rLr[rrorZrE)r[ registrationrrKs r=rzRegisterProxy._cbRegisters{++C9  " "d *   y,*A*A*J*J*L M   y$1M1M*M N+S1 X&rEc8|jttyr)rrrrs r=rzRegisterProxy._ebRegisters $k2rEc t|jdd}|dk(ru|dk(rd}nt|\}}}|jj |j ||}|j |j|j|j|yy#t$r$|j|jd|YywxYw)Nrr*r() r}rrrrfrr _cbUnregisterry _ebUnregisterr|rErL) r[rrrrr[rrrs r=rzRegisterProxy.unregisters '//)4Q78G!|c>!$J/;G/D,D*fMM33GKK S d00':EE&&  I  !9!9#w!G H IsB*CCc|jd|}|jjdgj|jj |j dd|j|y)Nr&rrr)rLrrrr[rorrE)r[rrr1s r=rzRegisterProxy._cbUnregisters^&&sG4 y"-44\5L5L5U5U5WX i% S!rEcyrrC)r[rrs r=rzRegisterProxy._ebUnregisters rE)rprqrrrsrrrrrr__annotations__r^rrrrrrrrrrrrrCrEr=rrsi FH*,Kc;&',! 7"  I&+ /4'3  "  rErc4eZdZdZdZdZdZdZdZdZ y) InMemoryRegistryz6 A simplistic registry for a specific domain. c ||_i|_yr)domainusers)r[rs r=r^zInMemoryRegistry.__init__s  rEc>|j|jk7rtjt dS|j |j vr1|j |j \}}tj|Stjt dSNzunknown domain no such user)rMrr failrrrsucceedr[userURIdcrs r=rmzInMemoryRegistry.getAddressst <<4;; &::k*:;< <   tzz )jj!1!12GB==% %::k.9: :rEc |j|jk7rtjt dS|j |j vrg|j |j \}}tjtt|jtjz |Stjt dSr) rMrr rrrrrrXr}getTimetimers r=riz$InMemoryRegistry.getRegistrationInfos <<4;; &::k*:;< <   tzz )jj!1!12GB==c"**,2L.Ms!ST T::k.9: :rEc |j|\}}|j|j|=tj td|S#t$r!tjt dcYSwxYw)Nrr)rcancelKeyErrorr rrrrX)r[rrrs r=_expireRegistrationz$InMemoryRegistry._expireRegistrationsk %jj*GB IIK 8$}}\!S122  ;::k.9: : ;sA'A:9A:c N|j|jk7r3tjdt j t dS|j|jk7r3tjdt j t dS|j|jvr.|j|j\}}|jdn+tjd|j|j}tjd|jd|j||f|j|j<t jtt!|j#t%j$z |S)Nz(Registration for domain we don't handle.r,iz Registered z at )rMrr r1r rrrrrr callLaterrrorrXr}rr)r[r`rarbrolds r=rcz InMemoryRegistry.registerAddresss- >>T[[ ( GG> ?::/45 5 ??dkk ) GG> ?::/45 5   $** ,jj!4!45GB HHTN""4)A)A:CVCVWB +j1134D9M9M9O8PQR+-{*; :&&'}}\#bjjlTYY[.H*I;WXXrEc8|j|jSr)rr)r[r`rarbs r=rfz"InMemoryRegistry.unregisterAddresss'' (;(;<rDobjectrWrGrrrrrrrrrrrrrDatagramProtocolr+rVrXr]rkrorrrrCrEr=rsy  #155#         DAqKNq666 "6 6   6  6 6 6 666 666 6 !6"#6$ %6& '6( ()6* +6,-6./60 162 #364 566 !768 !96:;6< =6> ?6@ "A6B *C6DE6FG6H I6JK6LM6N O6P Q6R S6T U6V W6X Y6Z[6\ ]6^ _6` $a6b c6d e6fg6h # k6 r * < (EEP(VQ Q h4n Fy %"%"P>g>*4w4&a'U''a'Ha"8 $ $a"Hy %%   6  y   D D ) (P EP f Y!6=6="6=rE