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.Host;
33600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.HostPort;
34600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.InternalErrorHandler;
35600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.ServerLogger;
36600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.address.AddressImpl;
37600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.ContentLength;
38600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.ContentType;
39600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.Via;
40600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.message.MessageFactoryImpl;
41600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.message.SIPMessage;
42600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.message.SIPRequest;
43600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.message.SIPResponse;
44600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
45600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.io.IOException;
46600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.net.InetAddress;
47600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.text.ParseException;
48600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
49600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.address.Hop;
50600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.CSeqHeader;
51600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.CallIdHeader;
52600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.ContactHeader;
53600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.ContentLengthHeader;
54600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.ContentTypeHeader;
55600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.FromHeader;
56600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.ServerHeader;
57600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.ToHeader;
58600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.ViaHeader;
59600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
60600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/**
61600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Message channel abstraction for the SIP stack.
62600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
63600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @author M. Ranganathan <br/> Contains additions for support of symmetric NAT contributed by
64600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *         Hagai.
65600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
66600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @version 1.2 $Revision: 1.28 $ $Date: 2009/11/14 20:06:18 $
67600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
68600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
69600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */
70600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangpublic abstract class MessageChannel {
71600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
72600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // Incremented whenever a transaction gets assigned
73600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // to the message channel and decremented when
74600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // a transaction gets freed from the message channel.
75600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	protected int useCount;
76600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
77600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	/**
78600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	 * Hook method, overridden by subclasses
79600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	 */
80600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	protected void uncache() {}
81600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
82600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
83600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Message processor to whom I belong (if set).
84600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
85600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected transient MessageProcessor messageProcessor;
86600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
87600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
88600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Close the message channel.
89600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
90600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public abstract void close();
91600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
92600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
93600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the SIPStack object from this message channel.
94600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
95600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return SIPStack object of this message channel
96600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
97600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public abstract SIPTransactionStack getSIPStack();
98600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
99600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
100600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get transport string of this message channel.
101600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
102600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return Transport string of this message channel.
103600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
104600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public abstract String getTransport();
105600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
106600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
107600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get whether this channel is reliable or not.
108600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
109600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return True if reliable, false if not.
110600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
111600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public abstract boolean isReliable();
112600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
113600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
114600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Return true if this is a secure channel.
115600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
116600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public abstract boolean isSecure();
117600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
118600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
119600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Send the message (after it has been formatted)
120600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
121600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param sipMessage Message to send.
122600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
123600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public abstract void sendMessage(SIPMessage sipMessage) throws IOException;
124600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
125600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
126600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the peer address of the machine that sent us this message.
127600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
128600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return a string contianing the ip address or host name of the sender of the message.
129600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
130600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public abstract String getPeerAddress();
131600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
132600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected abstract InetAddress getPeerInetAddress();
133600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
134600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected abstract String getPeerProtocol();
135600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
136600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
137600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the sender port ( the port of the other end that sent me the message).
138600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
139600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public abstract int getPeerPort();
140600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
141600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public abstract int getPeerPacketSourcePort();
142600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
143600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public abstract InetAddress getPeerPacketSourceAddress();
144600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
145600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
146600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Generate a key which identifies the message channel. This allows us to cache the message
147600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * channel.
148600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
149600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public abstract String getKey();
150600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
151600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
152600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the host to assign for an outgoing Request via header.
153600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
154600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public abstract String getViaHost();
155600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
156600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
157600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the port to assign for the via header of an outgoing message.
158600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
159600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public abstract int getViaPort();
160600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
161600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
162600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Send the message (after it has been formatted), to a specified address and a specified port
163600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
164600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param message Message to send.
165600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param receiverAddress Address of the receiver.
166600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param receiverPort Port of the receiver.
167600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
168600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected abstract void sendMessage(byte[] message, InetAddress receiverAddress,
169600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            int receiverPort, boolean reconnectFlag) throws IOException;
170600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
171600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
172600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the host of this message channel.
173600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
174600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return host of this messsage channel.
175600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
176600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public String getHost() {
177600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.getMessageProcessor().getIpAddress().getHostAddress();
178600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
179600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
180600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
181600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get port of this message channel.
182600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
183600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return Port of this message channel.
184600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
185600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public int getPort() {
186600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (this.messageProcessor != null)
187600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return messageProcessor.getPort();
188600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        else
189600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return -1;
190600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
191600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
192600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
193600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Send a formatted message to the specified target.
194600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
195600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param sipMessage Message to send.
196600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param hop hop to send it to.
197600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @throws IOException If there is an error sending the message
198600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
199600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void sendMessage(SIPMessage sipMessage, Hop hop) throws IOException {
200600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        long time = System.currentTimeMillis();
201600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        InetAddress hopAddr = InetAddress.getByName(hop.getHost());
202600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
203600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
204600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
205600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            for (MessageProcessor messageProcessor : getSIPStack().getMessageProcessors()) {
206600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (messageProcessor.getIpAddress().equals(hopAddr)
207600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        && messageProcessor.getPort() == hop.getPort()
208600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        && messageProcessor.getTransport().equals(hop.getTransport())) {
209600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    MessageChannel messageChannel = messageProcessor.createMessageChannel(
210600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            hopAddr, hop.getPort());
211600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (messageChannel instanceof RawMessageChannel) {
212600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        ((RawMessageChannel) messageChannel).processMessage(sipMessage);
213600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        if (getSIPStack().isLoggingEnabled())
214600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        	getSIPStack().getStackLogger().logDebug("Self routing message");
215600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        return;
216600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
217600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
218600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
219600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
220600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            byte[] msg = sipMessage.encodeAsBytes(this.getTransport());
221600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
222600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.sendMessage(msg, hopAddr, hop.getPort(), sipMessage instanceof SIPRequest);
223600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
224600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } catch (IOException ioe) {
225600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw ioe;
226600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } catch (Exception ex) {
227600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        	if (this.getSIPStack().getStackLogger().isLoggingEnabled(ServerLogger.TRACE_ERROR)) {
228600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        		this.getSIPStack().getStackLogger().logError("Error self routing message cause by: ", ex);
229600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        	}
230600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        	// TODO: When moving to Java 6, use the IOExcpetion(message, exception) constructor
231600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new IOException("Error self routing message");
232600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } finally {
233600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
234600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (this.getSIPStack().getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES))
235600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                logMessage(sipMessage, hopAddr, hop.getPort(), time);
236600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
237600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
238600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
239600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
240600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Send a message given SIP message.
241600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
242600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param sipMessage is the messge to send.
243600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param receiverAddress is the address to which we want to send
244600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param receiverPort is the port to which we want to send
245600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
246600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void sendMessage(SIPMessage sipMessage, InetAddress receiverAddress, int receiverPort)
247600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throws IOException {
248600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        long time = System.currentTimeMillis();
249600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        byte[] bytes = sipMessage.encodeAsBytes(this.getTransport());
250600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        sendMessage(bytes, receiverAddress, receiverPort, sipMessage instanceof SIPRequest);
251600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        logMessage(sipMessage, receiverAddress, receiverPort, time);
252600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
253600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
254600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
255600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Convenience function to get the raw IP source address of a SIP message as a String.
256600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
257600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public String getRawIpSourceAddress() {
258600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String sourceAddress = getPeerAddress();
259600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String rawIpSourceAddress = null;
260600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
261600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            InetAddress sourceInetAddress = InetAddress.getByName(sourceAddress);
262600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            rawIpSourceAddress = sourceInetAddress.getHostAddress();
263600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } catch (Exception ex) {
264600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            InternalErrorHandler.handleException(ex);
265600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
266600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return rawIpSourceAddress;
267600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
268600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
269600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
270600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * generate a key given the inet address port and transport.
271600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
272600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public static String getKey(InetAddress inetAddr, int port, String transport) {
273600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return (transport + ":" + inetAddr.getHostAddress() + ":" + port).toLowerCase();
274600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
275600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
276600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
277600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Generate a key given host and port.
278600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
279600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public static String getKey(HostPort hostPort, String transport) {
280600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return (transport + ":" + hostPort.getHost().getHostname() + ":" + hostPort.getPort())
281600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                .toLowerCase();
282600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
283600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
284600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
285600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the hostport structure of this message channel.
286600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
287600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public HostPort getHostPort() {
288600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        HostPort retval = new HostPort();
289600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        retval.setHost(new Host(this.getHost()));
290600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        retval.setPort(this.getPort());
291600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return retval;
292600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
293600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
294600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
295600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the peer host and port.
296600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
297600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return a HostPort structure for the peer.
298600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
299600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public HostPort getPeerHostPort() {
300600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        HostPort retval = new HostPort();
301600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        retval.setHost(new Host(this.getPeerAddress()));
302600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        retval.setPort(this.getPeerPort());
303600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return retval;
304600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
305600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
306600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
307600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the Via header for this transport. Note that this does not set a branch identifier.
308600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
309600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return a via header for outgoing messages sent from this channel.
310600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
311600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public Via getViaHeader() {
312600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        Via channelViaHeader;
313600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
314600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        channelViaHeader = new Via();
315600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
316600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            channelViaHeader.setTransport(getTransport());
317600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } catch (ParseException ex) {
318600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
319600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        channelViaHeader.setSentBy(getHostPort());
320600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return channelViaHeader;
321600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
322600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
323600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
324600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the via header host:port structure. This is extracted from the topmost via header of
325600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * the request.
326600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
327600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return a host:port structure
328600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
329600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public HostPort getViaHostPort() {
330600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        HostPort retval = new HostPort();
331600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        retval.setHost(new Host(this.getViaHost()));
332600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        retval.setPort(this.getViaPort());
333600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return retval;
334600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
335600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
336600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
337600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Log a message sent to an address and port via the default interface.
338600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
339600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param sipMessage is the message to log.
340600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param address is the inet address to which the message is sent.
341600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param port is the port to which the message is directed.
342600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
343600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected void logMessage(SIPMessage sipMessage, InetAddress address, int port, long time) {
344600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (!getSIPStack().getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES))
345600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return;
346600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
347600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Default port.
348600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (port == -1)
349600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            port = 5060;
350600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        getSIPStack().serverLogger.logMessage(sipMessage, this.getHost() + ":" + this.getPort(),
351600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                address.getHostAddress().toString() + ":" + port, true, time);
352600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
353600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
354600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
355600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Log a response received at this message channel. This is used for processing incoming
356600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * responses to a client transaction.
357600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
358600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param receptionTime is the time at which the response was received.
359600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param status is the processing status of the message.
360600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
361600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
362600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void logResponse(SIPResponse sipResponse, long receptionTime, String status) {
363600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        int peerport = getPeerPort();
364600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (peerport == 0 && sipResponse.getContactHeaders() != null) {
365600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            ContactHeader contact = (ContactHeader) sipResponse.getContactHeaders().getFirst();
366600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            peerport = ((AddressImpl) contact.getAddress()).getPort();
367600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
368600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
369600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String from = getPeerAddress().toString() + ":" + peerport;
370600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String to = this.getHost() + ":" + getPort();
371600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.getSIPStack().serverLogger.logMessage(sipResponse, from, to, status, false,
372600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                receptionTime);
373600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
374600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
375600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
376600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Creates a response to a bad request (ie one that causes a ParseException)
377600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
378600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param badReq
379600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return message bytes, null if unable to formulate response
380600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
381600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected final String createBadReqRes(String badReq, ParseException pe) {
382600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
383600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        StringBuffer buf = new StringBuffer(512);
384600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        buf.append("SIP/2.0 400 Bad Request (" + pe.getLocalizedMessage() + ')');
385600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
386600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // We need the following headers: all Vias, CSeq, Call-ID, From, To
387600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (!copyViaHeaders(badReq, buf))
388600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return null;
389600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (!copyHeader(CSeqHeader.NAME, badReq, buf))
390600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return null;
391600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (!copyHeader(CallIdHeader.NAME, badReq, buf))
392600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return null;
393600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (!copyHeader(FromHeader.NAME, badReq, buf))
394600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return null;
395600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (!copyHeader(ToHeader.NAME, badReq, buf))
396600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return null;
397600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
398600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Should add a to-tag if not already present...
399600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        int toStart = buf.indexOf(ToHeader.NAME);
400600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (toStart != -1 && buf.indexOf("tag", toStart) == -1) {
401600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            buf.append(";tag=badreq");
402600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
403600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
404600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Let's add a Server header too..
405600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        ServerHeader s = MessageFactoryImpl.getDefaultServerHeader();
406600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if ( s != null ) {
407600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            buf.append("\r\n" + s.toString());
408600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
409600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        int clength = badReq.length();
410600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (! (this instanceof UDPMessageChannel) ||
411600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                clength + buf.length() + ContentTypeHeader.NAME.length()
412600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                + ": message/sipfrag\r\n".length() +
413600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                ContentLengthHeader.NAME.length()  < 1300) {
414600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
415600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            /*
416600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             * Check to see we are within one UDP packet.
417600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             */
418600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            ContentTypeHeader cth = new ContentType("message", "sipfrag");
419600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            buf.append("\r\n" + cth.toString());
420600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            ContentLength clengthHeader = new ContentLength(clength);
421600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            buf.append("\r\n" + clengthHeader.toString());
422600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            buf.append("\r\n\r\n" + badReq);
423600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
424600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            ContentLength clengthHeader = new ContentLength(0);
425600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            buf.append("\r\n" + clengthHeader.toString());
426600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
427600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
428600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return buf.toString();
429600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
430600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
431600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
432600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Copies a header from a request
433600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
434600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param name
435600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param fromReq
436600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param buf
437600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return
438600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
439600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Note: some limitations here: does not work for short forms of headers, or continuations;
440600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * problems when header names appear in other parts of the request
441600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
442600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private static final boolean copyHeader(String name, String fromReq, StringBuffer buf) {
443600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        int start = fromReq.indexOf(name);
444600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (start != -1) {
445600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            int end = fromReq.indexOf("\r\n", start);
446600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (end != -1) {
447600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // XX Assumes no continuation here...
448600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                buf.append(fromReq.subSequence(start - 2, end)); // incl CRLF
449600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // in front
450600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return true;
451600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
452600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
453600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return false;
454600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
455600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
456600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
457600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Copies all via headers from a request
458600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
459600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param fromReq
460600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param buf
461600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return
462600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
463600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Note: some limitations here: does not work for short forms of headers, or continuations
464600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
465600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private static final boolean copyViaHeaders(String fromReq, StringBuffer buf) {
466600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        int start = fromReq.indexOf(ViaHeader.NAME);
467600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        boolean found = false;
468600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        while (start != -1) {
469600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            int end = fromReq.indexOf("\r\n", start);
470600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (end != -1) {
471600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // XX Assumes no continuation here...
472600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                buf.append(fromReq.subSequence(start - 2, end)); // incl CRLF
473600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // in front
474600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                found = true;
475600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                start = fromReq.indexOf(ViaHeader.NAME, end);
476600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else {
477600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return false;
478600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
479600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
480600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return found;
481600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
482600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
483600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
484600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the message processor.
485600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
486600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public MessageProcessor getMessageProcessor() {
487600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.messageProcessor;
488600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
489600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang}
490