Source code: com/opencloud/slee/services/sip/proxy/BaseProxySbb.java
1 package com.opencloud.slee.services.sip.proxy;
2
3
4
5 import javax.naming.InitialContext;
6 import javax.naming.NamingException;
7
8 import javax.sip.*;
9 import javax.sip.TimeoutEvent;
10 import javax.sip.message.Request;
11 import javax.sip.message.Response;
12
13 import javax.slee.ActivityContextInterface;
14 import javax.slee.ChildRelation;
15 import javax.slee.SbbContext;
16 import javax.slee.SbbLocalObject;
17 import javax.slee.facilities.Level;
18
19 import com.opencloud.slee.services.sip.common.AbstractSipProxy;
20 import com.opencloud.slee.services.sip.common.SipBaseSbb;
21
22 public abstract class BaseProxySbb extends SipBaseSbb {
23
24 protected String getTraceMessageType() { return "SipProxySbb"; }
25
26 // child relation
27 public abstract ChildRelation getRegistrarSbbChild();
28
29 // Activity Context Interface narrow method
30 public abstract SipProxySbbActivityContextInterface asSbbActivityContextInterface(ActivityContextInterface ac);
31
32 private void processRequest(ServerTransaction serverTransaction, Request request, ActivityContextInterface ac) {
33 trace(Level.FINEST, "processRequest: request = \n" + request.toString());
34 try {
35
36 SipProxySbbActivityContextInterface sipaci = asSbbActivityContextInterface(ac);
37
38 if (sipaci.getTransactionTerminated()) {
39 return; // nothing to do
40 }
41
42 // Create a worker to process this event
43 MySipProxy proxy = new MySipProxy(this, sipaci);
44 // Go
45 proxy.processRequest(serverTransaction, request);
46
47 } catch (Exception e) {
48 // Send error response so client can deal with it
49 trace(Level.WARNING, "Exception during processRequest", e);
50 try {
51 serverTransaction.sendResponse(getMessageFactory().createResponse(Response.SERVER_INTERNAL_ERROR, request));
52 } catch (Exception ex) {
53 ex.printStackTrace();
54 }
55 }
56
57 }
58
59 private void processResponse(ClientTransaction clientTransaction, Response response, ActivityContextInterface ac) {
60 trace(Level.FINEST, "processResponse: response = \n" + response.toString());
61 try {
62
63 SipProxySbbActivityContextInterface sipaci = asSbbActivityContextInterface(ac);
64
65 // Create a worker to process this event
66 MySipProxy proxy = new MySipProxy(this, sipaci);
67 // Go
68 proxy.processResponse(getServerTransaction(clientTransaction), response);
69
70 } catch (Exception e) {
71 // Send error response so client can deal with it
72 trace(Level.WARNING, "Exception during processResponse", e);
73 }
74
75 }
76
77 public void onRegisterEvent(RequestEvent event, ActivityContextInterface ac) {
78 getDefaultSbbUsageParameterSet().incrementNumberOfRegister(1);
79 trace(Level.INFO, "Received REGISTER request, class="+event.getClass());
80 try {
81
82 // is local domain?
83
84 // create registrar child SBB
85 ChildRelation relation = getRegistrarSbbChild();
86 SbbLocalObject child = relation.create();
87
88 // attach child to this activity
89 ac.attach(child);
90
91 // detach myself
92 ac.detach(getSbbLocalObject());
93
94 // Event router will pass this event to child SBB
95
96 } catch (Exception e) {
97 trace(Level.WARNING, "Exception during onRegisterEvent", e);
98 }
99 }
100
101 public void onInviteEvent(RequestEvent event, ActivityContextInterface ac) {
102 getDefaultSbbUsageParameterSet().incrementNumberOfInvite(1);
103 trace(Level.INFO, "Received INVITE request");
104 try {
105 Request request = event.getRequest();
106 ServerTransaction serverTransaction = event.getServerTransaction();
107 processRequest(serverTransaction, request, ac);
108 } catch (Exception e) {
109 trace(Level.WARNING, "Exception during onInviteEvent", e);
110 }
111 }
112
113 public void onByeEvent(RequestEvent event, ActivityContextInterface ac) {
114 getDefaultSbbUsageParameterSet().incrementNumberOfBye(1);
115 trace(Level.INFO, "Received BYE request");
116 try {
117
118 Request request = event.getRequest();
119 ServerTransaction serverTransaction = event.getServerTransaction();
120 processRequest(serverTransaction, request, ac);
121
122 } catch (Exception e) {
123 trace(Level.WARNING, "Exception during onByeEvent", e);
124 }
125 }
126
127 public void onCancelEvent(RequestEvent event, ActivityContextInterface ac) {
128 trace(Level.INFO, "Received CANCEL request");
129 try {
130
131 Request request = event.getRequest();
132 ServerTransaction serverTransaction = event.getServerTransaction();
133
134 // CANCELs are hop-by-hop, so here we respond immediately on the server txn.
135 serverTransaction.sendResponse(getMessageFactory().createResponse(Response.OK, request));
136
137 // This will generate a new CANCEL request that originates from the proxy
138 processRequest(serverTransaction, request, ac);
139
140 } catch (Exception e) {
141 trace(Level.WARNING, "Exception during onCancelEvent", e);
142 }
143 }
144
145 public void onAckEvent(RequestEvent event, ActivityContextInterface ac) {
146 getDefaultSbbUsageParameterSet().incrementNumberOfAck(1);
147 trace(Level.INFO, "Received ACK request");
148 try {
149
150 Request request = event.getRequest();
151 ServerTransaction serverTransaction = event.getServerTransaction();
152 processRequest(serverTransaction, request, ac);
153
154 } catch (Exception e) {
155 trace(Level.WARNING, "Exception during onAckEvent", e);
156 }
157 }
158
159 public void onOptionsEvent(RequestEvent event, ActivityContextInterface ac) {
160 trace(Level.INFO, "Received OPTIONS request");
161 try {
162
163 Request request = event.getRequest();
164 ServerTransaction serverTransaction = event.getServerTransaction();
165 processRequest(serverTransaction, request, ac);
166
167 } catch (Exception e) {
168 trace(Level.WARNING, "Exception during onOptionsEvent", e);
169 }
170 }
171
172 public void onInfoRespEvent(ResponseEvent event, ActivityContextInterface ac) {
173 trace(Level.INFO, "Received 1xx (INFO) response");
174 try {
175
176 Response response = event.getResponse();
177 ClientTransaction clientTransaction = event.getClientTransaction();
178 processResponse(clientTransaction, response, ac);
179
180 } catch (Exception e) {
181 trace(Level.WARNING, "Exception during onInfoRespEvent", e);
182 }
183 }
184
185 public void onSuccessRespEvent(ResponseEvent event, ActivityContextInterface ac) {
186 trace(Level.INFO, "Received 2xx (SUCCESS) response");
187 try {
188
189 Response response = event.getResponse();
190 ClientTransaction clientTransaction = event.getClientTransaction();
191 processResponse(clientTransaction, response, ac);
192
193 } catch (Exception e) {
194 trace(Level.WARNING, "Exception during onSuccessRespEvent", e);
195 }
196 }
197
198 public void onRedirRespEvent(ResponseEvent event, ActivityContextInterface ac) {
199 trace(Level.INFO, "Received 3xx (REDIRECT) response");
200 try {
201
202 Response response = event.getResponse();
203 ClientTransaction clientTransaction = event.getClientTransaction();
204 processResponse(clientTransaction, response, ac);
205
206 } catch (Exception e) {
207 trace(Level.WARNING, "Exception during onRedirRespEvent", e);
208 }
209 }
210
211 public void onClientErrorRespEvent(ResponseEvent event, ActivityContextInterface ac) {
212 trace(Level.INFO, "Received 4xx (CLIENT ERROR) response");
213 try {
214
215 Response response = event.getResponse();
216 ClientTransaction clientTransaction = event.getClientTransaction();
217 processResponse(clientTransaction, response, ac);
218
219 } catch (Exception e) {
220 trace(Level.WARNING, "Exception during onClientErrorRespEvent", e);
221 }
222 }
223
224 public void onServerErrorRespEvent(ResponseEvent event, ActivityContextInterface ac) {
225 trace(Level.INFO, "Received 5xx (SERVER ERROR) response");
226 try {
227
228 Response response = event.getResponse();
229 ClientTransaction clientTransaction = event.getClientTransaction();
230 processResponse(clientTransaction, response, ac);
231
232 } catch (Exception e) {
233 trace(Level.WARNING, "Exception during onServerErrorRespEvent", e);
234 }
235 }
236
237 public void onGlobalFailureRespEvent(ResponseEvent event, ActivityContextInterface ac) {
238 trace(Level.INFO, "Received 6xx (GLOBAL FAILURE) response");
239 try {
240
241 Response response = event.getResponse();
242 ClientTransaction clientTransaction = event.getClientTransaction();
243 processResponse(clientTransaction, response, ac);
244
245 } catch (Exception e) {
246 trace(Level.WARNING, "Exception during onGlobalFailureRespEvent", e);
247 }
248 }
249
250 /*
251 Timeouts
252 */
253
254 public void onTransactionTimeoutEvent( TimeoutEvent event, ActivityContextInterface ac ){
255 ClientTransaction clientTransaction = event.getClientTransaction();
256 ServerTransaction serverTransaction = event.getServerTransaction();
257
258 trace(Level.INFO, "Received transaction timeout event, tid=" + clientTransaction);
259 if (serverTransaction != null) {
260 try {
261 // Find the server transaction activity that is associated with this
262 // client transaction, and set it to terminated so subsequent ACKs
263 // will be ignored.
264 ActivityContextInterface[] activities = getSbbContext().getActivities();
265 SipProxySbbActivityContextInterface serverTxnActivity = null;
266 for (int i=0; i < activities.length; i++) {
267 serverTxnActivity = asSbbActivityContextInterface(activities[i]);
268 if (clientTransaction == serverTxnActivity.getClientTransaction()) {
269 trace(Level.INFO, "onTransactionTimeoutEvent: terminating server transaction " + serverTransaction);
270 serverTxnActivity.setTransactionTerminated(true);
271 break;
272 }
273 }
274
275 serverTransaction.sendResponse(getMessageFactory().createResponse(Response.REQUEST_TIMEOUT, serverTransaction.getRequest()));
276
277 } catch (Exception e) {
278 trace(Level.WARNING, "Exception during onTransactionTimeoutEvent", e);
279 }
280 }
281 }
282
283 public void onTransactionExpiredEvent( TimeoutEvent event, ActivityContextInterface ac ){
284 trace(Level.INFO, "Received transaction expired event");
285 }
286
287 public ServerTransaction getServerTransaction(ClientTransaction clientTransaction) {
288 // We should only ever be attached to two activities (our client and server transactions) so find the attached activity
289 // that is a server transaction
290 ActivityContextInterface myacis[] = getSbbContext().getActivities();
291 for (int i = 0; i < myacis.length; i++) {
292 ActivityContextInterface myaci = myacis[i];
293 if (myaci.getActivity() instanceof ServerTransaction) {
294 return (ServerTransaction) myaci.getActivity();
295 }
296 }
297 trace(Level.WARNING, "Could not find an attached ServerTransaction");
298 return null;
299 }
300
301 /**
302 * Inner class that overrides some proxy behaviour.
303 * Used to store transaction mappings in ACIs
304 *
305 * TODO: support forking
306 */
307 private class MySipProxy extends AbstractSipProxy {
308
309 private SipProxySbbActivityContextInterface sipaci;
310
311 MySipProxy(SipBaseSbb config, SipProxySbbActivityContextInterface sipaci) {
312 super(config);
313 this.sipaci = sipaci;
314 }
315
316 /* overridden to keep state in ACIs */
317 public void forwardRequest(ServerTransaction serverTransaction, Request request) {
318 try {
319
320 if (request.getMethod().equals(Request.ACK)) {
321 trace(Level.FINEST, "Sending request:\n" + request.toString());
322 sendStatelessRequest(request);
323
324 }
325 else if (request.getMethod().equals(Request.CANCEL)) {
326 // send the CANCEL request to endpoint - don't care about response
327 sendRequest(request, false);
328 }
329 else {
330 trace(Level.FINEST, "Sending request:\n" + request.toString());
331 // Send request on a new client transaction, and attach so we get responses
332 ClientTransaction clientTransaction = sendRequest(request, true);
333 trace(Level.FINEST, "clientTransaction = " + clientTransaction);
334 }
335
336 } catch (Exception e) {
337 e.printStackTrace();
338 trace(Level.WARNING, "Exception during forwardRequest", e);
339 sendErrorResponse(serverTransaction, request, Response.SERVER_INTERNAL_ERROR);
340 }
341 }
342
343 public void sendErrorResponse(ServerTransaction txn, Request request, int statusCode) {
344 try {
345 trace(Level.FINEST, "Ending transaction - subsequent messages will be ignored");
346 new Throwable().printStackTrace();
347 sipaci.setTransactionTerminated(true);
348 txn.sendResponse(getMessageFactory().createResponse(statusCode, request));
349 } catch (Exception e) {
350 //e.printStackTrace();
351 trace(Level.WARNING, "Exception during sendErrorResponse", e);
352 }
353 }
354
355 public void forwardResponse(ServerTransaction txn, Response response) {
356 try {
357 trace(Level.FINEST, "Forwarding response:\n" + response);
358 if (txn != null) {
359 txn.sendResponse(response);
360 }
361 else {
362 // forward statelessly anyway
363 sendStatelessResponse(response);
364 }
365 } catch (Exception e) {
366 e.printStackTrace();
367 }
368 }
369
370 }
371 public abstract ProxySbbUsage getDefaultSbbUsageParameterSet();
372 protected abstract ClientTransaction sendRequest(Request request, boolean attach) throws SipException;
373 protected abstract void sendStatelessRequest(Request request) throws SipException;
374 protected abstract void sendStatelessResponse(Response response) throws SipException;
375 }
376