1600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/*
2600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Conditions Of Use
3600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
4600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This software was developed by employees of the National Institute of
5600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Standards and Technology (NIST), an agency of the Federal Government.
6600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Pursuant to title 15 Untied States Code Section 105, works of NIST
7600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * employees are not subject to copyright protection in the United States
8600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * and are considered to be in the public domain.  As a result, a formal
9600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * license is not needed to use the software.
10600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
11600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This software is provided by NIST as a service and is expressly
12600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * provided "AS IS."  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
13600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
14600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
15600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * AND DATA ACCURACY.  NIST does not warrant or make any representations
16600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * regarding the use of the software or the results thereof, including but
17600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * not limited to the correctness, accuracy, reliability or usefulness of
18600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * the software.
19600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
20600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Permission to use this software is contingent upon your acceptance
21600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * of the terms of this agreement
22600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
23600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * .
24600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
25600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */
26600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/*****************************************************************************
27600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *   Product of NIST/ITL Advanced Networking Technologies Division (ANTD).    *
28600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *****************************************************************************/
29600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
30600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangpackage gov.nist.javax.sip.stack;
31600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
32600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.InternalErrorHandler;
33600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.ServerLogger;
34600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.StackLogger;
35600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.ThreadAuditor;
36600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.SIPConstants;
37600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.CSeq;
38600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.CallID;
39600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.From;
40600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.RequestLine;
41600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.StatusLine;
42600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.To;
43600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.Via;
44600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.ViaList;
45600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.message.SIPMessage;
46600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.message.SIPRequest;
47600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.message.SIPResponse;
48600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.parser.ParseExceptionListener;
49600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.parser.StringMsgParser;
50600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
51600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.io.IOException;
52600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.io.OutputStream;
53600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.net.DatagramPacket;
54600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.net.DatagramSocket;
55600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.net.InetAddress;
56600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.net.Socket;
57600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.text.ParseException;
58600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.HashSet;
59600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.Hashtable;
60600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.TimerTask;
61600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
62600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.address.Hop;
63600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
64600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/*
65600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Kim Kirby (Keyvoice) suggested that duplicate checking should be added to the
66600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * stack (later removed). Lamine Brahimi suggested a single threaded behavior
67600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * flag be added to this. Niklas Uhrberg suggested that thread pooling support
68600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * be added to this for performance and resource management. Peter Parnes found
69600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * a bug with this code that was sending it into an infinite loop when a bad
70600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * incoming message was parsed. Bug fix by viswashanti.kadiyala@antepo.com.
71600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Hagai Sela addded fixes for NAT traversal. Jeroen van Bemmel fixed up for
72600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * buggy clients (such as windows messenger) and added code to return
73600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * BAD_REQUEST. David Alique fixed an address recording bug. Jeroen van Bemmel
74600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * fixed a performance issue where the stack was doing DNS lookups (potentially
75600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * unnecessary). Ricardo Bora (Natural Convergence ) added code that prevents
76600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * the stack from exitting when an exception is encountered.
77600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
78600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */
79600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
80600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/**
81600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This is the UDP Message handler that gets created when a UDP message needs to
82600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * be processed. The message is processed by creating a String Message parser
83600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * and invoking it on the message read from the UDP socket. The parsed structure
84600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * is handed off via a SIP stack request for further processing. This stack
85600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * structure isolates the message handling logic from the mechanics of sending
86600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * and recieving messages (which could be either udp or tcp.
87600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
88600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
89600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @author M. Ranganathan <br/>
90600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
91600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
92600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
93600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @version 1.2 $Revision: 1.66 $ $Date: 2010/01/14 05:15:49 $
94600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */
95600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangpublic class UDPMessageChannel extends MessageChannel implements
96600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        ParseExceptionListener, Runnable, RawMessageChannel {
97600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
98600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
99600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
100600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * SIP Stack structure for this channel.
101600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
102600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected SIPTransactionStack sipStack;
103600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
104600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
105600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * The parser we are using for messages received from this channel.
106600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
107600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected StringMsgParser myParser;
108600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
109600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
110600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Where we got the stuff from
111600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
112600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private InetAddress peerAddress;
113600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
114600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private String myAddress;
115600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
116600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private int peerPacketSourcePort;
117600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
118600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private InetAddress peerPacketSourceAddress;
119600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
120600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
121600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Reciever port -- port of the destination.
122600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
123600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private int peerPort;
124600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
125600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
126600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Protocol to use when talking to receiver (i.e. when sending replies).
127600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
128600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private String peerProtocol;
129600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
130600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected int myPort;
131600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
132600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private DatagramPacket incomingPacket;
133600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
134600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private long receptionTime;
135600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
136600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
137600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * A table that keeps track of when the last pingback was sent to a given remote IP address
138600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * and port. This is for NAT compensation. This stays in the table for 1 seconds and prevents
139600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * infinite loop. If a second pingback happens in that period of time, it will be dropped.
140600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
141600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private Hashtable<String,PingBackTimerTask> pingBackRecord = new Hashtable<String,PingBackTimerTask>();
142600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
143600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    class PingBackTimerTask extends TimerTask {
144600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String ipAddress;
145600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        int port;
146600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
147600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        public PingBackTimerTask(String ipAddress, int port) {
148600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.ipAddress = ipAddress;
149600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.port = port;
150600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            pingBackRecord.put(ipAddress + ":" + port, this);
151600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
152600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        @Override
153600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        public void run() {
154600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang           pingBackRecord.remove(ipAddress + ":" + port);
155600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
156600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        @Override
157600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        public int hashCode() {
158600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return (ipAddress + ":" + port).hashCode();
159600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
160600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
161600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
162600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
163600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Constructor - takes a datagram packet and a stack structure Extracts the
164600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * address of the other from the datagram packet and stashes away the
165600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * pointer to the passed stack structure.
166600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
167600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param stack
168600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            is the shared SIPStack structure
169600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param messageProcessor
170600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            is the creating message processor.
171600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
172600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected UDPMessageChannel(SIPTransactionStack stack,
173600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            UDPMessageProcessor messageProcessor) {
174600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        super.messageProcessor = messageProcessor;
175600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.sipStack = stack;
176600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
177600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        Thread mythread = new Thread(this);
178600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
179600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.myAddress = messageProcessor.getIpAddress().getHostAddress();
180600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.myPort = messageProcessor.getPort();
181600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
182600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        mythread.setName("UDPMessageChannelThread");
183600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        mythread.setDaemon(true);
184600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        mythread.start();
185600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
186600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
187600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
188600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
189600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Constructor. We create one of these in order to process an incoming
190600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * message.
191600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
192600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param stack
193600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            is the SIP sipStack.
194600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param messageProcessor
195600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            is the creating message processor.
196600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param packet
197600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            is the incoming datagram packet.
198600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
199600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected UDPMessageChannel(SIPTransactionStack stack,
200600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            UDPMessageProcessor messageProcessor, DatagramPacket packet) {
201600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
202600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.incomingPacket = packet;
203600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        super.messageProcessor = messageProcessor;
204600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.sipStack = stack;
205600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
206600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.myAddress = messageProcessor.getIpAddress().getHostAddress();
207600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.myPort = messageProcessor.getPort();
208600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        Thread mythread = new Thread(this);
209600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        mythread.setDaemon(true);
21005ea84203978f79842df1d0d17ebaf30073ef1b1Chung-yih Wang        mythread.setName("UDPMessageChannelThread");
211600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
212600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        mythread.start();
213600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
214600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
215600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
216600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
217600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Constructor. We create one of these when we send out a message.
218600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
219600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param targetAddr
220600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            INET address of the place where we want to send messages.
221600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param port
222600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            target port (where we want to send the message).
223600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param sipStack
224600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            our SIP Stack.
225600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
226600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected UDPMessageChannel(InetAddress targetAddr, int port,
227600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            SIPTransactionStack sipStack, UDPMessageProcessor messageProcessor) {
228600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        peerAddress = targetAddr;
229600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        peerPort = port;
230600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        peerProtocol = "UDP";
231600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        super.messageProcessor = messageProcessor;
232600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.myAddress = messageProcessor.getIpAddress().getHostAddress();
233600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.myPort = messageProcessor.getPort();
234600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.sipStack = sipStack;
235600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipStack.isLoggingEnabled()) {
236600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.sipStack.getStackLogger().logDebug("Creating message channel "
237600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    + targetAddr.getHostAddress() + "/" + port);
238600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
239600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
240600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
241600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
242600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Run method specified by runnnable.
243600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
244600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void run() {
245600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Assume no thread pooling (bug fix by spierhj)
246600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        ThreadAuditor.ThreadHandle threadHandle = null;
247600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
248600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        while (true) {
249600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Create a new string message parser to parse the list of messages.
250600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (myParser == null) {
251600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                myParser = new StringMsgParser();
252600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                myParser.setParseExceptionListener(this);
253600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
254600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // messages that we write out to him.
255600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            DatagramPacket packet;
256600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
257600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipStack.threadPoolSize != -1) {
258600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                synchronized (((UDPMessageProcessor) messageProcessor).messageQueue) {
259600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    while (((UDPMessageProcessor) messageProcessor).messageQueue
260600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            .isEmpty()) {
261600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // Check to see if we need to exit.
262600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        if (!((UDPMessageProcessor) messageProcessor).isRunning)
263600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            return;
264600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        try {
265600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            // We're part of a thread pool. Ask the auditor to
266600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            // monitor this thread.
267600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            if (threadHandle == null) {
268600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                threadHandle = sipStack.getThreadAuditor()
269600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                        .addCurrentThread();
270600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            }
271600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
272600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            // Send a heartbeat to the thread auditor
273600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            threadHandle.ping();
274600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
275600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            // Wait for packets
276600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            // Note: getPingInterval returns 0 (infinite) if the
277600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            // thread auditor is disabled.
278600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            ((UDPMessageProcessor) messageProcessor).messageQueue
279600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    .wait(threadHandle
280600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                            .getPingIntervalInMillisecs());
281600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        } catch (InterruptedException ex) {
282600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            if (!((UDPMessageProcessor) messageProcessor).isRunning)
283600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                return;
284600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        }
285600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
286600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    packet = (DatagramPacket) ((UDPMessageProcessor) messageProcessor).messageQueue
287600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            .removeFirst();
288600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
289600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
290600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.incomingPacket = packet;
291600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else {
292600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                packet = this.incomingPacket;
293600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
294600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
295600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Process the packet. Catch and log any exception we may throw.
296600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
297600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                processIncomingDataPacket(packet);
298600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (Exception e) {
299600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
300600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sipStack.getStackLogger().logError(
301600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        "Error while processing incoming UDP packet", e);
302600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
303600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
304600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipStack.threadPoolSize == -1) {
305600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return;
306600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
307600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
308600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
309600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
310600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
311600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Process an incoming datagram
312600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
313600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param packet
314600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            is the incoming datagram packet.
315600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
316600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private void processIncomingDataPacket(DatagramPacket packet)
317600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throws Exception {
318600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.peerAddress = packet.getAddress();
319600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        int packetLength = packet.getLength();
320600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Read bytes and put it in a eueue.
321600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        byte[] bytes = packet.getData();
322600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        byte[] msgBytes = new byte[packetLength];
323600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        System.arraycopy(bytes, 0, msgBytes, 0, packetLength);
324600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
325600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Do debug logging.
326600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipStack.isLoggingEnabled()) {
327600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.sipStack.getStackLogger()
328600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    .logDebug("UDPMessageChannel: processIncomingDataPacket : peerAddress = "
329600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            + peerAddress.getHostAddress() + "/"
330600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            + packet.getPort() + " Length = " + packetLength);
331600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
332600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
333600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
334600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPMessage sipMessage = null;
335600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
336600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.receptionTime = System.currentTimeMillis();
337600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sipMessage = myParser.parseSIPMessage(msgBytes);
338600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            myParser = null;
339600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } catch (ParseException ex) {
340600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            myParser = null; // let go of the parser reference.
341600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipStack.isLoggingEnabled()) {
342600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.sipStack.getStackLogger().logDebug("Rejecting message !  "
343600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + new String(msgBytes));
344600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.sipStack.getStackLogger().logDebug("error message "
345600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + ex.getMessage());
346600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.sipStack.getStackLogger().logException(ex);
347600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
348600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
349600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
350600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // JvB: send a 400 response for requests (except ACK)
351600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Currently only UDP, @todo also other transports
352600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            String msgString = new String(msgBytes, 0, packetLength);
353600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (!msgString.startsWith("SIP/") && !msgString.startsWith("ACK ")) {
354600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
355600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                String badReqRes = createBadReqRes(msgString, ex);
356600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (badReqRes != null) {
357600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (sipStack.isLoggingEnabled()) {
358600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        sipStack.getStackLogger().logDebug(
359600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                "Sending automatic 400 Bad Request:");
360600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        sipStack.getStackLogger().logDebug(badReqRes);
361600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
362600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    try {
363600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        this.sendMessage(badReqRes.getBytes(), peerAddress,
364600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                packet.getPort(), "UDP", false);
365600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    } catch (IOException e) {
366600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        this.sipStack.getStackLogger().logException(e);
367600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
368600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else {
369600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (sipStack.isLoggingEnabled()) {
370600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        sipStack
371600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                .getStackLogger()
372600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                .logDebug(
373600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                        "Could not formulate automatic 400 Bad Request");
374600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
375600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
376600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
377600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
378600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return;
379600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
380600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // No parse exception but null message - reject it and
381600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // march on (or return).
382600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // exit this message processor if the message did not parse.
383600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
384600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipMessage == null) {
385600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipStack.isLoggingEnabled()) {
386600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.sipStack.getStackLogger().logDebug("Rejecting message !  + Null message parsed.");
387600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
388600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (pingBackRecord.get(packet.getAddress().getHostAddress() + ":" + packet.getPort()) == null ) {
389600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                byte[] retval = "\r\n\r\n".getBytes();
390600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                DatagramPacket keepalive = new DatagramPacket(retval,0,retval.length,packet.getAddress(),packet.getPort());
391600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                ((UDPMessageProcessor)this.messageProcessor).sock.send(keepalive);
392600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.sipStack.getTimer().schedule(new PingBackTimerTask(packet.getAddress().getHostAddress(),
393600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            packet.getPort()), 1000);
394600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
395600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return;
396600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
397600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        ViaList viaList = sipMessage.getViaHeaders();
398600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Check for the required headers.
399600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipMessage.getFrom() == null || sipMessage.getTo() == null
400600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                || sipMessage.getCallId() == null
401600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                || sipMessage.getCSeq() == null
402600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                || sipMessage.getViaHeaders() == null) {
403600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            String badmsg = new String(msgBytes);
404600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipStack.isLoggingEnabled()) {
405600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.sipStack.getStackLogger().logError("bad message " + badmsg);
406600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.sipStack.getStackLogger().logError(">>> Dropped Bad Msg "
407600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "From = " + sipMessage.getFrom() + "To = "
408600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + sipMessage.getTo() + "CallId = "
409600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + sipMessage.getCallId() + "CSeq = "
410600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + sipMessage.getCSeq() + "Via = "
411600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + sipMessage.getViaHeaders());
412600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
413600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return;
414600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
415600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // For a request first via header tells where the message
416600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // is coming from.
417600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // For response, just get the port from the packet.
418600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipMessage instanceof SIPRequest) {
419600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            Via v = (Via) viaList.getFirst();
420600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            Hop hop = sipStack.addressResolver.resolveAddress(v.getHop());
421600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.peerPort = hop.getPort();
422600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.peerProtocol = v.getTransport();
423600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
424600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.peerPacketSourceAddress = packet.getAddress();
425600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.peerPacketSourcePort = packet.getPort();
426600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
427600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.peerAddress = packet.getAddress();
428600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Check to see if the received parameter matches
429600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // the peer address and tag it appropriately.
430600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
431600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
432600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                boolean hasRPort = v.hasParameter(Via.RPORT);
433600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (hasRPort
434600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        || !hop.getHost().equals(
435600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                this.peerAddress.getHostAddress())) {
436600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    v.setParameter(Via.RECEIVED, this.peerAddress
437600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            .getHostAddress());
438600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
439600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
440600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (hasRPort) {
441600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    v.setParameter(Via.RPORT, Integer
442600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            .toString(this.peerPacketSourcePort));
443600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
444600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (java.text.ParseException ex1) {
445600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                InternalErrorHandler.handleException(ex1);
446600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
447600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
448600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
449600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
450600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.peerPacketSourceAddress = packet.getAddress();
451600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.peerPacketSourcePort = packet.getPort();
452600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.peerAddress = packet.getAddress();
453600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.peerPort = packet.getPort();
454600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.peerProtocol = ((Via) viaList.getFirst()).getTransport();
455600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
456600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
457600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.processMessage(sipMessage);
458600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
459600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
460600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
461600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
462600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Actually proces the parsed message.
463600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
464600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param sipMessage
465600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
466600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void processMessage(SIPMessage sipMessage) {
467600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
468600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipMessage instanceof SIPRequest) {
469600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            SIPRequest sipRequest = (SIPRequest) sipMessage;
470600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
471600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // This is a request - process it.
472600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // So far so good -- we will commit this message if
473600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // all processing is OK.
474600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES)) {
475600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
476600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.sipStack.serverLogger.logMessage(sipMessage, this
477600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        .getPeerHostPort().toString(), this.getHost() + ":"
478600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + this.myPort, false, receptionTime);
479600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
480600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
481600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            ServerRequestInterface sipServerRequest = sipStack
482600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    .newSIPServerRequest(sipRequest, this);
483600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Drop it if there is no request returned
484600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipServerRequest == null) {
485600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (sipStack.isLoggingEnabled()) {
486600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.sipStack.getStackLogger()
487600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            .logWarning("Null request interface returned -- dropping request");
488600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
489600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
490600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
491600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return;
492600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
493600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipStack.isLoggingEnabled())
494600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.sipStack.getStackLogger().logDebug("About to process "
495600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + sipRequest.getFirstLine() + "/" + sipServerRequest);
496600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
497600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sipServerRequest.processRequest(sipRequest, this);
498600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } finally {
499600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (sipServerRequest instanceof SIPTransaction) {
500600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    SIPServerTransaction sipServerTx = (SIPServerTransaction) sipServerRequest;
501600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (!sipServerTx.passToListener()) {
502600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        ((SIPTransaction) sipServerRequest).releaseSem();
503600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
504600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
505600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
506600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipStack.isLoggingEnabled())
507600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.sipStack.getStackLogger().logDebug("Done processing "
508600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + sipRequest.getFirstLine() + "/" + sipServerRequest);
509600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
510600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // So far so good -- we will commit this message if
511600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // all processing is OK.
512600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
513600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
514600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Handle a SIP Reply message.
515600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            SIPResponse sipResponse = (SIPResponse) sipMessage;
516600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
517600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sipResponse.checkHeaders();
518600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (ParseException ex) {
519600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (sipStack.isLoggingEnabled())
520600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipStack.getStackLogger()
521600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            .logError("Dropping Badly formatted response message >>> "
522600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    + sipResponse);
523600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return;
524600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
525600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            ServerResponseInterface sipServerResponse = sipStack
526600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    .newSIPServerResponse(sipResponse, this);
527600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipServerResponse != null) {
528600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                try {
529600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (sipServerResponse instanceof SIPClientTransaction
530600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            && !((SIPClientTransaction) sipServerResponse)
531600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    .checkFromTag(sipResponse)) {
532600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        if (sipStack.isLoggingEnabled())
533600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            sipStack.getStackLogger()
534600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    .logError("Dropping response message with invalid tag >>> "
535600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                            + sipResponse);
536600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        return;
537600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
538600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
539600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipServerResponse.processResponse(sipResponse, this);
540600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } finally {
541600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (sipServerResponse instanceof SIPTransaction
542600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            && !((SIPTransaction) sipServerResponse)
543600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    .passToListener())
544600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        ((SIPTransaction) sipServerResponse).releaseSem();
545600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
546600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
547600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Normal processing of message.
548600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else {
549600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (sipStack.isLoggingEnabled()) {
550600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.sipStack.getStackLogger().logDebug("null sipServerResponse!");
551600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
552600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
553600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
554600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
555600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
556600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
557600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
558600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * JvB: added method to check for known buggy clients (Windows Messenger) to
559600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * fix the port to which responses are sent
560600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
561600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * checks for User-Agent: RTC/1.3.5470 (Messenger 5.1.0701)
562600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
563600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * JvB 22/7/2006 better to take this out for the moment, it is only a
564600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * problem in rare cases (unregister)
565600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
566600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * private final boolean isBuggyClient( SIPRequest r ) { UserAgent uah =
567600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * (UserAgent) r.getHeader( UserAgent.NAME ); if (uah!=null) {
568600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * java.util.ListIterator i = uah.getProduct(); if (i.hasNext()) { String p =
569600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * (String) uah.getProduct().next(); return p.startsWith( "RTC" ); } }
570600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * return false; }
571600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
572600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
573600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
574600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Implementation of the ParseExceptionListener interface.
575600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
576600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param ex
577600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            Exception that is given to us by the parser.
578600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @throws ParseException
579600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *             If we choose to reject the header or message.
580600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
581600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void handleException(ParseException ex, SIPMessage sipMessage,
582600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            Class hdrClass, String header, String message)
583600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throws ParseException {
584600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipStack.isLoggingEnabled())
585600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.sipStack.getStackLogger().logException(ex);
586600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Log the bad message for later reference.
587600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if ((hdrClass != null)
588600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                && (hdrClass.equals(From.class) || hdrClass.equals(To.class)
589600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        || hdrClass.equals(CSeq.class)
590600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        || hdrClass.equals(Via.class)
591600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        || hdrClass.equals(CallID.class)
592600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        || hdrClass.equals(RequestLine.class) || hdrClass
593600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        .equals(StatusLine.class))) {
594600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        	if (sipStack.isLoggingEnabled()) {
595600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        		sipStack.getStackLogger().logError("BAD MESSAGE!");
596600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            	sipStack.getStackLogger().logError(message);
597600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        	}
598600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw ex;
599600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
600600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sipMessage.addUnparsed(header);
601600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
602600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
603600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
604600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
605600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Return a reply from a pre-constructed reply. This sends the message back
606600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * to the entity who caused us to create this channel in the first place.
607600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
608600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param sipMessage
609600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            Message string to send.
610600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @throws IOException
611600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *             If there is a problem with sending the message.
612600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
613600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void sendMessage(SIPMessage sipMessage) throws IOException {
614600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipStack.isLoggingEnabled() && this.sipStack.isLogStackTraceOnMessageSend()) {
615600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if ( sipMessage instanceof SIPRequest &&
616600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    ((SIPRequest)sipMessage).getRequestLine() != null) {
617600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                /*
618600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                 * We dont want to log empty trace messages.
619600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                 */
620600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.sipStack.getStackLogger().logStackTrace(StackLogger.TRACE_INFO);
621600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else {
622600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.sipStack.getStackLogger().logStackTrace(StackLogger.TRACE_INFO);
623600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
624600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
625600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
626600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Test and see where we are going to send the messsage. If the message
627600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // is sent back to oursleves, just
628600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // shortcircuit processing.
629600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        long time = System.currentTimeMillis();
630600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
631600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            for (MessageProcessor messageProcessor : sipStack
632600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    .getMessageProcessors()) {
633600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (messageProcessor.getIpAddress().equals(this.peerAddress)
634600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        && messageProcessor.getPort() == this.peerPort
635600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        && messageProcessor.getTransport().equals(
636600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                this.peerProtocol)) {
637600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    MessageChannel messageChannel = messageProcessor
638600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            .createMessageChannel(this.peerAddress,
639600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    this.peerPort);
640600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (messageChannel instanceof RawMessageChannel) {
641600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        ((RawMessageChannel) messageChannel)
642600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                .processMessage(sipMessage);
643600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        if (sipStack.isLoggingEnabled())
644600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        	sipStack.getStackLogger().logDebug("Self routing message");
645600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        return;
646600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
647600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
648600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
649600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
650600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
651600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            byte[] msg = sipMessage.encodeAsBytes( this.getTransport() );
652600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
653600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sendMessage(msg, peerAddress, peerPort, peerProtocol,
654600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipMessage instanceof SIPRequest);
655600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
656600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } catch (IOException ex) {
657600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw ex;
658600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } catch (Exception ex) {
659600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sipStack.getStackLogger().logError("An exception occured while sending message",ex);
660600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new IOException(
661600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    "An exception occured while sending message");
662600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } finally {
663600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES) && !sipMessage.isNullRequest())
664600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                logMessage(sipMessage, peerAddress, peerPort, time);
665600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            else if (sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_DEBUG))
666600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sipStack.getStackLogger().logDebug("Sent EMPTY Message");
667600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
668600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
669600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
670600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
671600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Send a message to a specified receiver address.
672600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
673600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param msg
674600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            string to send.
675600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param peerAddress
676600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            Address of the place to send it to.
677600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param peerPort
678600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            the port to send it to.
679600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @throws IOException
680600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *             If there is trouble sending this message.
681600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
682600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected void sendMessage(byte[] msg, InetAddress peerAddress,
683600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            int peerPort, boolean reConnect) throws IOException {
684600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Via is not included in the request so silently drop the reply.
685600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipStack.isLoggingEnabled() && this.sipStack.isLogStackTraceOnMessageSend() ) {
686600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.sipStack.getStackLogger().logStackTrace(StackLogger.TRACE_INFO);
687600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
688600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (peerPort == -1) {
689600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipStack.isLoggingEnabled()) {
690600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.sipStack.getStackLogger().logDebug(getClass().getName()
691600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + ":sendMessage: Dropping reply!");
692600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
693600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new IOException("Receiver port not set ");
694600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
695600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipStack.isLoggingEnabled()) {
696600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.sipStack.getStackLogger().logDebug("sendMessage " + peerAddress.getHostAddress() + "/"
697600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + peerPort + "\n" + "messageSize =  "  + msg.length + " message = " + new String(msg)) ;
698600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.sipStack.getStackLogger().logDebug("*******************\n");
699600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
700600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
701600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
702600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        DatagramPacket reply = new DatagramPacket(msg, msg.length, peerAddress,
703600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                peerPort);
704600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
705600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            DatagramSocket sock;
706600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            boolean created = false;
707600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
708600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipStack.udpFlag) {
709600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Use the socket from the message processor (for firewall
710600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // support use the same socket as the message processor
711600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // socket -- feature request # 18 from java.net). This also
712600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // makes the whole thing run faster!
713600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sock = ((UDPMessageProcessor) messageProcessor).sock;
714600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
715600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Bind the socket to the stack address in case there
716600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // are multiple interfaces on the machine (feature reqeust
717600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // by Will Scullin) 0 binds to an ephemeral port.
718600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // sock = new DatagramSocket(0,sipStack.stackInetAddress);
719600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else {
720600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // bind to any interface and port.
721600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sock = new DatagramSocket();
722600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                created = true;
723600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
724600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sock.send(reply);
725600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (created)
726600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sock.close();
727600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } catch (IOException ex) {
728600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw ex;
729600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } catch (Exception ex) {
730600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            InternalErrorHandler.handleException(ex);
731600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
732600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
733600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
734600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
735600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Send a message to a specified receiver address.
736600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
737600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param msg
738600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            message string to send.
739600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param peerAddress
740600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            Address of the place to send it to.
741600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param peerPort
742600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            the port to send it to.
743600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param peerProtocol
744600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            protocol to use to send.
745600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @throws IOException
746600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *             If there is trouble sending this message.
747600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
748600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected void sendMessage(byte[] msg, InetAddress peerAddress,
749600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            int peerPort, String peerProtocol, boolean retry)
750600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throws IOException {
751600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Via is not included in the request so silently drop the reply.
752600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (peerPort == -1) {
753600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipStack.isLoggingEnabled()) {
754600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.sipStack.getStackLogger().logDebug(getClass().getName()
755600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + ":sendMessage: Dropping reply!");
756600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
757600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new IOException("Receiver port not set ");
758600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
759600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipStack.isLoggingEnabled()) {
760600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.sipStack.getStackLogger().logDebug( ":sendMessage " + peerAddress.getHostAddress() + "/"
761600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + peerPort + "\n" + " messageSize = " + msg.length);
762600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
763600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
764600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (peerProtocol.compareToIgnoreCase("UDP") == 0) {
765600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            DatagramPacket reply = new DatagramPacket(msg, msg.length,
766600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    peerAddress, peerPort);
767600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
768600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
769600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                DatagramSocket sock;
770600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (sipStack.udpFlag) {
771600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sock = ((UDPMessageProcessor) messageProcessor).sock;
772600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
773600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else {
774600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // bind to any interface and port.
775600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sock = sipStack.getNetworkLayer().createDatagramSocket();
776600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
777600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (sipStack.isLoggingEnabled()) {
778600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.sipStack.getStackLogger().logDebug("sendMessage "
779600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            + peerAddress.getHostAddress() + "/" + peerPort
780600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            + "\n" + new String(msg));
781600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
782600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sock.send(reply);
783600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (!sipStack.udpFlag)
784600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sock.close();
785600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (IOException ex) {
786600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                throw ex;
787600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (Exception ex) {
788600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                InternalErrorHandler.handleException(ex);
789600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
790600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
791600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
792600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Use TCP to talk back to the sender.
793600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            Socket outputSocket = sipStack.ioHandler.sendBytes(
794600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.messageProcessor.getIpAddress(), peerAddress,
795600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    peerPort, "tcp", msg, retry,this);
796600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            OutputStream myOutputStream = outputSocket.getOutputStream();
797600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            myOutputStream.write(msg, 0, msg.length);
798600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            myOutputStream.flush();
799600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // The socket is cached (dont close it!);
800600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
801600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
802600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
803600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
804600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * get the stack pointer.
805600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
806600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return The sip stack for this channel.
807600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
808600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SIPTransactionStack getSIPStack() {
809600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return sipStack;
810600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
811600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
812600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
813600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Return a transport string.
814600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
815600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return the string "udp" in this case.
816600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
817600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public String getTransport() {
818600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return SIPConstants.UDP;
819600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
820600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
821600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
822600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * get the stack address for the stack that received this message.
823600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
824600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return The stack address for our sipStack.
825600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
826600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public String getHost() {
827600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return messageProcessor.getIpAddress().getHostAddress();
828600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
829600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
830600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
831600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * get the port.
832600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
833600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return Our port (on which we are getting datagram packets).
834600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
835600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public int getPort() {
836600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return ((UDPMessageProcessor) messageProcessor).getPort();
837600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
838600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
839600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
840600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * get the name (address) of the host that sent me the message
841600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
842600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return The name of the sender (from the datagram packet).
843600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
844600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public String getPeerName() {
845600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return peerAddress.getHostName();
846600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
847600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
848600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
849600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * get the address of the host that sent me the message
850600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
851600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return The senders ip address.
852600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
853600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public String getPeerAddress() {
854600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return peerAddress.getHostAddress();
855600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
856600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
857600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected InetAddress getPeerInetAddress() {
858600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return peerAddress;
859600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
860600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
861600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
862600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Compare two UDP Message channels for equality.
863600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
864600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param other
865600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            The other message channel with which to compare oursleves.
866600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
867600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public boolean equals(Object other) {
868600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
869600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (other == null)
870600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return false;
871600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        boolean retval;
872600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (!this.getClass().equals(other.getClass())) {
873600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            retval = false;
874600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
875600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            UDPMessageChannel that = (UDPMessageChannel) other;
876600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            retval = this.getKey().equals(that.getKey());
877600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
878600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
879600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return retval;
880600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
881600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
882600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public String getKey() {
883600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return getKey(peerAddress, peerPort, "UDP");
884600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
885600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
886600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public int getPeerPacketSourcePort() {
887600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return peerPacketSourcePort;
888600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
889600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
890600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public InetAddress getPeerPacketSourceAddress() {
891600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return peerPacketSourceAddress;
892600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
893600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
894600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
895600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the logical originator of the message (from the top via header).
896600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
897600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return topmost via header sentby field
898600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
899600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public String getViaHost() {
900600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.myAddress;
901600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
902600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
903600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
904600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the logical port of the message orginator (from the top via hdr).
905600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
906600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return the via port from the topmost via header.
907600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
908600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public int getViaPort() {
909600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.myPort;
910600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
911600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
912600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
913600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Returns "false" as this is an unreliable transport.
914600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
915600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public boolean isReliable() {
916600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return false;
917600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
918600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
919600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
920600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * UDP is not a secure protocol.
921600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
922600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public boolean isSecure() {
923600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return false;
924600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
925600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
926600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public int getPeerPort() {
927600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return peerPort;
928600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
929600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
930600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public String getPeerProtocol() {
931600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.peerProtocol;
932600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
933600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
934600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
935600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Close the message channel.
936600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
937600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void close() {
938600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
939600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
940600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
941600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang}
942