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.stack;
028:
029: import java.io.IOException;
030: import gov.nist.core.*;
031: import gov.nist.siplite.address.*;
032: import gov.nist.siplite.header.*;
033: import gov.nist.siplite.message.*;
034: import gov.nist.siplite.SIPConstants;
035: import java.util.Vector;
036: import java.util.Enumeration;
037: import com.sun.midp.security.SecurityToken;
038:
039: import com.sun.midp.log.Logging;
040: import com.sun.midp.log.LogChannels;
041:
042: /**
043: * This class defines a SIP Stack. In order to build a SIP server (UAS/UAC or
044: * Proxy etc.) you need to extend this class and instantiate it in your
045: * application. After you have done so, call
046: * {@link #createMessageProcessor}
047: * to create message processors and then start these message processors to
048: * get the stack the process messages.
049: * This will start the necessary threads that wait for incoming SIP messages.
050: * A general note about the handler structures -- handlers are expected to
051: * returnResponse for successful message processing and throw
052: * SIPServerException for unsuccessful message processing.
053: *
054: * <a href="{@docRoot}/uncopyright.html">This code is in the public domain.</a>
055: *
056: */
057:
058: public abstract class SIPMessageStack {
059: /**
060: * Security token for SIP/SIPS protocol class
061: */
062: protected SecurityToken securityToken;
063: /** Flag indicating tcp connection in use. */
064: protected boolean tcpFlag;
065: /** Flag indicating udp connection in use. */
066: protected boolean udpFlag;
067: /** The outbound proxy location. */
068: protected String outboundProxy;
069: /** The outbound proxy server port. */
070: protected int outboundPort = -1;
071:
072: /**
073: * Flag that indicates that the stack is active.
074: */
075: protected boolean toExit;
076:
077: /**
078: * Bad message log. The name of a file that stores bum messages for
079: * debugging.
080: */
081: protected String badMessageLog;
082:
083: /**
084: * Internal flag for debugging
085: */
086: protected boolean debugFlag;
087:
088: /**
089: * Name of the stack.
090: */
091: protected String stackName;
092:
093: /**
094: * IP address of stack.
095: */
096: protected String stackAddress; // My host address.
097:
098: /**
099: * Request factory interface (to be provided by the application).
100: */
101: protected SIPStackMessageFactory sipMessageFactory;
102:
103: /**
104: * Router to determine where to forward the request.
105: */
106: protected Router router;
107:
108: /**
109: * Starts a single processing thread for all UDP messages
110: * (otherwise, the stack will start a new thread for each UDP
111: * message).
112: */
113: protected int threadPoolSize;
114:
115: /** Max number of simultaneous connections. */
116: protected int maxConnections;
117:
118: /** A collection of message processors. */
119: private Vector messageProcessors;
120:
121: /**
122: * Logs a bad message (invoked when a parse exception arises).
123: *
124: * @param message is a string that contains the bad message to log.
125: */
126: public void logBadMessage(String message) {
127: if (badMessageLog != null) {
128: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
129: Logging.report(Logging.INFORMATION,
130: LogChannels.LC_JSR180, message + badMessageLog);
131: }
132: }
133: }
134:
135: /**
136: * Gets the file name of the bad message log.
137: * @return the file where bad messages are logged.
138: */
139: public String getBadMessageLog() {
140: return this .badMessageLog;
141: }
142:
143: /**
144: * Sets the flag that instructs the stack to only start a single
145: * thread for sequentially processing incoming udp messages (thus
146: * serializing the processing).
147: * Caution: If the user-defined function called by the
148: * processing thread blocks, then the entire server will block.
149: */
150: public void setSingleThreaded() {
151: this .threadPoolSize = 1;
152: }
153:
154: /**
155: * Sets the thread pool size for processing incoming UDP messages.
156: * Limit the total number of threads for processing udp messages.
157: * Caution: If the user-defined function called by the
158: * processing thread blocks, then the entire server will block.
159: * @param size the new thread pool size
160: */
161: public void setThreadPoolSize(int size) {
162: this .threadPoolSize = size;
163: }
164:
165: /**
166: * Sets the max # of simultaneously handled TCP connections.
167: * @param nconnections the new max connections
168: */
169: public void setMaxConnections(int nconnections) {
170: this .maxConnections = nconnections;
171: }
172:
173: /**
174: * Construcor for the stack. Registers the request and response
175: * factories for the stack.
176: * @param messageFactory User-implemented factory for processing
177: * messages.
178: * @param stackAddress -- IP address or host name of the stack.
179: * @param stackName -- descriptive name for the stack.
180: */
181: public SIPMessageStack(SIPStackMessageFactory messageFactory,
182: String stackAddress, String stackName)
183: throws IllegalArgumentException {
184: this ();
185: sipMessageFactory = messageFactory;
186: if (stackAddress == null) {
187: throw new IllegalArgumentException("stack Address not set");
188: }
189:
190: // Set a descriptive name for the message trace logger.
191: ServerLog.description = stackName;
192: ServerLog.stackIpAddress = stackAddress;
193: }
194:
195: /**
196: * Sets the server Request and response factories.
197: * @param messageFactory User-implemented factory for processing
198: * messages.
199: */
200: public void setStackMessageFactory(
201: SIPStackMessageFactory messageFactory) {
202: sipMessageFactory = messageFactory;
203: }
204:
205: /**
206: * Sets the descriptive name of the stack.
207: * @param stackName -- descriptive name of the stack.
208: */
209: public void setStackName(String stackName) {
210: this .stackName = stackName;
211: ServerLog.setDescription(stackName);
212: ServerLog.stackIpAddress = stackAddress;
213: }
214:
215: /**
216: * Gets the Stack name.
217: * @return name of the stack.
218: */
219: public String getStackName() {
220: return this .stackName;
221: }
222:
223: /**
224: * Sets my address.
225: * @param stackAddress -- A string containing the stack address.
226: */
227: public void setHostAddress(String stackAddress) {
228: if (stackAddress.indexOf(':') != stackAddress.lastIndexOf(':')
229: && stackAddress.trim().charAt(0) != '[')
230: this .stackAddress = '[' + stackAddress + ']';
231: else
232: this .stackAddress = stackAddress;
233: }
234:
235: /**
236: * Gets my address.
237: * @return hostAddress - my host address.
238: */
239: public String getHostAddress() {
240: return this .stackAddress;
241: }
242:
243: /**
244: * Gets the default next hop from the router.
245: * @return the default next hop
246: */
247: public Hop getNextHop() {
248: return (Hop) this .router.getOutboundProxy();
249:
250: }
251:
252: /**
253: * Gets port of the message processor (based on the transport). If
254: * multiple ports are enabled for the same transport then the first
255: * one is retrieved.
256: * @param transport is the transport for which to get the port.
257: * @return the message processor port
258: * @exception IllegalArgumentException if the transport is not
259: * supported
260: */
261: public int getPort(String transport)
262: throws IllegalArgumentException {
263: synchronized (messageProcessors) {
264: Enumeration it = messageProcessors.elements();
265: while (it.hasMoreElements()) {
266: MessageProcessor mp = (MessageProcessor) it
267: .nextElement();
268: if (Utils
269: .equalsIgnoreCase(mp.getTransport(), transport))
270: return mp.getPort();
271: }
272: throw new IllegalArgumentException(
273: "Transport not supported " + transport);
274: }
275: }
276:
277: /**
278: * Returns true if a transport is enabled.
279: * @param transport is the transport to check.
280: * @return true if transport is enabled
281: */
282: public boolean isTransportEnabled(String transport) {
283: synchronized (messageProcessors) {
284: Enumeration it = messageProcessors.elements();
285: while (it.hasMoreElements()) {
286: MessageProcessor mp = (MessageProcessor) it
287: .nextElement();
288: if (Utils
289: .equalsIgnoreCase(mp.getTransport(), transport))
290: return true;
291: }
292: return false;
293: }
294: }
295:
296: /**
297: * Returns true if the transport is enabled for a given port.
298: * @param transport transport to check
299: * @param port port to check transport at.
300: * @return true if transport is enabled
301: */
302: public boolean isTransportEnabled(String transport, int port) {
303: synchronized (messageProcessors) {
304: Enumeration it = messageProcessors.elements();
305: while (it.hasMoreElements()) {
306: MessageProcessor mp = (MessageProcessor) it
307: .nextElement();
308: if (Utils
309: .equalsIgnoreCase(mp.getTransport(), transport)
310: && mp.getPort() == port)
311: return true;
312: }
313: return false;
314: }
315: }
316:
317: /**
318: * Default constructor.
319: */
320: public SIPMessageStack() {
321: this .toExit = false;
322: // Set an infinit thread pool size.
323: this .threadPoolSize = -1;
324: // Max number of simultaneous connections.
325: this .maxConnections = -1;
326: // Array of message processors.
327: messageProcessors = new Vector();
328: }
329:
330: /**
331: * Generates a new SIPSeverRequest from the given Request. A
332: * SIPServerRequest is generated by the application
333: * SIPServerRequestFactoryImpl. The application registers the
334: * factory implementation at the time the stack is initialized.
335: * @param siprequest Request for which we want to generate
336: * thsi SIPServerRequest.
337: * @param msgchan Message channel for the request for which
338: * we want to generate the SIPServerRequest
339: * @return Generated SIPServerRequest.
340: */
341: protected SIPServerRequestInterface newSIPServerRequest(
342: Request siprequest, MessageChannel msgchan) {
343: return sipMessageFactory.newSIPServerRequest(siprequest,
344: msgchan);
345: }
346:
347: /**
348: * Generates a new SIPSeverResponse from the given Response.
349: * @param sipresponse Response from which the SIPServerResponse
350: * is to be generated. Note - this just calls the factory interface
351: * to do its work. The factory interface is provided by the user.
352: * @param msgchan Message channel for the SIPServerResponse
353: * @return SIPServerResponse generated from this SIP
354: * Response
355: */
356: SIPServerResponseInterface newSIPServerResponse(
357: Response sipresponse, MessageChannel msgchan) {
358: return sipMessageFactory.newSIPServerResponse(sipresponse,
359: msgchan);
360: }
361:
362: /**
363: * Sets the router algorithm.
364: * @param router A class that implements the Router interface.
365: */
366: public void setRouter(Router router) {
367: this .router = router;
368: }
369:
370: /**
371: * Gets the router algorithm.
372: * @return Router router
373: */
374: public Router getRouter() {
375: return router;
376: }
377:
378: /**
379: * Gets the default route.
380: * @return the default route
381: */
382: public Hop getDefaultRoute() {
383: return this .router.getOutboundProxy();
384: }
385:
386: /**
387: * Gets the route header for this hop.
388: * @param hop the hop to be processed
389: * @return the route header for the hop.
390: */
391: public RouteHeader getRouteHeader(Hop hop) {
392: HostPort hostPort = new HostPort();
393: Host h = new Host(hop.getHost());
394: hostPort.setHost(h);
395: hostPort.setPort(hop.getPort());
396: gov.nist.siplite.address.SipURI uri = new SipURI();
397: uri.setHostPort(hostPort);
398: uri.setScheme(SIPConstants.SCHEME_SIP);
399:
400: try {
401: uri.setTransportParam(hop.getTransport());
402: } catch (ParseException ex) {
403: InternalErrorHandler.handleException(ex);
404: }
405:
406: Address address = new Address();
407: address.setURI(uri);
408: RouteHeader route = new RouteHeader();
409: route.setAddress(address);
410:
411: return route;
412: }
413:
414: /**
415: * Gets the route header corresponding to the default route.
416: * @return the default route header
417: */
418: public RouteHeader getDefaultRouteHeader() {
419: if (router.getOutboundProxy() != null) {
420: Hop hop = ((Hop) router.getOutboundProxy());
421: return getRouteHeader(hop);
422: } else
423: return null;
424: }
425:
426: /**
427: * Returns the status of the toExit flag.
428: * @return true if the stack object is alive and false otherwise.
429: */
430: public synchronized boolean isAlive() {
431: return !toExit;
432: }
433:
434: /**
435: * Makes the stack close all accept connections and return. This
436: * is useful if you want to start/stop the stack several times from
437: * your application. Caution : use of this function could cause
438: * peculiar bugs as messages are prcessed asynchronously by the stack.
439: */
440:
441: public void stopStack() {
442: synchronized (this .messageProcessors) {
443: // Threads must periodically check this flag.
444: this .toExit = true;
445: Vector processorList;
446: processorList = getMessageProcessors();
447: /*
448: * IMPL_NOTE:
449: * Normally, messageprocessors are already stopped before
450: * stopStack() is explicitely invoked from close() of
451: * SipConnectionNotifier. So it is not needed to iterate through the
452: * list. However, this part of the code is not yet removed as it is
453: * not known if sipStack() needs to be closed independantly.
454: * A safetly check is added before invoking stop() for a message
455: * processor to verify if it was already closed
456: */
457: for (int i = 0; i < processorList.size(); i++) {
458: MessageProcessor mp = (MessageProcessor) processorList
459: .elementAt(i);
460: if (!mp.toExit()) {
461: mp.stop();
462: }
463: }
464: processorList.removeAllElements();
465: }
466: }
467:
468: /**
469: * Adds a new MessageProcessor to the list of running processors
470: * for this SIPMessageStack and starts it. You can use this method
471: * for dynamic stack configuration.
472: * Acknowledgement: This code is contributed by Jeff Keyser.
473: * @param newMessageProcessor the new message processor to
474: * register
475: */
476: public void addMessageProcessor(MessageProcessor newMessageProcessor)
477: throws IOException {
478: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
479: Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
480: "addMessageProcessor "
481: + newMessageProcessor.getPort() + " / "
482: + newMessageProcessor.getTransport());
483: }
484:
485: synchronized (messageProcessors) {
486: messageProcessors.addElement(newMessageProcessor);
487: newMessageProcessor.start();
488: }
489: }
490:
491: /**
492: * Removes a MessageProcessor from this SIPMessageStack. Acknowledgement:
493: * Code contributed by Jeff Keyser.
494: * @param oldMessageProcessor
495: */
496: public void removeMessageProcessor(
497: MessageProcessor oldMessageProcessor) {
498: synchronized (messageProcessors) {
499:
500: if (messageProcessors.removeElement(oldMessageProcessor)) {
501:
502: oldMessageProcessor.stop();
503: }
504: }
505: }
506:
507: /**
508: * Gets an array of running MessageProcessors on this SIPMessageStack.
509: * Acknowledgement: Jeff Keyser suggested that applications should
510: * have access to the running message processors and contributed
511: * this code.
512: * @return an array of running message processors.
513: *
514: */
515: public Vector getMessageProcessors() {
516: return messageProcessors;
517: }
518:
519: /**
520: * Gets a message processor for the given transport.
521: * @param transport the transport to be checked
522: * @return the message processor for the transport
523: */
524: public MessageProcessor getMessageProcessor(String transport) {
525: synchronized (messageProcessors) {
526: Enumeration it = messageProcessors.elements();
527: while (it.hasMoreElements()) {
528: MessageProcessor mp = (MessageProcessor) it
529: .nextElement();
530: if (Utils
531: .equalsIgnoreCase(mp.getTransport(), transport)) {
532: return mp;
533: }
534: }
535:
536: return null;
537: }
538: }
539:
540: /**
541: * Creates the equivalent of a JAIN listening point and attaches
542: * to the stack.
543: * @param port the message processor port address
544: * @param transport the message processor transport type
545: * @return the requested message processor
546: */
547: public MessageProcessor createMessageProcessor(int port,
548: String transport) throws java.io.IOException,
549: IllegalArgumentException {
550:
551: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
552: Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
553: "createMessageProcessor : " + port + " / "
554: + transport);
555: }
556:
557: if (Utils.equalsIgnoreCase(transport,
558: SIPConstants.TRANSPORT_UDP)) {
559: UDPMessageProcessor udpMessageProcessor = new UDPMessageProcessor(
560: this , port);
561: this .addMessageProcessor(udpMessageProcessor);
562: this .udpFlag = true;
563: return udpMessageProcessor;
564: } else if (Utils.equalsIgnoreCase(transport,
565: SIPConstants.TRANSPORT_TCP)) {
566: TCPMessageProcessor tcpMessageProcessor = new TCPMessageProcessor(
567: this , port);
568: this .addMessageProcessor(tcpMessageProcessor);
569: this .tcpFlag = true;
570: return tcpMessageProcessor;
571: } else {
572: throw new IllegalArgumentException("bad transport");
573: }
574:
575: }
576:
577: /**
578: * Sets the message factory.
579: * @param messageFactory -- messageFactory to set.
580: */
581: protected void setMessageFactory(
582: SIPStackMessageFactory messageFactory) {
583: this .sipMessageFactory = messageFactory;
584: }
585:
586: /**
587: * Creates a new MessageChannel for a given Hop.
588: * @param nextHop Hop to create a MessageChannel to.
589: * @return A MessageChannel to the specified Hop, or null if
590: * no MessageProcessors support contacting that Hop.
591: * @throws UnknwonHostException If the host in the Hop doesn't
592: * exist.
593: */
594: public MessageChannel createMessageChannel(Hop nextHop) {
595: Host targetHost;
596: HostPort targetHostPort;
597: MessageProcessor nextProcessor;
598: MessageChannel newChannel;
599:
600: // Create the host/port of the target hop
601: targetHost = new Host();
602: targetHost.setHostname(nextHop.getHost());
603: targetHostPort = new HostPort();
604: targetHostPort.setHost(targetHost);
605: targetHostPort.setPort(nextHop.getPort());
606:
607: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
608: Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
609: "createMessageChannel " + nextHop);
610: }
611:
612: // Search each processor for the correct transport
613: newChannel = null;
614: Enumeration processorIterator = messageProcessors.elements();
615:
616: while (processorIterator.hasMoreElements()
617: && newChannel == null) {
618: nextProcessor = (MessageProcessor) processorIterator
619: .nextElement();
620: // If a processor that supports the correct
621: // transport is found,
622: if (Utils.equalsIgnoreCase(nextHop.getTransport(),
623: nextProcessor.getTransport())) {
624: try {
625: // Create a channel to the target host/port
626: newChannel = nextProcessor
627: .createMessageChannel(targetHostPort);
628: } catch (IOException e) {
629: e.printStackTrace();
630: // Ignore channel creation error -
631: // try next processor
632: }
633: }
634: }
635:
636: if (newChannel == null) { // Message processor was not found
637: // Try to create it
638: try {
639: MessageProcessor processor = createMessageProcessor(
640: nextHop.getPort(), nextHop.getTransport());
641: // IMPL_NOTE: The previous message processor should be
642: // removed on level of re-routing SIP messages
643: newChannel = processor
644: .createMessageChannel(targetHostPort);
645: } catch (IOException ex) {
646: } catch (IllegalArgumentException ex) {
647: }
648: }
649: // Return the newly-created channel
650: return newChannel;
651: }
652:
653: /**
654: * Return a security token associated with the protocol class
655: * @return Security token
656: */
657: protected SecurityToken getSecurityToken() {
658: return securityToken;
659: }
660:
661: /**
662: * Set the security token associated with the protocol class
663: * @param token Security token from SIP/SIPS Protocol class
664: */
665: protected void setSecurityToken(SecurityToken token) {
666: securityToken = token;
667: }
668:
669: }
|