001: /*
002: * Portions Copyright 2000-2007 Sun Microsystems, Inc. All Rights
003: * Reserved. Use is subject to license terms.
004: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU General Public License version
008: * 2 only, as published by the Free Software Foundation.
009: *
010: * This program is distributed in the hope that it will be useful, but
011: * WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * General Public License version 2 for more details (a copy is
014: * included at /legal/license.txt).
015: *
016: * You should have received a copy of the GNU General Public License
017: * version 2 along with this work; if not, write to the Free Software
018: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
019: * 02110-1301 USA
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
022: * Clara, CA 95054 or visit www.sun.com if you need additional
023: * information or have any questions.
024: */
025: /*
026: */
027: package gov.nist.siplite;
028:
029: import gov.nist.siplite.message.*;
030: import gov.nist.siplite.stack.*;
031: import gov.nist.siplite.header.*;
032: import gov.nist.core.*;
033:
034: import com.sun.midp.log.Logging;
035: import com.sun.midp.log.LogChannels;
036:
037: /**
038: * An adapter class from the JAIN implementation objects to the NIST-SIP stack.
039: * This is the class that is instantiated by the NistSipMessageFactory to
040: * create a new SIPServerRequest or SIPServerResponse.
041: * Note that this is not part of the JAIN-SIP spec (it does not implement
042: * a JAIN-SIP interface). This is part of the glue that ties together the
043: * NIST-SIP stack and event model with the JAIN-SIP stack. Implementors
044: * of JAIN services need not concern themselves with this class.
045: *
046: * @version JAIN-SIP-1.1
047: *
048: * <a href="{@docRoot}/uncopyright.html">This code is in the public domain.</a>
049: *
050: */
051: public class NistSipMessageHandlerImpl implements
052: SIPServerRequestInterface, SIPServerResponseInterface {
053: /** Current transaction channel. */
054: protected Transaction transactionChannel;
055: /** Raw message channel. */
056: protected MessageChannel rawMessageChannel;
057: // protected Request sipRequest;
058: // protected Response sipResponse;
059: /** Current listening filter. */
060: protected ListeningPoint listeningPoint;
061:
062: /**
063: * Process a request.
064: * @param sipRequest the request to be processed
065: * @param incomingMessageChannel the inbound message connection
066: * @exception SIPServerException is thrown when there is an error
067: * processing the request.
068: */
069: public void processRequest(Request sipRequest,
070: MessageChannel incomingMessageChannel)
071: throws SIPServerException {
072: // Generate the wrapper JAIN-SIP object.
073: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
074: Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
075: "PROCESSING INCOMING REQUEST "
076: + sipRequest.getFirstLine());
077: }
078: this .rawMessageChannel = incomingMessageChannel;
079:
080: SipStack sipStack = (SipStack) transactionChannel.getSIPStack();
081:
082: /*
083: * What if the listeningPoint of the incomingMessagechannel different
084: * than the one that set during initialization in
085: * NistSipMesageFactoryImpl?
086: * So, initialize it explicitely for the incomingMessageChannel
087: */
088: listeningPoint = incomingMessageChannel.getMessageProcessor()
089: .getListeningPoint();
090: if (listeningPoint == null) {
091: if (Logging.REPORT_LEVEL <= Logging.WARNING) {
092: Logging
093: .report(Logging.WARNING, LogChannels.LC_JSR180,
094: "Dropping message: No listening point registered!");
095: }
096: return;
097: }
098:
099: SipProvider sipProvider = listeningPoint.getProvider();
100:
101: if (sipProvider == null) {
102: if (Logging.REPORT_LEVEL <= Logging.WARNING) {
103: Logging.report(Logging.WARNING, LogChannels.LC_JSR180,
104: "No provider - dropping !!");
105: }
106: return;
107: }
108:
109: // SipListener sipListener = sipProvider.sipListener;
110: Transaction transaction = transactionChannel;
111:
112: // Look for the registered SIPListener for the message channel.
113: synchronized (sipProvider) {
114: String dialogId = sipRequest.getDialogId(true);
115: Dialog dialog = sipStack.getDialog(dialogId);
116: final ServerTransaction requestTransaction = (ServerTransaction) sipRequest
117: .getTransaction();
118: if (null == requestTransaction.getDialog()) {
119: requestTransaction.setDialog(dialog);
120: }
121: if (sipRequest.getMethod().equals(Request.ACK)) {
122: // Could not find transaction. Generate an event
123: // with a null transaction identifier.
124: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
125: Logging.report(Logging.INFORMATION,
126: LogChannels.LC_JSR180,
127: "Processing ACK for dialog " + dialog);
128: }
129:
130: if (dialog == null) {
131: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
132: Logging.report(Logging.INFORMATION,
133: LogChannels.LC_JSR180,
134: "Dialog does not exist "
135: + sipRequest.getFirstLine()
136: + " isServerTransaction = "
137: + true);
138: }
139:
140: transaction = sipStack.findTransaction(sipRequest,
141: true);
142: } else if (dialog.getLastAck() != null
143: && dialog.getLastAck().equals(sipRequest)) {
144: if (sipStack.isRetransmissionFilterActive()) {
145: dialog.ackReceived(sipRequest);
146: transaction.setDialog(dialog);
147:
148: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
149: Logging
150: .report(
151: Logging.INFORMATION,
152: LogChannels.LC_JSR180,
153: "Retransmission Filter enabled -"
154: + " dropping Ack retransmission");
155: }
156:
157: // filter out retransmitted acks if
158: // retransmission filter is enabled.
159: return;
160: }
161:
162: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
163: Logging.report(Logging.INFORMATION,
164: LogChannels.LC_JSR180,
165: "ACK retransmission for 2XX "
166: + "response "
167: + "Sending ACK to the TU");
168: }
169: } else {
170: // This could be a re-invite processing.
171: // check to see if the ack matches with the last
172: // transaction.
173:
174: Transaction tr = dialog.getLastTransaction();
175: Response sipResponse = tr.getLastResponse();
176:
177: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
178: Logging.report(Logging.INFORMATION,
179: LogChannels.LC_JSR180, "TRANSACTION:"
180: + tr);
181: }
182:
183: if (tr instanceof ServerTransaction
184: && sipResponse != null
185: && sipResponse.getStatusCode() / 100 == 2
186: && sipResponse.getCSeqHeader()
187: .getSequenceNumber() == sipRequest
188: .getCSeqHeader()
189: .getSequenceNumber()) {
190: transaction.setDialog(dialog);
191: dialog.ackReceived(sipRequest);
192:
193: if (sipStack.isRetransmissionFilterActive()
194: && tr.isAckSeen()) {
195: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
196: Logging.report(Logging.INFORMATION,
197: LogChannels.LC_JSR180,
198: "ACK retransmission for"
199: + " 2XX response --- "
200: + "Dropping ");
201: }
202: return;
203: } else {
204: // record that we already saw an ACK for
205: // this transaction.
206: tr.setAckSeen();
207: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
208: Logging.report(Logging.INFORMATION,
209: LogChannels.LC_JSR180,
210: "ACK retransmission for 2XX "
211: + "response --- "
212: + "sending to TU ");
213: }
214: }
215:
216: } else {
217: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
218: Logging.report(Logging.INFORMATION,
219: LogChannels.LC_JSR180,
220: "ACK retransmission for non"
221: + " 2XX response "
222: + "Discarding ACK");
223: }
224:
225: // Could not find a transaction.
226: if (tr == null) {
227: if (Logging.REPORT_LEVEL <= Logging.WARNING) {
228: Logging
229: .report(Logging.WARNING,
230: LogChannels.LC_JSR180,
231: "Could not find transaction ACK dropped");
232: }
233: return;
234: }
235:
236: transaction = tr;
237: if (transaction instanceof ClientTransaction) {
238: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
239: Logging.report(Logging.INFORMATION,
240: LogChannels.LC_JSR180,
241: "Dropping late ACK");
242: }
243: return;
244: }
245: }
246: }
247: } else if (sipRequest.getMethod().equals(Request.BYE)) {
248: transaction = this .transactionChannel;
249: // If the stack has not mapped this transaction because
250: // of sequence number problem then just drop the BYE
251: if (transaction != null
252: && ((ServerTransaction) transaction)
253: .isTransactionMapped()) {
254: // Get the dialog identifier for the bye request.
255: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
256: Logging.report(Logging.INFORMATION,
257: LogChannels.LC_JSR180, "dialogId = "
258: + dialogId);
259: }
260:
261: // Find the dialog identifier in the SIP stack and
262: // mark it for garbage collection.
263: if (dialog != null) {
264: // Remove dialog marks all
265: dialog.addTransaction(transaction);
266: } else {
267: dialogId = sipRequest.getDialogId(false);
268:
269: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
270: Logging.report(Logging.INFORMATION,
271: LogChannels.LC_JSR180,
272: "dialogId = " + dialogId);
273: }
274:
275: dialog = sipStack.getDialog(dialogId);
276:
277: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
278: Logging.report(Logging.INFORMATION,
279: LogChannels.LC_JSR180, "dialog = "
280: + dialog);
281: }
282:
283: if (dialog != null) {
284: dialog.addTransaction(transaction);
285: } else {
286: transaction = null;
287: // pass up to provider for
288: // stateless handling.
289: }
290: }
291: } else if (transaction != null) {
292: // This is an out of sequence BYE
293: // transaction was allocated but
294: // not mapped to the stack so
295: // just discard it.
296: if (dialog != null) {
297: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
298: Logging.report(Logging.INFORMATION,
299: LogChannels.LC_JSR180,
300: "Dropping out of sequence BYE");
301: }
302: return;
303: } else
304: transaction = null;
305: }
306: // note that the transaction may be null (which
307: // happens when no dialog for the bye was fund.
308: } else if (sipRequest.getRequestLine().getMethod().equals(
309: Request.CANCEL)) {
310:
311: // The ID refers to a previously sent
312: // INVITE therefore it refers to the
313: // server transaction table.
314: // Find the transaction to cancel.
315: // Send a 487 for the cancel to inform the
316: // other side that we've seen it but do not send the
317: // request up to the application layer.
318:
319: // Get rid of the CANCEL transaction -- we pass the
320: // transaciton we are trying to cancel up to the TU.
321:
322: // Antonis Karydas: Suggestion
323: // 'transaction' here refers to the transaction to
324: // be cancelled. Do not change
325: // it's state because of the CANCEL.
326: // Wait, instead for the 487 from TU.
327: // transaction.setState(Transaction.TERMINATED_STATE);
328:
329: ServerTransaction serverTransaction = (ServerTransaction) sipStack
330: .findCancelTransaction(sipRequest, true);
331:
332: // Generate an event
333: // with a null transaction identifier.
334: if (serverTransaction == null) {
335: // Could not find the invite transaction.
336: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
337: Logging.report(Logging.INFORMATION,
338: LogChannels.LC_JSR180, "transaction "
339: + " does not exist "
340: + sipRequest.getFirstLine()
341: + "isServerTransaction = "
342: + true);
343: }
344: transaction = null;
345: } else {
346: transaction = serverTransaction;
347: }
348: }
349:
350: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
351: Logging.report(Logging.INFORMATION,
352: LogChannels.LC_JSR180, "-----------------");
353: Logging.report(Logging.INFORMATION,
354: LogChannels.LC_JSR180, sipRequest.toString());
355: }
356:
357: if (dialog != null && transaction != null
358: && !sipRequest.getMethod().equals(Request.BYE)
359: && !sipRequest.getMethod().equals(Request.CANCEL)
360: && !sipRequest.getMethod().equals(Request.ACK)) {
361: // already dealt with bye above.
362: // Note that route updates are only effective until
363: // Dialog is in the confirmed state.
364: if (dialog.getRemoteSequenceNumber() >= sipRequest
365: .getCSeqHeader().getSequenceNumber()) {
366: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
367: Logging
368: .report(
369: Logging.INFORMATION,
370: LogChannels.LC_JSR180,
371: "Dropping out of sequence message "
372: + dialog
373: .getRemoteSequenceNumber()
374: + " "
375: + sipRequest
376: .getCSeqHeader());
377: }
378:
379: return;
380: }
381:
382: dialog.addTransaction(transaction);
383: dialog.addRoute(sipRequest);
384: }
385:
386: RequestEvent sipEvent;
387:
388: if (dialog == null
389: && sipRequest.getMethod().equals(Request.NOTIFY)) {
390: ClientTransaction ct = sipStack
391: .findSubscribeTransaction(sipRequest);
392: // From RFC 3265
393: // If the server transaction cannot be found or if it
394: // aleady has a dialog attached to it then just assign the
395: // notify to this dialog and pass it up.
396: if (ct != null) {
397: transaction.setDialog(ct.getDialog());
398: if (ct.getDialog().getState() == Dialog.INITIAL_STATE) {
399: sipEvent = new RequestEvent(sipProvider, null,
400: (Request) sipRequest);
401: } else {
402: sipEvent = new RequestEvent(sipProvider,
403: (ServerTransaction) transaction,
404: sipRequest);
405: }
406: } else {
407: // Got a notify out of the blue - just pass it up
408: // for stateless handling by the application.
409: sipEvent = new RequestEvent(sipProvider, null,
410: sipRequest);
411: }
412:
413: } else {
414: // For a dialog creating event - set the transaction to null.
415: // The listener can create the dialog if needed.
416: if (transaction != null
417: && ((ServerTransaction) transaction)
418: .isTransactionMapped())
419: sipEvent = new RequestEvent(sipProvider,
420: (ServerTransaction) transaction, sipRequest);
421: else
422: sipEvent = new RequestEvent(sipProvider, null,
423: sipRequest);
424: }
425: sipProvider.handleEvent(sipEvent, transaction);
426: }
427:
428: }
429:
430: /**
431: * Process the response.
432: * @param sipResponse the response message
433: * @param incomingMessageChannel message channel on which the
434: * response is received.
435: * @exception SIPServerException is thrown when there is an error
436: * processing the response
437: */
438: public void processResponse(Response sipResponse,
439: MessageChannel incomingMessageChannel)
440: throws SIPServerException {
441: try {
442: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
443: Logging.report(Logging.INFORMATION,
444: LogChannels.LC_JSR180,
445: "PROCESSING INCOMING RESPONSE"
446: + sipResponse.encode());
447: }
448:
449: /*
450: * What if the listeningPoint of the incomingMessagechannel
451: * different than the one that set during initialization in
452: * NistSipMesageFactoryImpl?
453: * So, initialize it explicitely for the incomingMessageChannel.
454: */
455: listeningPoint = incomingMessageChannel
456: .getMessageProcessor().getListeningPoint();
457:
458: if (listeningPoint == null) {
459: if (Logging.REPORT_LEVEL <= Logging.WARNING) {
460: Logging
461: .report(Logging.WARNING,
462: LogChannels.LC_JSR180,
463: "Dropping message: No listening point registered!");
464: }
465: return;
466: }
467:
468: Transaction transaction = this .transactionChannel;
469: SipProvider sipProvider = listeningPoint.getProvider();
470:
471: if (sipProvider == null) {
472: if (Logging.REPORT_LEVEL <= Logging.WARNING) {
473: Logging.report(Logging.WARNING,
474: LogChannels.LC_JSR180,
475: "Dropping message: no provider");
476: }
477: return;
478: }
479:
480: SipStack sipStack = sipProvider.sipStack;
481:
482: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
483: Logging.report(Logging.INFORMATION,
484: LogChannels.LC_JSR180, "Transaction = "
485: + transaction);
486: }
487:
488: if (this .transactionChannel == null) {
489: String dialogId = sipResponse.getDialogId(false);
490: Dialog dialog = sipStack.getDialog(dialogId);
491:
492: // Have a dialog but could not find transaction.
493: if (sipProvider.sipListener == null) {
494: return;
495: } else if (dialog != null) {
496: if (sipResponse.getStatusCode() != Response.OK) {
497: return;
498: } else if (sipStack.isRetransmissionFilterActive()) {
499: // 200 retransmission for the final response.
500: if (sipResponse.getCSeqHeader().equals(
501: dialog.getFirstTransaction()
502: .getRequest().getHeader(
503: Header.CSEQ))) {
504: dialog.resendAck();
505: return;
506: }
507: }
508: }
509:
510: // long receptionTime = System.currentTimeMillis();
511: // Pass the response up to the application layer to handle
512: // statelessly.
513:
514: // Dialog is null so this is handled statelessly
515: ResponseEvent sipEvent = new ResponseEvent(sipProvider,
516: null, sipResponse);
517: sipProvider.handleEvent(sipEvent, transaction);
518: // transaction.logResponse(sipResponse,
519: // receptionTime,"Retransmission");
520: return;
521: }
522:
523: this .rawMessageChannel = incomingMessageChannel;
524:
525: String method = sipResponse.getCSeqHeader().getMethod();
526: // Retrieve the client transaction for which we are getting
527: // this response.
528: ClientTransaction clientTransaction = (ClientTransaction) this .transactionChannel;
529:
530: Dialog dialog = null;
531: if (transaction != null) {
532: dialog = transaction.getDialog();
533:
534: if (Logging.REPORT_LEVEL <= Logging.INFORMATION
535: && dialog == null) {
536: Logging.report(Logging.INFORMATION,
537: LogChannels.LC_JSR180,
538: "dialog not found for "
539: + sipResponse.getFirstLine());
540: }
541: }
542:
543: // SipListener sipListener = sipProvider.sipListener;
544:
545: ResponseEvent responseEvent = new ResponseEvent(
546: sipProvider, (ClientTransaction) transaction,
547: sipResponse);
548: sipProvider.handleEvent(responseEvent, transaction);
549: } catch (NullPointerException ex) {
550: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
551: Logging.report(Logging.INFORMATION,
552: LogChannels.LC_JSR180, "null ptr");
553: ex.printStackTrace();
554: }
555: }
556: }
557:
558: /**
559: * Gets the sender channel.
560: * @return the request channel
561: */
562: public MessageChannel getRequestChannel() {
563: return this .transactionChannel;
564: }
565:
566: /**
567: * Gets the channel if we want to initiate a new transaction to
568: * the sender of a response.
569: * @return a message channel that points to the place from where we got
570: * the response.
571: */
572: public MessageChannel getResponseChannel() {
573: if (this .transactionChannel != null)
574: return this .transactionChannel;
575: else
576: return this .rawMessageChannel;
577: }
578:
579: /**
580: * Just a placeholder. This is called from the stack
581: * for message logging. Auxiliary processing information can
582: * be passed back to be written into the log file.
583: * @return auxiliary information that we may have generated during the
584: * message processing which is retrieved by the message logger.
585: * (Always returns null)
586: */
587: public String getProcessingInfo() {
588: return null;
589: }
590: }
|