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 Wangpackage gov.nist.javax.sip.stack;
30600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
31600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.io.IOException;
32600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.LinkedList;
33600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.net.*;
34600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
35600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.*;
36600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
37600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/**
38600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Sit in a loop and handle incoming udp datagram messages. For each Datagram
39600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * packet, a new UDPMessageChannel is created (upto the max thread pool size).
40600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Each UDP message is processed in its own thread).
41600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
42600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @version 1.2 $Revision: 1.37 $ $Date: 2009/11/14 20:06:16 $
43600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
44600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @author M. Ranganathan  <br/>
45600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
46600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
47600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
48600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * <a href="{@docRoot}/../uml/udp-request-processing-sequence-diagram.jpg">
49600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * See the implementation sequence diagram for processing incoming requests.
50600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * </a>
51600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
52600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
53600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Acknowledgement: Jeff Keyser contributed ideas on starting and stoppping the
54600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * stack that were incorporated into this code. Niklas Uhrberg suggested that
55600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * thread pooling be added to limit the number of threads and improve
56600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * performance.
57600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */
58600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangpublic class UDPMessageProcessor extends MessageProcessor {
59600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
60600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * The Mapped port (in case STUN suport is enabled)
61600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
62600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private int port;
63600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
64600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
65600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Incoming messages are queued here.
66600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
67600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected LinkedList messageQueue;
68600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
69600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
70600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * A list of message channels that we have started.
71600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
72600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected LinkedList messageChannels;
73600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
74600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
75600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Max # of udp message channels
76600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
77600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected int threadPoolSize;
78600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
79600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected DatagramSocket sock;
80600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
81600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
82600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * A flag that is set to false to exit the message processor (suggestion by
83600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Jeff Keyser).
84600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
85600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected boolean isRunning;
86600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
87600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private static final int HIGHWAT=5000;
88600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
89600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private static final int LOWAT=2500;
90600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
91600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
92600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Constructor.
93600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
94600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param sipStack
95600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            pointer to the stack.
96600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
97600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected UDPMessageProcessor(InetAddress ipAddress,
98600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            SIPTransactionStack sipStack, int port) throws IOException {
99600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        super(ipAddress, port, "udp",sipStack);
100600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
101600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.sipStack = sipStack;
102600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
103600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.messageQueue = new LinkedList();
104600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
105600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.port = port;
106600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
107600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.sock = sipStack.getNetworkLayer().createDatagramSocket(port,
108600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    ipAddress);
109600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Create a new datagram socket.
110600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sock.setReceiveBufferSize(sipStack.getReceiveUdpBufferSize());
111600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sock.setSendBufferSize(sipStack.getSendUdpBufferSize());
112600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
113600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            /**
114600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             * If the thread auditor is enabled, define a socket timeout value in order to
115600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             * prevent sock.receive() from blocking forever
116600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             */
117600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipStack.getThreadAuditor().isEnabled()) {
118600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sock.setSoTimeout((int) sipStack.getThreadAuditor().getPingIntervalInMillisecs());
119600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
120600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if ( ipAddress.getHostAddress().equals(IN_ADDR_ANY)  ||
121600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                 ipAddress.getHostAddress().equals(IN6_ADDR_ANY)){
122600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Store the address to which we are actually bound
123600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Note that on WINDOWS this is actually broken. It will
124600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // return IN_ADDR_ANY again. On linux it will return the
125600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // address to which the socket was actually bound.
126600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                super.setIpAddress( sock.getLocalAddress() );
127600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
128600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
129600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } catch (SocketException ex) {
130600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new IOException(ex.getMessage());
131600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
132600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
133600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
134600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
135600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
136600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
137600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get port on which to listen for incoming stuff.
138600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
139600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return port on which I am listening.
140600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
141600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public int getPort() {
142600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.port;
143600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
144600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
145600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
146600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Start our processor thread.
147600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
148600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void start() throws IOException {
149600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
150600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
151600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.isRunning = true;
152600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        Thread thread = new Thread(this);
153600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        thread.setDaemon(true);
154600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Issue #32 on java.net
155600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        thread.setName("UDPMessageProcessorThread");
156600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Issue #184
157600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        thread.setPriority(Thread.MAX_PRIORITY);
158600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        thread.start();
159600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
160600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
161600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
162600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Thread main routine.
163600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
164600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void run() {
165600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Check for running flag.
166600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.messageChannels = new LinkedList();
167600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // start all our messageChannels (unless the thread pool size is
168600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // infinity.
169600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipStack.threadPoolSize != -1) {
170600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            for (int i = 0; i < sipStack.threadPoolSize; i++) {
171600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                UDPMessageChannel channel = new UDPMessageChannel(sipStack,
172600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        this);
173600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.messageChannels.add(channel);
174600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
175600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
176600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
177600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
178600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Ask the auditor to monitor this thread
179600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        ThreadAuditor.ThreadHandle threadHandle = sipStack.getThreadAuditor().addCurrentThread();
180600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
181600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Somebody asked us to exit. if isRunnning is set to false.
182600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        while (this.isRunning) {
183600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
184600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
185600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Let the thread auditor know we're up and running
186600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                threadHandle.ping();
187600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
188600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                int bufsize = sock.getReceiveBufferSize();
189600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                byte message[] = new byte[bufsize];
190600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                DatagramPacket packet = new DatagramPacket(message, bufsize);
191600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sock.receive(packet);
192600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
193600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
194600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
195600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             // This is a simplistic congestion control algorithm.
196600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             // It accepts packets if queuesize is < LOWAT. It drops
197600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             // requests if the queue size exceeds a HIGHWAT and accepts
198600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             // requests with probability p proportional to the difference
199600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             // between current queue size and LOWAT in the range
200600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             // of queue sizes between HIGHWAT and LOWAT.
201600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             // TODO -- penalize spammers by looking at the source
202600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             // port and IP address.
203600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             if ( sipStack.stackDoesCongestionControl ) {
204600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             if ( this.messageQueue.size() >= HIGHWAT) {
205600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (sipStack.isLoggingEnabled()) {
206600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        sipStack.getStackLogger().logDebug("Dropping message -- queue length exceeded");
207600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
208600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
209600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    //System.out.println("HIGHWAT Drop!");
210600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    continue;
211600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else if ( this.messageQueue.size() > LOWAT && this .messageQueue.size() < HIGHWAT ) {
212600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // Drop the message with a probabilty that is linear in the range 0 to 1
213600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    float threshold = ((float)(messageQueue.size() - LOWAT))/ ((float)(HIGHWAT - LOWAT));
214600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    boolean decision = Math.random() > 1.0 - threshold;
215600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if ( decision ) {
216600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        if (sipStack.isLoggingEnabled()) {
217600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            sipStack.getStackLogger().logDebug("Dropping message with probability  " + (1.0 - threshold));
218600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
219600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        }
220600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        //System.out.println("RED Drop!");
221600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        continue;
222600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
223600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
224600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
225600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             }
226600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
227600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
228600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
229600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Count of # of packets in process.
230600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // this.useCount++;
231600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (sipStack.threadPoolSize != -1) {
232600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // Note: the only condition watched for by threads
233600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // synchronizing on the messageQueue member is that it is
234600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // not empty. As soon as you introduce some other
235600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // condition you will have to call notifyAll instead of
236600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // notify below.
237600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
238600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    synchronized (this.messageQueue) {
239600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // was addLast
240600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        this.messageQueue.add(packet);
241600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        this.messageQueue.notify();
242600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
243600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else {
244600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    new UDPMessageChannel(sipStack, this, packet);
245600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
246600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (SocketTimeoutException ex) {
247600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang              // This socket timeout alows us to ping the thread auditor periodically
248600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (SocketException ex) {
249600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (sipStack.isLoggingEnabled())
250600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    getSIPStack().getStackLogger()
251600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            .logDebug("UDPMessageProcessor: Stopping");
252600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                isRunning = false;
253600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // The notifyAll should be in a synchronized block.
254600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // ( bug report by Niklas Uhrberg ).
255600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                synchronized (this.messageQueue) {
256600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.messageQueue.notifyAll();
257600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
258600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (IOException ex) {
259600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                isRunning = false;
260600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                ex.printStackTrace();
261600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (sipStack.isLoggingEnabled())
262600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    getSIPStack().getStackLogger()
263600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            .logDebug("UDPMessageProcessor: Got an IO Exception");
264600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (Exception ex) {
265600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (sipStack.isLoggingEnabled())
266600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    getSIPStack().getStackLogger()
267600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            .logDebug("UDPMessageProcessor: Unexpected Exception - quitting");
268600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                InternalErrorHandler.handleException(ex);
269600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return;
270600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
271600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
272600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
273600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
274600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
275600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Shut down the message processor. Close the socket for recieving incoming
276600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * messages.
277600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
278600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void stop() {
279600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        synchronized (this.messageQueue) {
280600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.isRunning = false;
281600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.messageQueue.notifyAll();
282600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sock.close();
283600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
284600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
285600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
286600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
287600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
288600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
289600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Return the transport string.
290600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
291600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return the transport string
292600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
293600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public String getTransport() {
294600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return "udp";
295600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
296600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
297600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
298600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Returns the stack.
299600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
300600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return my sip stack.
301600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
302600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SIPTransactionStack getSIPStack() {
303600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return sipStack;
304600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
305600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
306600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
307600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Create and return new TCPMessageChannel for the given host/port.
308600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
309600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public MessageChannel createMessageChannel(HostPort targetHostPort)
310600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throws UnknownHostException {
311600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return new UDPMessageChannel(targetHostPort.getInetAddress(),
312600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                targetHostPort.getPort(), sipStack, this);
313600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
314600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
315600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public MessageChannel createMessageChannel(InetAddress host, int port)
316600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throws IOException {
317600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return new UDPMessageChannel(host, port, sipStack, this);
318600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
319600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
320600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
321600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Default target port for UDP
322600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
323600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public int getDefaultTargetPort() {
324600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return 5060;
325600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
326600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
327600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
328600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * UDP is not a secure protocol.
329600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
330600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public boolean isSecure() {
331600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return false;
332600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
333600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
334600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
335600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * UDP can handle a message as large as the MAX_DATAGRAM_SIZE.
336600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
337600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public int getMaximumMessageSize() {
338600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return 8*1024;
339600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
340600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
341600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
342600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Return true if there are any messages in use.
343600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
344600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public boolean inUse() {
345600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        synchronized (messageQueue) {
346600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return messageQueue.size() != 0;
347600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
348600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
349600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
350600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang}
351