001: /*
002: * Portions Copyright 2000-2007 Sun Microsystems, Inc. All Rights
003: * Reserved. Use is subject to license terms.
004: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU General Public License version
008: * 2 only, as published by the Free Software Foundation.
009: *
010: * This program is distributed in the hope that it will be useful, but
011: * WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * General Public License version 2 for more details (a copy is
014: * included at /legal/license.txt).
015: *
016: * You should have received a copy of the GNU General Public License
017: * version 2 along with this work; if not, write to the Free Software
018: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
019: * 02110-1301 USA
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
022: * Clara, CA 95054 or visit www.sun.com if you need additional
023: * information or have any questions.
024: */
025: package gov.nist.siplite.stack;
026:
027: import java.io.*;
028: import java.util.Vector;
029:
030: import javax.microedition.io.*;
031: import javax.microedition.io.SocketConnection;
032:
033: import com.sun.midp.log.LogChannels;
034: import com.sun.midp.log.Logging;
035:
036: import gov.nist.core.*;
037: import gov.nist.siplite.SIPConstants;
038:
039: /**
040: * TCP Message Processor.
041: *
042: * @version 1.0
043: */
044: public class TCPMessageProcessor extends MessageProcessor implements
045: Runnable {
046: /** Local Port number. */
047: private int localPort = SIPConstants.DEFAULT_NONTLS_PORT;
048: /** Inbound server socket connection. */
049: private ServerSocketConnection serverSocket;
050: /** Current error socket disabled. */
051: public boolean ERROR_SOCKET = false;
052: /* Max size. */
053: // private static final int MAX_LENGTH = 1000;
054: /** Our stack (that created us). */
055: private SIPMessageStack sipStack;
056: /** Thread of TCP server. */
057: private Thread incomingHandler;
058: /** Array of registered message channels. */
059: private Vector tcpMsgChannels = new Vector();
060:
061: /**
062: * Main loop for TCP message handling.
063: */
064: public void run() {
065: TCPMessageChannel tmc;
066: try {
067: while (!exitFlag) {
068: SocketConnection sock = (SocketConnection) serverSocket
069: .acceptAndOpen();
070: if (sock != null) {
071: tmc = new TCPMessageChannel(sock, sipStack, this );
072: tcpMsgChannels.addElement(tmc);
073: }
074: }
075: } catch (IOException ex) {
076: /*
077: * If IOEXception occurs after main thread closes serversocket,
078: * ignore it
079: */
080: if (!exitFlag) {
081: if (Logging.REPORT_LEVEL <= Logging.ERROR) {
082: Logging
083: .report(
084: Logging.ERROR,
085: LogChannels.LC_JSR180,
086: "Server socket exception. "
087: + "Shutting down of incoming handler thread!");
088: }
089: }
090: }
091: }
092:
093: /**
094: * Gets the SIP stack context.
095: * @return the currenit SIP stack
096: */
097: public SIPMessageStack getSIPStack() {
098: return sipStack;
099: }
100:
101: /**
102: * Creates new TCPMessageProcessor.
103: * @param ss the current SIP stack context
104: * @param lp Local port number for messages
105: */
106: public TCPMessageProcessor(SIPMessageStack ss, int lp) {
107: sipStack = ss;
108: localPort = lp;
109: }
110:
111: /**
112: * Gets the transport string.
113: * @return A string that indicates the transport.
114: * (i.e. "tcp" or "udp")
115: */
116: public String getTransport() {
117: return SIPConstants.TRANSPORT_TCP;
118: }
119:
120: /**
121: * Gets the local port identifier.
122: * @return the port for this message processor.
123: */
124: public int getPort() {
125: return localPort;
126: }
127:
128: /**
129: * Gets the SIP Stack.
130: * @return the sip stack.
131: */
132: public SIPMessageStack getSipStack() {
133: return sipStack;
134: }
135:
136: /**
137: * Creates and return new TCPMessageChannel for the given host/port.
138: * @param targetHostPort target host and port address
139: * @return a new message channel
140: */
141:
142: public MessageChannel createMessageChannel(HostPort targetHostPort)
143: throws IOException {
144: TCPMessageChannel tmc;
145: synchronized (tcpMsgChannels) {
146: for (int i = 0; i < tcpMsgChannels.size(); i++) {
147: tmc = ((TCPMessageChannel) tcpMsgChannels.elementAt(i));
148: if (tmc.getPeerHostPort().equals(targetHostPort)) {
149: tmc.incrementUseCounter();
150: return tmc;
151: }
152: }
153: }
154: tmc = new TCPMessageChannel(targetHostPort, sipStack, this );
155: tcpMsgChannels.addElement(tmc);
156: return tmc;
157: }
158:
159: /**
160: * Checks if the currenttransport is secure channel
161: * @return always false
162: */
163: public boolean isSecure() {
164: return false;
165: }
166:
167: /**
168: * Starts our thread.
169: * @exception IOException if the connection failed
170: */
171: synchronized public void start() throws IOException {
172: /*
173: * Original NIST method for opening the serversocket connection
174: * has been replaced by direct calls to instantiate the protocol
175: * handler, in order to pass the security token for use of lower
176: * level transport connection.
177: * Original NIST sequence is :
178: *
179: * serverSocket = (ServerSocketConnection)
180: * Connector.open("socket://:"+getPort());
181: */
182: com.sun.midp.io.j2me.socket.Protocol conn = new com.sun.midp.io.j2me.socket.Protocol();
183:
184: serverSocket = (ServerSocketConnection) conn.openPrim(sipStack
185: .getSecurityToken(), "//:" + localPort);
186:
187: // A serversocket needs to be created to handle incoming data.
188: // This part of the code is used while creating
189: // a SipConnectionNotifier with TCP transport
190: //
191: // Also under error conditions, the server may attempt to open
192: // a new connection to send the response. To handle this case,
193: // the transport layer MUST also be prepared to receive
194: // an incoming connection on the source IP address from which
195: // the request was sent and port number in
196: // the "sent-by" field (RFC3261, p.143)
197: incomingHandler = new Thread(this );
198: incomingHandler.start();
199: }
200:
201: /**
202: * Stops the current processor.
203: */
204: synchronized public void stop() {
205: try {
206: exitFlag = true;
207: if (serverSocket != null) {
208: serverSocket.close();
209: try {
210: incomingHandler.join();
211: } catch (InterruptedException exc) {
212: // ignore
213: }
214: serverSocket = null;
215: }
216: Object[] arr;
217: synchronized (tcpMsgChannels) {
218: arr = new Object[tcpMsgChannels.size()];
219: tcpMsgChannels.copyInto(arr);
220: }
221: TCPMessageChannel tmc;
222: for (int i = 0; i < arr.length; i++) {
223: tmc = (TCPMessageChannel) arr[i];
224: tmc.exit();
225: }
226: } catch (IOException ex) {
227: if (Logging.REPORT_LEVEL <= Logging.ERROR) {
228: Logging.report(Logging.ERROR, LogChannels.LC_JSR180,
229: "SYSTEM, TCPMessageProcessor, stop(), "
230: + "exception raised: " + ex);
231: }
232: }
233: }
234:
235: /**
236: * Notification about message channel shutting down.
237: * Now it cat be removed from registration vector.
238: * @param tmc channel that was closed
239: */
240: public void notifyClose(TCPMessageChannel tmc) {
241: tcpMsgChannels.removeElement(tmc);
242: }
243: }
|