MessageChannel.java revision 600c7a4bbc7348167293eac928192e695b4ad5ba
10c7ca13f3a726e3cf7d7a582c95ab7eea990082aroubert@google.com/*
20c7ca13f3a726e3cf7d7a582c95ab7eea990082aroubert@google.com * Conditions Of Use
30c7ca13f3a726e3cf7d7a582c95ab7eea990082aroubert@google.com *
40c7ca13f3a726e3cf7d7a582c95ab7eea990082aroubert@google.com * This software was developed by employees of the National Institute of
50c7ca13f3a726e3cf7d7a582c95ab7eea990082aroubert@google.com * Standards and Technology (NIST), an agency of the Federal Government.
60c7ca13f3a726e3cf7d7a582c95ab7eea990082aroubert@google.com * Pursuant to title 15 Untied States Code Section 105, works of NIST
70c7ca13f3a726e3cf7d7a582c95ab7eea990082aroubert@google.com * employees are not subject to copyright protection in the United States
80c7ca13f3a726e3cf7d7a582c95ab7eea990082aroubert@google.com * and are considered to be in the public domain.  As a result, a formal
90c7ca13f3a726e3cf7d7a582c95ab7eea990082aroubert@google.com * license is not needed to use the software.
100c7ca13f3a726e3cf7d7a582c95ab7eea990082aroubert@google.com *
110c7ca13f3a726e3cf7d7a582c95ab7eea990082aroubert@google.com * This software is provided by NIST as a service and is expressly
120c7ca13f3a726e3cf7d7a582c95ab7eea990082aroubert@google.com * provided "AS IS."  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
130c7ca13f3a726e3cf7d7a582c95ab7eea990082aroubert@google.com * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
140c7ca13f3a726e3cf7d7a582c95ab7eea990082aroubert@google.com * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
150c7ca13f3a726e3cf7d7a582c95ab7eea990082aroubert@google.com * AND DATA ACCURACY.  NIST does not warrant or make any representations
160c7ca13f3a726e3cf7d7a582c95ab7eea990082aroubert@google.com * regarding the use of the software or the results thereof, including but
170c7ca13f3a726e3cf7d7a582c95ab7eea990082aroubert@google.com * not limited to the correctness, accuracy, reliability or usefulness of
180c7ca13f3a726e3cf7d7a582c95ab7eea990082aroubert@google.com * the software.
190c7ca13f3a726e3cf7d7a582c95ab7eea990082aroubert@google.com *
200c7ca13f3a726e3cf7d7a582c95ab7eea990082aroubert@google.com * Permission to use this software is contingent upon your acceptance
210c7ca13f3a726e3cf7d7a582c95ab7eea990082aroubert@google.com * of the terms of this agreement
220c7ca13f3a726e3cf7d7a582c95ab7eea990082aroubert@google.com *
232a2386e14357a672090d07daf6e2316d2dd34b88lararennie@google.com * .
242a2386e14357a672090d07daf6e2316d2dd34b88lararennie@google.com *
250c7ca13f3a726e3cf7d7a582c95ab7eea990082aroubert@google.com */
26dc4cdad9dd71a57be66262d1d6d46a09c0973818lararennie@google.com/******************************************************************************
272c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).       *
282c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com ******************************************************************************/
292c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com
302c25a6f4922225b619b0e389befde8b941e78834jeanine@google.compackage gov.nist.javax.sip.stack;
312c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com
322c25a6f4922225b619b0e389befde8b941e78834jeanine@google.comimport gov.nist.core.Host;
332c25a6f4922225b619b0e389befde8b941e78834jeanine@google.comimport gov.nist.core.HostPort;
342a2386e14357a672090d07daf6e2316d2dd34b88lararennie@google.comimport gov.nist.core.InternalErrorHandler;
352a2386e14357a672090d07daf6e2316d2dd34b88lararennie@google.comimport gov.nist.core.ServerLogger;
362c25a6f4922225b619b0e389befde8b941e78834jeanine@google.comimport gov.nist.javax.sip.address.AddressImpl;
372c25a6f4922225b619b0e389befde8b941e78834jeanine@google.comimport gov.nist.javax.sip.header.ContentLength;
382c25a6f4922225b619b0e389befde8b941e78834jeanine@google.comimport gov.nist.javax.sip.header.ContentType;
392a2386e14357a672090d07daf6e2316d2dd34b88lararennie@google.comimport gov.nist.javax.sip.header.Via;
402c25a6f4922225b619b0e389befde8b941e78834jeanine@google.comimport gov.nist.javax.sip.message.MessageFactoryImpl;
412c25a6f4922225b619b0e389befde8b941e78834jeanine@google.comimport gov.nist.javax.sip.message.SIPMessage;
422c25a6f4922225b619b0e389befde8b941e78834jeanine@google.comimport gov.nist.javax.sip.message.SIPRequest;
432a2386e14357a672090d07daf6e2316d2dd34b88lararennie@google.comimport gov.nist.javax.sip.message.SIPResponse;
442a2386e14357a672090d07daf6e2316d2dd34b88lararennie@google.com
452a2386e14357a672090d07daf6e2316d2dd34b88lararennie@google.comimport java.io.IOException;
462a2386e14357a672090d07daf6e2316d2dd34b88lararennie@google.comimport java.net.InetAddress;
472c25a6f4922225b619b0e389befde8b941e78834jeanine@google.comimport java.text.ParseException;
482c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com
492c25a6f4922225b619b0e389befde8b941e78834jeanine@google.comimport javax.sip.address.Hop;
502a2386e14357a672090d07daf6e2316d2dd34b88lararennie@google.comimport javax.sip.header.CSeqHeader;
512c25a6f4922225b619b0e389befde8b941e78834jeanine@google.comimport javax.sip.header.CallIdHeader;
522c25a6f4922225b619b0e389befde8b941e78834jeanine@google.comimport javax.sip.header.ContactHeader;
532c25a6f4922225b619b0e389befde8b941e78834jeanine@google.comimport javax.sip.header.ContentLengthHeader;
542c25a6f4922225b619b0e389befde8b941e78834jeanine@google.comimport javax.sip.header.ContentTypeHeader;
552a2386e14357a672090d07daf6e2316d2dd34b88lararennie@google.comimport javax.sip.header.FromHeader;
562c25a6f4922225b619b0e389befde8b941e78834jeanine@google.comimport javax.sip.header.ServerHeader;
572c25a6f4922225b619b0e389befde8b941e78834jeanine@google.comimport javax.sip.header.ToHeader;
582c25a6f4922225b619b0e389befde8b941e78834jeanine@google.comimport javax.sip.header.ViaHeader;
59771cc560df04dc201a90012c15b5814c33f6d5d8lararennie@google.com
60771cc560df04dc201a90012c15b5814c33f6d5d8lararennie@google.com/**
61771cc560df04dc201a90012c15b5814c33f6d5d8lararennie@google.com * Message channel abstraction for the SIP stack.
62771cc560df04dc201a90012c15b5814c33f6d5d8lararennie@google.com *
632c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * @author M. Ranganathan <br/> Contains additions for support of symmetric NAT contributed by
642c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com *         Hagai.
652c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com *
662c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * @version 1.2 $Revision: 1.28 $ $Date: 2009/11/14 20:06:18 $
67771cc560df04dc201a90012c15b5814c33f6d5d8lararennie@google.com *
682c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com *
692c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com */
702c25a6f4922225b619b0e389befde8b941e78834jeanine@google.compublic abstract class MessageChannel {
712a2386e14357a672090d07daf6e2316d2dd34b88lararennie@google.com
722c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com    // Incremented whenever a transaction gets assigned
732c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com    // to the message channel and decremented when
742c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com    // a transaction gets freed from the message channel.
752a2386e14357a672090d07daf6e2316d2dd34b88lararennie@google.com	protected int useCount;
762a2386e14357a672090d07daf6e2316d2dd34b88lararennie@google.com
772c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com	/**
782c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com	 * Hook method, overridden by subclasses
792c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com	 */
802a2386e14357a672090d07daf6e2316d2dd34b88lararennie@google.com	protected void uncache() {}
812c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com
822c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com    /**
832c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com     * Message processor to whom I belong (if set).
842a2386e14357a672090d07daf6e2316d2dd34b88lararennie@google.com     */
852c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com    protected transient MessageProcessor messageProcessor;
862c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com
872c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com    /**
882c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com     * Close the message channel.
892c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com     */
902c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com    public abstract void close();
912c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com
922c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com    /**
932c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com     * Get the SIPStack object from this message channel.
942c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com     *
952c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com     * @return SIPStack object of this message channel
962c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com     */
97771cc560df04dc201a90012c15b5814c33f6d5d8lararennie@google.com    public abstract SIPTransactionStack getSIPStack();
982c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com
992c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com    /**
1000c7ca13f3a726e3cf7d7a582c95ab7eea990082aroubert@google.com     * Get transport string of this message channel.
1012c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com     *
1022c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com     * @return Transport string of this message channel.
1032c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com     */
1042c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com    public abstract String getTransport();
105dc4cdad9dd71a57be66262d1d6d46a09c0973818lararennie@google.com
106e9664fb4251726db44bec0751f77026e23ce71bbshaopengjia@google.com    /**
1072c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com     * Get whether this channel is reliable or not.
1082c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com     *
109e9664fb4251726db44bec0751f77026e23ce71bbshaopengjia@google.com     * @return True if reliable, false if not.
110e9664fb4251726db44bec0751f77026e23ce71bbshaopengjia@google.com     */
1110c7ca13f3a726e3cf7d7a582c95ab7eea990082aroubert@google.com    public abstract boolean isReliable();
1122c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com
1132a2386e14357a672090d07daf6e2316d2dd34b88lararennie@google.com    /**
1142a2386e14357a672090d07daf6e2316d2dd34b88lararennie@google.com     * Return true if this is a secure channel.
115e9664fb4251726db44bec0751f77026e23ce71bbshaopengjia@google.com     */
1162c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com    public abstract boolean isSecure();
1170c7ca13f3a726e3cf7d7a582c95ab7eea990082aroubert@google.com
1180c7ca13f3a726e3cf7d7a582c95ab7eea990082aroubert@google.com    /**
119     * Send the message (after it has been formatted)
120     *
121     * @param sipMessage Message to send.
122     */
123    public abstract void sendMessage(SIPMessage sipMessage) throws IOException;
124
125    /**
126     * Get the peer address of the machine that sent us this message.
127     *
128     * @return a string contianing the ip address or host name of the sender of the message.
129     */
130    public abstract String getPeerAddress();
131
132    protected abstract InetAddress getPeerInetAddress();
133
134    protected abstract String getPeerProtocol();
135
136    /**
137     * Get the sender port ( the port of the other end that sent me the message).
138     */
139    public abstract int getPeerPort();
140
141    public abstract int getPeerPacketSourcePort();
142
143    public abstract InetAddress getPeerPacketSourceAddress();
144
145    /**
146     * Generate a key which identifies the message channel. This allows us to cache the message
147     * channel.
148     */
149    public abstract String getKey();
150
151    /**
152     * Get the host to assign for an outgoing Request via header.
153     */
154    public abstract String getViaHost();
155
156    /**
157     * Get the port to assign for the via header of an outgoing message.
158     */
159    public abstract int getViaPort();
160
161    /**
162     * Send the message (after it has been formatted), to a specified address and a specified port
163     *
164     * @param message Message to send.
165     * @param receiverAddress Address of the receiver.
166     * @param receiverPort Port of the receiver.
167     */
168    protected abstract void sendMessage(byte[] message, InetAddress receiverAddress,
169            int receiverPort, boolean reconnectFlag) throws IOException;
170
171    /**
172     * Get the host of this message channel.
173     *
174     * @return host of this messsage channel.
175     */
176    public String getHost() {
177        return this.getMessageProcessor().getIpAddress().getHostAddress();
178    }
179
180    /**
181     * Get port of this message channel.
182     *
183     * @return Port of this message channel.
184     */
185    public int getPort() {
186        if (this.messageProcessor != null)
187            return messageProcessor.getPort();
188        else
189            return -1;
190    }
191
192    /**
193     * Send a formatted message to the specified target.
194     *
195     * @param sipMessage Message to send.
196     * @param hop hop to send it to.
197     * @throws IOException If there is an error sending the message
198     */
199    public void sendMessage(SIPMessage sipMessage, Hop hop) throws IOException {
200        long time = System.currentTimeMillis();
201        InetAddress hopAddr = InetAddress.getByName(hop.getHost());
202
203        try {
204
205            for (MessageProcessor messageProcessor : getSIPStack().getMessageProcessors()) {
206                if (messageProcessor.getIpAddress().equals(hopAddr)
207                        && messageProcessor.getPort() == hop.getPort()
208                        && messageProcessor.getTransport().equals(hop.getTransport())) {
209                    MessageChannel messageChannel = messageProcessor.createMessageChannel(
210                            hopAddr, hop.getPort());
211                    if (messageChannel instanceof RawMessageChannel) {
212                        ((RawMessageChannel) messageChannel).processMessage(sipMessage);
213                        if (getSIPStack().isLoggingEnabled())
214                        	getSIPStack().getStackLogger().logDebug("Self routing message");
215                        return;
216                    }
217
218                }
219            }
220            byte[] msg = sipMessage.encodeAsBytes(this.getTransport());
221
222            this.sendMessage(msg, hopAddr, hop.getPort(), sipMessage instanceof SIPRequest);
223
224        } catch (IOException ioe) {
225            throw ioe;
226        } catch (Exception ex) {
227        	if (this.getSIPStack().getStackLogger().isLoggingEnabled(ServerLogger.TRACE_ERROR)) {
228        		this.getSIPStack().getStackLogger().logError("Error self routing message cause by: ", ex);
229        	}
230        	// TODO: When moving to Java 6, use the IOExcpetion(message, exception) constructor
231            throw new IOException("Error self routing message");
232        } finally {
233
234            if (this.getSIPStack().getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES))
235                logMessage(sipMessage, hopAddr, hop.getPort(), time);
236        }
237    }
238
239    /**
240     * Send a message given SIP message.
241     *
242     * @param sipMessage is the messge to send.
243     * @param receiverAddress is the address to which we want to send
244     * @param receiverPort is the port to which we want to send
245     */
246    public void sendMessage(SIPMessage sipMessage, InetAddress receiverAddress, int receiverPort)
247            throws IOException {
248        long time = System.currentTimeMillis();
249        byte[] bytes = sipMessage.encodeAsBytes(this.getTransport());
250        sendMessage(bytes, receiverAddress, receiverPort, sipMessage instanceof SIPRequest);
251        logMessage(sipMessage, receiverAddress, receiverPort, time);
252    }
253
254    /**
255     * Convenience function to get the raw IP source address of a SIP message as a String.
256     */
257    public String getRawIpSourceAddress() {
258        String sourceAddress = getPeerAddress();
259        String rawIpSourceAddress = null;
260        try {
261            InetAddress sourceInetAddress = InetAddress.getByName(sourceAddress);
262            rawIpSourceAddress = sourceInetAddress.getHostAddress();
263        } catch (Exception ex) {
264            InternalErrorHandler.handleException(ex);
265        }
266        return rawIpSourceAddress;
267    }
268
269    /**
270     * generate a key given the inet address port and transport.
271     */
272    public static String getKey(InetAddress inetAddr, int port, String transport) {
273        return (transport + ":" + inetAddr.getHostAddress() + ":" + port).toLowerCase();
274    }
275
276    /**
277     * Generate a key given host and port.
278     */
279    public static String getKey(HostPort hostPort, String transport) {
280        return (transport + ":" + hostPort.getHost().getHostname() + ":" + hostPort.getPort())
281                .toLowerCase();
282    }
283
284    /**
285     * Get the hostport structure of this message channel.
286     */
287    public HostPort getHostPort() {
288        HostPort retval = new HostPort();
289        retval.setHost(new Host(this.getHost()));
290        retval.setPort(this.getPort());
291        return retval;
292    }
293
294    /**
295     * Get the peer host and port.
296     *
297     * @return a HostPort structure for the peer.
298     */
299    public HostPort getPeerHostPort() {
300        HostPort retval = new HostPort();
301        retval.setHost(new Host(this.getPeerAddress()));
302        retval.setPort(this.getPeerPort());
303        return retval;
304    }
305
306    /**
307     * Get the Via header for this transport. Note that this does not set a branch identifier.
308     *
309     * @return a via header for outgoing messages sent from this channel.
310     */
311    public Via getViaHeader() {
312        Via channelViaHeader;
313
314        channelViaHeader = new Via();
315        try {
316            channelViaHeader.setTransport(getTransport());
317        } catch (ParseException ex) {
318        }
319        channelViaHeader.setSentBy(getHostPort());
320        return channelViaHeader;
321    }
322
323    /**
324     * Get the via header host:port structure. This is extracted from the topmost via header of
325     * the request.
326     *
327     * @return a host:port structure
328     */
329    public HostPort getViaHostPort() {
330        HostPort retval = new HostPort();
331        retval.setHost(new Host(this.getViaHost()));
332        retval.setPort(this.getViaPort());
333        return retval;
334    }
335
336    /**
337     * Log a message sent to an address and port via the default interface.
338     *
339     * @param sipMessage is the message to log.
340     * @param address is the inet address to which the message is sent.
341     * @param port is the port to which the message is directed.
342     */
343    protected void logMessage(SIPMessage sipMessage, InetAddress address, int port, long time) {
344        if (!getSIPStack().getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES))
345            return;
346
347        // Default port.
348        if (port == -1)
349            port = 5060;
350        getSIPStack().serverLogger.logMessage(sipMessage, this.getHost() + ":" + this.getPort(),
351                address.getHostAddress().toString() + ":" + port, true, time);
352    }
353
354    /**
355     * Log a response received at this message channel. This is used for processing incoming
356     * responses to a client transaction.
357     *
358     * @param receptionTime is the time at which the response was received.
359     * @param status is the processing status of the message.
360     *
361     */
362    public void logResponse(SIPResponse sipResponse, long receptionTime, String status) {
363        int peerport = getPeerPort();
364        if (peerport == 0 && sipResponse.getContactHeaders() != null) {
365            ContactHeader contact = (ContactHeader) sipResponse.getContactHeaders().getFirst();
366            peerport = ((AddressImpl) contact.getAddress()).getPort();
367
368        }
369        String from = getPeerAddress().toString() + ":" + peerport;
370        String to = this.getHost() + ":" + getPort();
371        this.getSIPStack().serverLogger.logMessage(sipResponse, from, to, status, false,
372                receptionTime);
373    }
374
375    /**
376     * Creates a response to a bad request (ie one that causes a ParseException)
377     *
378     * @param badReq
379     * @return message bytes, null if unable to formulate response
380     */
381    protected final String createBadReqRes(String badReq, ParseException pe) {
382
383        StringBuffer buf = new StringBuffer(512);
384        buf.append("SIP/2.0 400 Bad Request (" + pe.getLocalizedMessage() + ')');
385
386        // We need the following headers: all Vias, CSeq, Call-ID, From, To
387        if (!copyViaHeaders(badReq, buf))
388            return null;
389        if (!copyHeader(CSeqHeader.NAME, badReq, buf))
390            return null;
391        if (!copyHeader(CallIdHeader.NAME, badReq, buf))
392            return null;
393        if (!copyHeader(FromHeader.NAME, badReq, buf))
394            return null;
395        if (!copyHeader(ToHeader.NAME, badReq, buf))
396            return null;
397
398        // Should add a to-tag if not already present...
399        int toStart = buf.indexOf(ToHeader.NAME);
400        if (toStart != -1 && buf.indexOf("tag", toStart) == -1) {
401            buf.append(";tag=badreq");
402        }
403
404        // Let's add a Server header too..
405        ServerHeader s = MessageFactoryImpl.getDefaultServerHeader();
406        if ( s != null ) {
407            buf.append("\r\n" + s.toString());
408        }
409        int clength = badReq.length();
410        if (! (this instanceof UDPMessageChannel) ||
411                clength + buf.length() + ContentTypeHeader.NAME.length()
412                + ": message/sipfrag\r\n".length() +
413                ContentLengthHeader.NAME.length()  < 1300) {
414
415            /*
416             * Check to see we are within one UDP packet.
417             */
418            ContentTypeHeader cth = new ContentType("message", "sipfrag");
419            buf.append("\r\n" + cth.toString());
420            ContentLength clengthHeader = new ContentLength(clength);
421            buf.append("\r\n" + clengthHeader.toString());
422            buf.append("\r\n\r\n" + badReq);
423        } else {
424            ContentLength clengthHeader = new ContentLength(0);
425            buf.append("\r\n" + clengthHeader.toString());
426        }
427
428        return buf.toString();
429    }
430
431    /**
432     * Copies a header from a request
433     *
434     * @param name
435     * @param fromReq
436     * @param buf
437     * @return
438     *
439     * Note: some limitations here: does not work for short forms of headers, or continuations;
440     * problems when header names appear in other parts of the request
441     */
442    private static final boolean copyHeader(String name, String fromReq, StringBuffer buf) {
443        int start = fromReq.indexOf(name);
444        if (start != -1) {
445            int end = fromReq.indexOf("\r\n", start);
446            if (end != -1) {
447                // XX Assumes no continuation here...
448                buf.append(fromReq.subSequence(start - 2, end)); // incl CRLF
449                // in front
450                return true;
451            }
452        }
453        return false;
454    }
455
456    /**
457     * Copies all via headers from a request
458     *
459     * @param fromReq
460     * @param buf
461     * @return
462     *
463     * Note: some limitations here: does not work for short forms of headers, or continuations
464     */
465    private static final boolean copyViaHeaders(String fromReq, StringBuffer buf) {
466        int start = fromReq.indexOf(ViaHeader.NAME);
467        boolean found = false;
468        while (start != -1) {
469            int end = fromReq.indexOf("\r\n", start);
470            if (end != -1) {
471                // XX Assumes no continuation here...
472                buf.append(fromReq.subSequence(start - 2, end)); // incl CRLF
473                // in front
474                found = true;
475                start = fromReq.indexOf(ViaHeader.NAME, end);
476            } else {
477                return false;
478            }
479        }
480        return found;
481    }
482
483    /**
484     * Get the message processor.
485     */
486    public MessageProcessor getMessageProcessor() {
487        return this.messageProcessor;
488    }
489}
490