/*
* Portions Copyright 2000-2007 Sun Microsystems, Inc. All Rights
* Reserved. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package gov.nist.siplite.stack;
import java.io.*;
import java.util.Vector;
import javax.microedition.io.*;
import javax.microedition.io.SocketConnection;
import com.sun.midp.log.LogChannels;
import com.sun.midp.log.Logging;
import gov.nist.core.*;
import gov.nist.siplite.SIPConstants;
/**
* TCP Message Processor.
*
* @version 1.0
*/
public class TCPMessageProcessor extends MessageProcessor implements Runnable {
/** Local Port number. */
private int localPort = SIPConstants.DEFAULT_NONTLS_PORT;
/** Inbound server socket connection. */
private ServerSocketConnection serverSocket;
/** Current error socket disabled. */
public boolean ERROR_SOCKET = false;
/* Max size. */
// private static final int MAX_LENGTH = 1000;
/** Our stack (that created us). */
private SIPMessageStack sipStack;
/** Thread of TCP server. */
private Thread incomingHandler;
/** Array of registered message channels. */
private Vector tcpMsgChannels = new Vector();
/**
* Main loop for TCP message handling.
*/
public void run() {
TCPMessageChannel tmc;
try {
while (!exitFlag) {
SocketConnection sock =
(SocketConnection) serverSocket.acceptAndOpen();
if (sock != null) {
tmc = new TCPMessageChannel(sock, sipStack, this);
tcpMsgChannels.addElement(tmc);
}
}
} catch (IOException ex) {
/*
* If IOEXception occurs after main thread closes serversocket,
* ignore it
*/
if (!exitFlag) {
if (Logging.REPORT_LEVEL <= Logging.ERROR) {
Logging.report(Logging.ERROR, LogChannels.LC_JSR180,
"Server socket exception. "+
"Shutting down of incoming handler thread!");
}
}
}
}
/**
* Gets the SIP stack context.
* @return the currenit SIP stack
*/
public SIPMessageStack getSIPStack() {
return sipStack;
}
/**
* Creates new TCPMessageProcessor.
* @param ss the current SIP stack context
* @param lp Local port number for messages
*/
public TCPMessageProcessor(SIPMessageStack ss, int lp) {
sipStack = ss;
localPort = lp;
}
/**
* Gets the transport string.
* @return A string that indicates the transport.
* (i.e. "tcp" or "udp")
*/
public String getTransport() {
return SIPConstants.TRANSPORT_TCP;
}
/**
* Gets the local port identifier.
* @return the port for this message processor.
*/
public int getPort() {
return localPort;
}
/**
* Gets the SIP Stack.
* @return the sip stack.
*/
public SIPMessageStack getSipStack() {
return sipStack;
}
/**
* Creates and return new TCPMessageChannel for the given host/port.
* @param targetHostPort target host and port address
* @return a new message channel
*/
public MessageChannel createMessageChannel(HostPort targetHostPort)
throws IOException {
TCPMessageChannel tmc;
synchronized (tcpMsgChannels) {
for (int i = 0; i < tcpMsgChannels.size(); i++) {
tmc = ((TCPMessageChannel)tcpMsgChannels.elementAt(i));
if (tmc.getPeerHostPort().equals(targetHostPort)) {
tmc.incrementUseCounter();
return tmc;
}
}
}
tmc = new TCPMessageChannel(targetHostPort, sipStack, this);
tcpMsgChannels.addElement(tmc);
return tmc;
}
/**
* Checks if the currenttransport is secure channel
* @return always false
*/
public boolean isSecure() {
return false;
}
/**
* Starts our thread.
* @exception IOException if the connection failed
*/
synchronized public void start() throws IOException {
/*
* Original NIST method for opening the serversocket connection
* has been replaced by direct calls to instantiate the protocol
* handler, in order to pass the security token for use of lower
* level transport connection.
* Original NIST sequence is :
*
* serverSocket = (ServerSocketConnection)
* Connector.open("socket://:"+getPort());
*/
com.sun.midp.io.j2me.socket.Protocol conn =
new com.sun.midp.io.j2me.socket.Protocol();
serverSocket = (ServerSocketConnection)conn.openPrim(
sipStack.getSecurityToken(), "//:" + localPort);
// A serversocket needs to be created to handle incoming data.
// This part of the code is used while creating
// a SipConnectionNotifier with TCP transport
//
// Also under error conditions, the server may attempt to open
// a new connection to send the response. To handle this case,
// the transport layer MUST also be prepared to receive
// an incoming connection on the source IP address from which
// the request was sent and port number in
// the "sent-by" field (RFC3261, p.143)
incomingHandler = new Thread(this);
incomingHandler.start();
}
/**
* Stops the current processor.
*/
synchronized public void stop() {
try {
exitFlag = true;
if (serverSocket != null) {
serverSocket.close();
try {
incomingHandler.join();
} catch (InterruptedException exc) {
// ignore
}
serverSocket = null;
}
Object[] arr;
synchronized (tcpMsgChannels) {
arr = new Object[tcpMsgChannels.size()];
tcpMsgChannels.copyInto(arr);
}
TCPMessageChannel tmc;
for (int i = 0; i < arr.length; i++) {
tmc = (TCPMessageChannel)arr[i];
tmc.exit();
}
} catch (IOException ex) {
if (Logging.REPORT_LEVEL <= Logging.ERROR) {
Logging.report(Logging.ERROR, LogChannels.LC_JSR180,
"SYSTEM, TCPMessageProcessor, stop(), " +
"exception raised: " + ex);
}
}
}
/**
* Notification about message channel shutting down.
* Now it cat be removed from registration vector.
* @param tmc channel that was closed
*/
public void notifyClose(TCPMessageChannel tmc) {
tcpMsgChannels.removeElement(tmc);
}
}
|