001: /**
002: * $RCSfile$
003: * $Revision: $
004: * $Date: $
005: *
006: * Copyright (C) 2007 Jive Software. All rights reserved.
007: *
008: * This software is published under the terms of the GNU Public License (GPL),
009: * a copy of which is included in this distribution.
010: */package org.jivesoftware.openfire.sip.tester.stack;
011:
012: import org.jivesoftware.openfire.sip.tester.comm.CommunicationsException;
013: import org.jivesoftware.openfire.sip.tester.comm.CommunicationsListener;
014: import org.jivesoftware.openfire.sip.tester.Log;
015: import org.jivesoftware.openfire.sip.tester.security.UserCredentials;
016: import org.jivesoftware.openfire.sip.tester.security.SipSecurityManager;
017:
018: import javax.sip.*;
019: import javax.sip.address.Address;
020: import javax.sip.address.AddressFactory;
021: import javax.sip.address.SipURI;
022: import javax.sip.header.*;
023: import javax.sip.message.MessageFactory;
024: import javax.sip.message.Request;
025: import javax.sip.message.Response;
026: import java.net.InetAddress;
027: import java.net.InetSocketAddress;
028: import java.net.UnknownHostException;
029: import java.text.ParseException;
030: import java.util.ArrayList;
031: import java.util.Iterator;
032: import java.util.TooManyListenersException;
033:
034: /**
035: * Title: SIP Register Tester
036: *
037: * @author Thiago Rocha Camargo (thiago@jivesoftware.com)
038: */
039:
040: public class SipManager implements SipListener {
041:
042: protected static final int RETRY_OBJECT_DELETES = 10;
043:
044: protected static final long RETRY_OBJECT_DELETES_AFTER = 500;
045:
046: protected static final String DEFAULT_TRANSPORT = "udp";
047:
048: protected InetAddress localAddress = null;
049:
050: public SipFactory sipFactory;
051:
052: public AddressFactory addressFactory;
053: public HeaderFactory headerFactory;
054: public MessageFactory messageFactory;
055: SipStack sipStack;
056: public boolean isBusy = true;
057: ListeningPoint listeningPoint;
058: public SipProvider sipProvider;
059: private InetSocketAddress publicIpAddress = null;
060: protected String sipStackPath = "gov.nist";
061: protected String currentlyUsedURI = null;
062: protected String displayName = null;
063: protected String transport = null;
064: protected String registrarAddress = null;
065: protected int localPort = -1;
066: protected int registrarPort = -1;
067: protected int registrationsExpiration = -1;
068: protected String registrarTransport = null;
069: private int registerRetries = 0;
070: protected String stackAddress = null;
071: protected String stackName = "JiveSIP";
072: protected FromHeader fromHeader = null;
073: protected ContactHeader contactHeader = null;
074: protected ArrayList<ViaHeader> viaHeaders = null;
075: protected static final int MAX_FORWARDS = 70;
076: protected MaxForwardsHeader maxForwardsHeader = null;
077: protected long registrationTransaction = -1;
078: protected ArrayList<CommunicationsListener> listeners = new ArrayList<CommunicationsListener>();
079: protected boolean isStarted = false;
080: private RegisterProcessing registerProcessing = null;
081: public SipSecurityManager sipSecurityManager = null;
082:
083: /**
084: * Constructor. It only creates a SipManager instance without initializing
085: * the stack itself.
086: *
087: * @param localAddress localAddress
088: */
089: public SipManager(InetAddress localAddress) {
090:
091: this .localAddress = localAddress;
092: registerProcessing = new RegisterProcessing(this );
093: sipSecurityManager = new SipSecurityManager();
094: registerRetries = 0;
095: }
096:
097: /**
098: * Creates and initializes JAIN SIP objects (factories, stack, listening
099: * point and provider). Once this method is called the application is ready
100: * to handle (incoming and outgoing) sip messages.
101: *
102: * @throws CommunicationsException if an axception should occur during the initialization
103: * process
104: */
105: public void start() throws CommunicationsException {
106:
107: initProperties();
108: SIPConfig.setSystemProperties();
109: this .sipFactory = SipFactory.getInstance();
110: sipFactory.setPathName(sipStackPath);
111: try {
112: addressFactory = sipFactory.createAddressFactory();
113: headerFactory = sipFactory.createHeaderFactory();
114: messageFactory = sipFactory.createMessageFactory();
115: } catch (PeerUnavailableException ex) {
116: Log.error("start", ex);
117:
118: throw new CommunicationsException(
119: "Could not create factories!", ex);
120: }
121:
122: try {
123: sipStack = sipFactory
124: .createSipStack(System.getProperties());
125: ((SipCommRouter) sipStack.getRouter())
126: .setOutboundProxy(SIPConfig.getOutboundProxy());
127: } catch (PeerUnavailableException ex) {
128: Log.error("start", ex);
129:
130: throw new CommunicationsException(
131: "Imposs�vel conectar!\n"
132: + "O proxy pode n�o est� acess�vel.\nVerifique sua conex�o."
133: + "(Syntax:<proxy_address:port/transport>)",
134: ex);
135: }
136:
137: try {
138: boolean successfullyBound = false;
139: while (!successfullyBound) {
140: try {
141:
142: publicIpAddress = new InetSocketAddress(
143: localAddress, localPort);
144: listeningPoint = sipStack.createListeningPoint(
145: localPort, transport);
146: } catch (InvalidArgumentException ex) {
147: // choose another port between 1024 and 65000
148:
149: localPort = (int) ((65000 - 1024) * Math.random()) + 1024;
150: try {
151: Thread.sleep(1000);
152: } catch (Exception e) {
153: // Do Nothing
154: }
155:
156: continue;
157: }
158: successfullyBound = true;
159: }
160: } catch (TransportNotSupportedException ex) {
161: throw new CommunicationsException(
162: "Transport "
163: + transport
164: + " is not suppported by the stack!\n Try specifying another"
165: + " transport in Mais property files.\n",
166: ex);
167: }
168: try {
169: sipProvider = sipStack.createSipProvider(listeningPoint);
170: } catch (ObjectInUseException ex) {
171: Log.error("start", ex);
172:
173: throw new CommunicationsException(
174: "Could not create factories!\n", ex);
175: }
176: try {
177: sipProvider.addSipListener(this );
178: } catch (TooManyListenersException exc) {
179: throw new CommunicationsException(
180: "Could not register SipManager as a sip listener!",
181: exc);
182: }
183:
184: sipSecurityManager.setHeaderFactory(headerFactory);
185: sipSecurityManager.setTransactionCreator(sipProvider);
186: sipSecurityManager.setSipManCallback(this );
187:
188: // Make sure prebuilt headers are nulled so that they get reinited
189: // if this is a restart
190: contactHeader = null;
191: fromHeader = null;
192: viaHeaders = null;
193: maxForwardsHeader = null;
194: isStarted = true;
195:
196: }
197:
198: /**
199: * Unregisters listening points, deletes sip providers, and generally
200: * prepares the stack for a re-start(). This method is meant to be used when
201: * properties are changed and should be reread by the stack.
202: *
203: * @throws CommunicationsException CommunicationsException
204: */
205: synchronized public void stop() throws CommunicationsException {
206: if (sipStack == null)
207: return;
208:
209: // Delete SipProvider
210: int tries;
211: for (tries = 0; tries < SipManager.RETRY_OBJECT_DELETES; tries++) {
212: try {
213: sipStack.deleteSipProvider(sipProvider);
214: } catch (ObjectInUseException ex) {
215:
216: SipManager.sleep(SipManager.RETRY_OBJECT_DELETES_AFTER);
217: continue;
218: }
219: break;
220: }
221:
222: if (sipStack == null)
223: return;
224:
225: if (tries >= SipManager.RETRY_OBJECT_DELETES)
226: throw new CommunicationsException(
227: "Failed to delete the sipProvider!");
228:
229: if (sipStack == null)
230: return;
231:
232: // Delete RI ListeningPoint
233: for (tries = 0; tries < SipManager.RETRY_OBJECT_DELETES; tries++) {
234: try {
235: sipStack.deleteListeningPoint(listeningPoint);
236: } catch (ObjectInUseException ex) {
237: // Log.debug("Retrying delete of riListeningPoint!");
238: SipManager.sleep(SipManager.RETRY_OBJECT_DELETES_AFTER);
239: continue;
240: }
241: break;
242: }
243:
244: if (sipStack != null) {
245:
246: for (Iterator it = sipStack.getSipProviders(); it.hasNext();) {
247: SipProvider element = (SipProvider) it.next();
248: try {
249: sipStack.deleteSipProvider(element);
250: } catch (Exception e) {
251: // Do nothing
252: }
253: }
254: }
255: if (tries >= SipManager.RETRY_OBJECT_DELETES)
256: throw new CommunicationsException(
257: "Failed to delete a listeningPoint!");
258:
259: listeningPoint = null;
260: addressFactory = null;
261: messageFactory = null;
262: headerFactory = null;
263: sipStack = null;
264:
265: registrarAddress = null;
266: viaHeaders = null;
267: contactHeader = null;
268: fromHeader = null;
269:
270: }
271:
272: /**
273: * Waits during _no_less_ than sleepFor milliseconds. Had to implement it on
274: * top of Thread.sleep() to guarantee minimum sleep time.
275: *
276: * @param sleepFor the number of miliseconds to wait
277: */
278: protected static void sleep(long sleepFor) {
279: long startTime = System.currentTimeMillis();
280: long haveBeenSleeping = 0;
281: while (haveBeenSleeping < sleepFor) {
282: try {
283: Thread.sleep(sleepFor - haveBeenSleeping);
284: } catch (InterruptedException ex) {
285: // we-ll have to wait again!
286: }
287: haveBeenSleeping = (System.currentTimeMillis() - startTime);
288: }
289: }
290:
291: /**
292: * @param uri the currentlyUsedURI to set.
293: */
294: public void setCurrentlyUsedURI(String uri) {
295: this .currentlyUsedURI = uri;
296: }
297:
298: public void register(String publicAddress) {
299: try {
300:
301: if (publicAddress == null
302: || publicAddress.trim().length() == 0) {
303: Log.debug("PUBLIC NOT FOUND!");
304: return; // maybe throw an exception?
305: }
306:
307: if (!publicAddress.trim().toLowerCase().startsWith("sip:")) {
308: publicAddress = "sip:" + publicAddress;
309: }
310:
311: this .currentlyUsedURI = publicAddress;
312: registerProcessing.register(registrarAddress,
313: registrarPort, registrarTransport,
314: registrationsExpiration);
315:
316: } catch (Exception e) {
317: Log.error("register", e);
318: }
319: }
320:
321: public void startRegisterProcess(String userName,
322: String authUserName, String password)
323: throws CommunicationsException {
324:
325: try {
326: checkIfStarted();
327:
328: // Obtain initial credentials
329:
330: String realm = SIPConfig.getAuthenticationRealm();
331: realm = realm == null ? "" : realm;
332:
333: // put the returned user name in the properties file
334: // so that it appears as a default one next time user is prompted
335: // for pass
336: SIPConfig.setUserName(userName);
337: SIPConfig.setAuthUserName(authUserName);
338:
339: UserCredentials initialCredentials = new UserCredentials();
340: initialCredentials.setUserName(userName);
341: initialCredentials.setAuthUserName(authUserName);
342: initialCredentials.setPassword(password.toCharArray());
343:
344: register(initialCredentials.getUserName() + "@" + realm);
345:
346: // at this point a simple register request has been sent and the
347: // global
348: // from header in SipManager has been set to a valid value by the
349: // RegisterProcesing
350: // class. Use it to extract the valid user name that needs to be
351: // cached by
352: // the security manager together with the user provided password.
353:
354: initialCredentials.setUserName(((SipURI) getFromHeader()
355: .getAddress().getURI()).getUser());
356:
357: // JOptionPane.showMessageDialog(null,( (SipURI)
358: // getFromHeader().getAddress().getURI()).getUser());
359:
360: cacheCredentials(realm, initialCredentials);
361:
362: } catch (Exception ee) {
363: Log.error("startRegisterProcess", ee);
364: }
365: }
366:
367: /**
368: * Causes the PresenceAgent object to notify all subscribers of our brand
369: * new offline status and the RegisterProcessing object to send a
370: * registration request with a 0 "expires" interval to the registrar defined
371: * in net.java.mais.sip.REGISTRAR_ADDRESS.
372: *
373: * @throws CommunicationsException if an exception is thrown by the underlying stack. The
374: * exception that caused this CommunicationsException may be
375: * extracted with CommunicationsException.getCause()
376: */
377: public void unregister() throws CommunicationsException {
378: try {
379: checkIfStarted();
380: registerProcessing.unregister();
381: fireUnregistered(registrarAddress == null ? ""
382: : registrarAddress);
383: } catch (Exception e) {
384: Log.error("unregister", e);
385: }
386: }
387:
388: private void registrationFailed(RegistrationEvent.Type type) {
389: try {
390: fireRegistrationFailed(registrarAddress == null ? ""
391: : registrarAddress, type);
392: } catch (Exception e) {
393: Log.error("unregister", e);
394: }
395: }
396:
397: /**
398: * Queries the RegisterProcessing object whether the application is
399: * registered with a registrar.
400: *
401: * @return true if the application is registered with a registrar.
402: */
403: public boolean isRegistered() {
404: return (registerProcessing != null && registerProcessing
405: .isRegistered());
406: }
407:
408: /**
409: * Determines whether the SipManager was started.
410: *
411: * @return true if the SipManager was started.
412: */
413: public boolean isStarted() {
414: return isStarted;
415: }
416:
417: /**
418: * Sends a NOT_IMPLEMENTED response through the specified transaction.
419: *
420: * @param serverTransaction the transaction to send the response through.
421: * @param request the request that is being answered.
422: */
423: void sendNotImplemented(ServerTransaction serverTransaction,
424: Request request) {
425: Response notImplemented;
426: try {
427: notImplemented = messageFactory.createResponse(
428: Response.NOT_IMPLEMENTED, request);
429: attachToTag(notImplemented, serverTransaction.getDialog());
430: } catch (ParseException ex) {
431: fireCommunicationsError(new CommunicationsException(
432: "Failed to create a NOT_IMPLEMENTED response to a "
433: + request.getMethod() + " request!", ex));
434: return;
435: }
436: try {
437: serverTransaction.sendResponse(notImplemented);
438: } catch (SipException ex) {
439: fireCommunicationsError(new CommunicationsException(
440: "Failed to create a NOT_IMPLEMENTED response to a "
441: + request.getMethod() + " request!", ex));
442: }
443: }
444:
445: public void fireCommunicationsError(Throwable throwable) {
446: }
447:
448: public FromHeader getFromHeader() throws CommunicationsException {
449: return this .getFromHeader(false);
450: }
451:
452: public FromHeader getFromHeader(boolean isNew)
453: throws CommunicationsException {
454: if (fromHeader != null && !isNew) {
455: return fromHeader;
456: }
457: try {
458: SipURI fromURI = (SipURI) addressFactory
459: .createURI(currentlyUsedURI);
460:
461: fromURI.setTransportParam(listeningPoint.getTransport());
462:
463: fromURI.setPort(listeningPoint.getPort());
464: Address fromAddress = addressFactory.createAddress(fromURI);
465: if (displayName != null && displayName.trim().length() > 0) {
466: fromAddress.setDisplayName(displayName);
467: } else {
468: fromAddress.setDisplayName(UserCredentials
469: .getUserDisplay());// UserCredentials.getUser());
470: // JOptionPane.showMessageDialog(null,currentlyUsedURI);
471: }
472: fromHeader = headerFactory.createFromHeader(fromAddress,
473: Integer.toString(hashCode()));
474:
475: } catch (ParseException ex) {
476: throw new CommunicationsException(
477: "A ParseException occurred while creating From Header!",
478: ex);
479: }
480: return fromHeader;
481: }
482:
483: /**
484: * Same as calling getContactHeader(true)
485: *
486: * @return the result of getContactHeader(true)
487: * @throws CommunicationsException if an exception is thrown while calling
488: * getContactHeader(false)
489: */
490: public ContactHeader getContactHeader()
491: throws CommunicationsException {
492: return getContactHeader(true);
493: }
494:
495: /**
496: * Same as calling getContactHeader(true).
497: *
498: * @return the result of calling getContactHeader(true).
499: * @throws CommunicationsException if an exception occurs while executing
500: * getContactHeader(true).
501: */
502: ContactHeader getRegistrationContactHeader()
503: throws CommunicationsException {
504: return getContactHeader(true);
505: }
506:
507: /**
508: * Initialises SipManager's contactHeader field in accordance with
509: * javax.sip.IP_ADDRESS net.java.mais.sip.DISPLAY_NAME
510: * net.java.mais.sip.TRANSPORT net.java.mais.sip.PREFERRED_LOCAL_PORT and
511: * returns a reference to it.
512: *
513: * @param useLocalHostAddress specifies whether the SipURI in the contact header should
514: * contain the value of javax.sip.IP_ADDRESS (true) or that of
515: * net.java.mais.sip.PUBLIC_ADDRESS (false).
516: * @return a reference to SipManager's contactHeader field.
517: * @throws CommunicationsException if a ParseException occurs while initially composing the
518: * FromHeader.
519: */
520: public ContactHeader getContactHeader(boolean useLocalHostAddress)
521: throws CommunicationsException {
522: if (contactHeader != null) {
523: return contactHeader;
524: }
525: try {
526:
527: SipURI contactURI;
528:
529: if (useLocalHostAddress) {
530: contactURI = addressFactory.createSipURI(null,
531: UserCredentials.getUserDisplay()
532: + "@"
533: + publicIpAddress.getAddress()
534: .getHostAddress());
535: } else {
536: contactURI = (SipURI) addressFactory
537: .createURI(currentlyUsedURI);
538: }
539:
540: contactURI.setPort(publicIpAddress.getPort());
541: Address contactAddress = addressFactory
542: .createAddress(contactURI);
543: if (displayName != null && displayName.trim().length() > 0) {
544: contactAddress.setDisplayName(displayName);
545: }
546: contactHeader = headerFactory
547: .createContactHeader(contactAddress);
548:
549: } catch (ParseException ex) {
550: throw new CommunicationsException(
551: "A ParseException occurred while creating From Header!",
552: ex);
553: }
554: return contactHeader;
555:
556: }
557:
558: /**
559: * Initializes (if null) and returns an ArrayList with a single ViaHeader
560: * containing localhost's address. This ArrayList may be used when sending
561: * requests.
562: *
563: * @return ViaHeader-s list to be used when sending requests.
564: * @throws CommunicationsException if a ParseException is to occur while initializing the array
565: * list.
566: */
567: public ArrayList getLocalViaHeaders()
568: throws CommunicationsException {
569: if (viaHeaders != null) {
570: return viaHeaders;
571: }
572: ListeningPoint lp = sipProvider.getListeningPoint();
573: viaHeaders = new ArrayList<ViaHeader>();
574: try {
575:
576: ViaHeader viaHeader = headerFactory.createViaHeader(
577: SIPConfig.getIPAddress(), lp.getPort(), lp
578: .getTransport(), null);
579:
580: viaHeader.setParameter("rport", null);
581: viaHeaders.add(viaHeader);
582:
583: return viaHeaders;
584: } catch (ParseException ex) {
585: throw new CommunicationsException(
586: "A ParseException occurred while creating Via Headers!");
587: } catch (InvalidArgumentException ex) {
588: throw new CommunicationsException(
589: "Unable to create a via header for port "
590: + lp.getPort(), ex);
591: }
592: }
593:
594: /**
595: * Initializes and returns SipManager's maxForwardsHeader field using the
596: * value specified by MAX_FORWARDS.
597: *
598: * @return an instance of a MaxForwardsHeader that can be used when sending
599: * requests
600: * @throws CommunicationsException if MAX_FORWARDS has an invalid value.
601: */
602: public MaxForwardsHeader getMaxForwardsHeader()
603: throws CommunicationsException {
604: if (maxForwardsHeader != null) {
605: return maxForwardsHeader;
606: }
607: try {
608: maxForwardsHeader = headerFactory
609: .createMaxForwardsHeader(SipManager.MAX_FORWARDS);
610: return maxForwardsHeader;
611: } catch (InvalidArgumentException ex) {
612: throw new CommunicationsException(
613: "A problem occurred while creating MaxForwardsHeader",
614: ex);
615: }
616: }
617:
618: /**
619: * Returns the user used to create the From Header URI.
620: *
621: * @return the user used to create the From Header URI.
622: */
623: public String getLocalUser() {
624: try {
625:
626: return ((SipURI) getFromHeader().getAddress().getURI())
627: .getUser();
628: } catch (CommunicationsException ex) {
629: return "";
630: }
631: }
632:
633: /**
634: * Generates a ToTag (the containingDialog's hashCode())and attaches it to
635: * response's ToHeader.
636: *
637: * @param response the response that is to get the ToTag.
638: * @param containingDialog the Dialog instance that is to extract a unique Tag value
639: * (containingDialog.hashCode())
640: */
641: public void attachToTag(Response response, Dialog containingDialog) {
642: ToHeader to = (ToHeader) response.getHeader(ToHeader.NAME);
643: if (to == null) {
644: fireCommunicationsError(new CommunicationsException(
645: "No TO header found in, attaching a to tag is therefore impossible"));
646: }
647: try {
648: if (to.getTag() == null || to.getTag().trim().length() == 0) {
649: int toTag = containingDialog != null ? containingDialog
650: .hashCode() : (int) System.currentTimeMillis();
651:
652: to.setTag(Integer.toString(toTag));
653: }
654: } catch (ParseException ex) {
655: fireCommunicationsError(new CommunicationsException(
656: "Failed to attach a TO tag to an outgoing response"));
657: }
658: }
659:
660: protected void initProperties() {
661: try {
662:
663: stackAddress = getLocalHostAddress();
664: // Add the host address to the properties that will pass the stack
665: SIPConfig.setIPAddress(stackAddress);
666: SIPConfig.setSystemProperties();
667:
668: // ensure IPv6 address compliance
669: if (stackAddress.indexOf(':') != stackAddress
670: .lastIndexOf(':')
671: && stackAddress.charAt(0) != '[') {
672: stackAddress = '[' + stackAddress.trim() + ']';
673: }
674: stackName = SIPConfig.getStackName();
675: if (stackName == null) {
676: stackName = "SIPark@" + Integer.toString(hashCode());
677: }
678:
679: currentlyUsedURI = SIPConfig.getPublicAddress();
680: if (currentlyUsedURI == null) {
681: currentlyUsedURI = SIPConfig.getUserName() + "@"
682: + stackAddress;
683: }
684: if (!currentlyUsedURI.trim().toLowerCase().startsWith(
685: "sip:")) {
686: currentlyUsedURI = "sip:" + currentlyUsedURI.trim();
687: }
688:
689: registrarAddress = SIPConfig.getRegistrarAddress();
690: try {
691: registrarPort = SIPConfig.getRegistrarPort();
692: } catch (NumberFormatException ex) {
693: registrarPort = 5060;
694: }
695: registrarTransport = SIPConfig.getRegistrarTransport();
696:
697: if (registrarTransport == null) {
698: registrarTransport = SipManager.DEFAULT_TRANSPORT;
699: }
700: try {
701: registrationsExpiration = SIPConfig
702: .getRegistrationExpiration();
703: } catch (NumberFormatException ex) {
704: registrationsExpiration = 3600;
705: }
706: sipStackPath = SIPConfig.getStackPath();
707: if (sipStackPath == null) {
708: sipStackPath = "gov.nist";
709: }
710:
711: transport = SIPConfig.getTransport();
712:
713: if (transport.equals("")) {
714: transport = SipManager.DEFAULT_TRANSPORT;
715: }
716: try {
717: localPort = SIPConfig.getLocalPort();
718: } catch (NumberFormatException exc) {
719: localPort = 5060;
720: }
721: displayName = SIPConfig.getDisplayName();
722:
723: } catch (Exception e) {
724: Log.error(e);
725: }
726: }
727:
728: /**
729: * Adds the specified credentials to the security manager's credentials
730: * cache so that they get tried next time they're needed.
731: *
732: * @param realm the realm these credentials should apply for.
733: * @param credentials a set of credentials (username and pass)
734: */
735: public void cacheCredentials(String realm,
736: UserCredentials credentials) {
737: sipSecurityManager.cacheCredentials(realm, credentials);
738: }
739:
740: /**
741: * Adds a CommunicationsListener to SipManager.
742: *
743: * @param listener The CommunicationsListener to be added.
744: */
745: public void addCommunicationsListener(
746: CommunicationsListener listener) {
747: try {
748: listeners.add(listener);
749: } catch (Exception e) {
750: Log.error("addCommunicationsListener", e);
751: }
752: }
753:
754: // ------------ registerred
755: void fireRegistered(String address) {
756: RegistrationEvent evt = new RegistrationEvent(address);
757: for (int i = listeners.size() - 1; i >= 0; i--) {
758: (listeners.get(i)).registered(evt);
759: }
760: } // call received
761:
762: // ------------ registering
763: void fireRegistering(String address) {
764: RegistrationEvent evt = new RegistrationEvent(address);
765: for (int i = listeners.size() - 1; i >= 0; i--) {
766: (listeners.get(i)).registering(evt);
767: }
768: } // call received
769:
770: // ------------ unregistered
771: public void fireUnregistered(String address) {
772: RegistrationEvent evt = new RegistrationEvent(address);
773: for (int i = listeners.size() - 1; i >= 0; i--) {
774: (listeners.get(i)).unregistered(evt);
775: }
776: }
777:
778: void fireRegistrationFailed(String address,
779: RegistrationEvent.Type type) {
780: RegistrationEvent evt = new RegistrationEvent(address, type);
781: for (int i = listeners.size() - 1; i >= 0; i--) {
782: (listeners.get(i)).registrationFailed(evt);
783: }
784: }
785:
786: void fireUnregistering(String address) {
787: RegistrationEvent evt = new RegistrationEvent(address);
788: for (int i = listeners.size() - 1; i >= 0; i--) {
789: (listeners.get(i)).unregistering(evt);
790: }
791: }
792:
793: public void processRequest(RequestEvent requestEvent) {
794: }
795:
796: // -------------------- PROCESS RESPONSE
797: public void processResponse(ResponseEvent responseReceivedEvent) {
798: Log.debug("RESPONSE ["
799: + responseReceivedEvent.getResponse().getStatusCode()
800: + "]");
801:
802: ClientTransaction clientTransaction = responseReceivedEvent
803: .getClientTransaction();
804: if (clientTransaction == null) {
805: return;
806: }
807: Response response = responseReceivedEvent.getResponse();
808: String method = ((CSeqHeader) response
809: .getHeader(CSeqHeader.NAME)).getMethod();
810:
811: // OK
812: if (response.getStatusCode() == Response.OK) {
813: // REGISTER
814: if (method.equals(Request.REGISTER)) {
815: registerProcessing.processOK(clientTransaction,
816: response);
817: }
818: }
819: // NOT_FOUND
820: else if (response.getStatusCode() == Response.NOT_FOUND) {
821: if (method.equals(Request.REGISTER)) {
822: try {
823: unregister();
824: registrationFailed(RegistrationEvent.Type.NotFound);
825: } catch (CommunicationsException e) {
826: Log.error("NOT FOUND", e);
827: }
828: Log.debug("REGISTER NOT FOUND");
829: }
830: }
831: // NOT_IMPLEMENTED
832: else if (response.getStatusCode() == Response.NOT_IMPLEMENTED) {
833: if (method.equals(Request.REGISTER)) {
834: // Fixed typo issues - Reported by pizarro
835: registerProcessing.processNotImplemented(
836: clientTransaction, response);
837: }
838: }
839: // REQUEST_TERMINATED
840: // 401 UNAUTHORIZED
841: else if (response.getStatusCode() == Response.UNAUTHORIZED
842: || response.getStatusCode() == Response.PROXY_AUTHENTICATION_REQUIRED) {
843: if (method.equals(Request.REGISTER)) {
844: CSeqHeader cseq = (CSeqHeader) response
845: .getHeader(CSeqHeader.NAME);
846: if (cseq.getSequenceNumber() < 2)
847: registerProcessing.processAuthenticationChallenge(
848: clientTransaction, response);
849: else
850: registrationFailed(RegistrationEvent.Type.WrongPass);
851: }
852: }
853: // 403 Wrong Authorization user for this account
854: else if (response.getStatusCode() == Response.FORBIDDEN) {
855: registrationFailed(RegistrationEvent.Type.Forbidden);
856: }
857: } // process response
858:
859: public void processTimeout(TimeoutEvent timeoutEvent) {
860:
861: }
862:
863: String getLocalHostAddress() {
864: return localAddress.getHostAddress();
865: }
866:
867: protected void checkIfStarted() throws CommunicationsException {
868: if (!isStarted) {
869:
870: throw new CommunicationsException(
871: "The underlying SIP Stack had not been"
872: + "properly initialised! Impossible to continue");
873: }
874: }
875:
876: public static void main(String args[]) {
877:
878: SIPConfig.setRegistrarAddress("apollo");
879: SIPConfig.setAuthenticationRealm("apollo");
880: SIPConfig.setDefaultDomain("apollo");
881:
882: InetAddress address = null;
883: try {
884: address = InetAddress.getLocalHost();
885: } catch (UnknownHostException e) {
886: e.printStackTrace();
887: }
888:
889: SipManager sipManager = new SipManager(address);
890:
891: try {
892: sipManager.start();
893: } catch (CommunicationsException e) {
894: e.printStackTrace();
895: }
896:
897: try {
898: sipManager.startRegisterProcess("7512", "7512", "7512");
899: } catch (CommunicationsException e) {
900: e.printStackTrace();
901: }
902:
903: try {
904: sipManager.unregister();
905: } catch (CommunicationsException e) {
906: e.printStackTrace();
907: }
908:
909: }
910:
911: }
|