Let's talk about something unrelated to this Article. Today we finally use X-Lite for registration. It turns out that we need to set the proxy server that goes through the outbound call to "127.0.0.1: 5081". Of course, this is the local machine, for other computers, set the IP address to the server. 5081 is the port used by the P-CSCF in SDS, if only use IP address, it is not possible!
If it is a b2bua, you only need a global container hashmap <sipsession, sipsession> map to save all "surviving" sessions, but now I am a proxy Servlet and a b2bua servlet, in this way, the container in the Saved state must be shared by two Servlet classes. therefore, create the servletcontext object in the two servlets respectively, and initialize CTX = config In the init function respectively. getservletcontext (). as follows:
Public void Init (servletconfig config) throws servletexception {<br/> super. init (config); <br/> CTX = config. getservletcontext (); <br/>... <br/>}
Then in the first servlet -- proxyservlet
Public class proxyservlet extends sipservlet {<br/>... <br/> servletcontext CTX = NULL; <br/> hashmap <sipsession, sipsession> map = new hashmap <sipsession, sipsession>; <br/>... <br/> Public void Init (servletconfig config) throws servletexception {<br/> super. init (config); <br/> CTX = config. getservletcontext (); <br/> CTX. setattribute ("statemap", MAP); <br/>... <br/>}< br/>... <br/>}
In the second servlet -- b2buaservlet
Public class b2buaservlet extends sipservlet {<br/>... <br/> servletcontext CTX = NULL; <br/> hashmap <sipsession, sipsession> map = new hashmap <sipsession, sipsession>; <br/>... <br/> Public void Init (servletconfig config) throws servletexception {<br/> super. init (config); <br/> CTX = config. getservletcontext (); <br/> map = (hashmap <sipsession, sipsession>) CTX. getattribute ("statemap"); <br/>... <br/>}< br/>... <br/>}
This solves the problem of using the same map to save the session in two servlets. But is it appropriate to use the hashmap <sipsession, sipsession> data structure? For proxyservlet, he can only get one sipsession -- request. getsession (). It may be more suitable to use list...
Public class proxyservlet extends sipservlet {<br/>... <br/> servletcontext CTX = NULL; <br/> List <sipsession> SSL = new secure list <sipsession> (); <br/>... <br/> Public void Init (servletconfig config) throws servletexception {<br/> super. init (config); <br/> CTX = config. getservletcontext (); <br/> CTX. setattribute ("statelist", SSL); <br/>... <br/>}< br/>... <br/>}< br/> public class b2buaservlet extends sipservlet {<br/>... <br/> servletcontext CTX = NULL; <br/> List <sipsession> SSL = new secure list <sipsession> (); <br/>... <br/> Public void Init (servletconfig config) throws servletexception {<br/> super. init (config); <br/> CTX = config. getservletcontext (); <br/> SSL = (list <sipsession) CTX. getattribute ("statelist"); <br/>... <br/>}< br/>... <br/>}
However, there is another problem, that is, a large amount of code will appear during the search or deletion, which affects the readability of the Code. Therefore, the list <sipsession> operation is encapsulated in a statelist class.
Public class statelist {<br/> List <sipsession> SSL = new external list <sipsession> (); <br/> // integrates set and Add, no need to know the index value <br/> Public bool add (sipsession SS) {<br/> int Index = SSL. indexof (SS); <br/> If (index! =-1) <br/>{< br/> SSL. set (index, SS); <br/> return true; <br/>}< br/> else <br/>{< br/> SSL. add (SSL. size (), SS); <br/> return true; <br/>}</P> <p> // recursive call, no need to know the index value <br/> Public bool remove (sipsession SS) {<br/> int Index = SSL. indexof (SS); <br/> If (index! =-1) <br/>{< br/> SSL. remove (INDEX); <br/> This. remove (SS); <br/>}< br/> else <br/>{< br/> return true; <br/>}</P> <p> // traverse the list, returns the first sipsession with the specified STR attribute 1 <br/> Public sipsession get (string Str) {<br/> iterator <sipsession> it = SSL. iterator (); <br/> while (it. hasnext () <br/>{< br/> If (it. next (). getattribute (STR) = 1) <br/>{< br/> return it. next (); <br/>}< br/> return NULL; <br/>}< br/>}; </P> <p>
Think of a problem... If sipsession is used to save the state, do list or map really need it ?... It seems that no longer needed!
Sipsession lifecycle <br/> generally, the lifecycle of a sipsession can be controlled by the following method: <br/> 1. if the parent sipapplicationsession times out or explicitly expires, the sub-sessions of all Protocols will also become invalid. <br/> 2. the application uses the invalidate () API of the sipsession to invalidate the statement. <br/> 3. the application indicates that the sipsession is invalid and the container then invalidates the session when it enters the ready-to-invalidate state. <br/> any attempt to obtain or store data on an invalid sipsession will cause the container to throw an illegalstateexception. <br/> when a sipsession is terminated, whether the parent application session times out or the session is explicitly invalid, the window must clear all sessions in this state from the memory. in this case, if you receive a subsequent request or response from the local Session, the container will process the message as follows: <br/> 1. reject this request by sending a 481 Error Response <br/> 2. routing this request or response <br/> is likely to have different lifecycles for different application instances in the same application path. the container processes subsequent requests and responses for a conversation...
Haha !~ It's all nonsense! You only need to set the session attribute value (held) when you receive the 182 message as a tag. When you receive the ACK message, you can judge the Ack. getsession (). whether getattribut ("flag") equals held. if yes, proxy the ACK request and
Sipapplicationsession SAS = ack. getapplicationsession (true );
SAS. setattribute ("invite_send", "invite_send );
Sipservletrequest newreq = SF. createrequest (SAS, "invite", Ack. getto (), Ack. getfrom ());
Add a judgment when you receive the 200 OK message.
Resp. getmethod () = "invite" & resp. getrequest (). isinitial! = True
If "yes"
Copy the SDP information of this response
Resp. setcontenttype ("text/plain ");
String content = resp. getcontent ();
Then
Sipapplicationsession SAS = resp. getapplicationsession (true );
Judge SAS. getattribute ("invite_send") = "invite_send ";
If yes
Sipservletrequest newreq = SF. createrequest (SAS, "invite", resp. getfrom (), resp. getto ());
Newreq. setcontenttype ("text/plain ");
Newreq. setcontent (content, "text/plain ");
Newreq. setcontenttype ("SDP/application ");
Newreq. setcontentlength (content. Length ());
Newreq. Send ();
SAS. removeattribute ("invite_send ");
Resp. createack (). Send ();
Of course, these are all functions completed in proxyservlet. Tomorrow, we will write the functions to be completed by the methods in b2buaservlet.