001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026: package com.sun.midp.jsr82emul;
027:
028: import java.io.IOException;
029: import java.io.InterruptedIOException;
030: import javax.microedition.io.SocketConnection;
031: import javax.microedition.io.ServerSocketConnection;
032: import javax.microedition.io.Connector;
033: import com.sun.midp.io.BluetoothUrl;
034: import com.sun.midp.io.j2me.serversocket.Socket;
035: import com.sun.midp.security.SecurityToken;
036: import com.sun.midp.security.ImplicitlyTrustedClass;
037: import com.sun.midp.main.Configuration;
038: import com.sun.midp.jsr082.BluetoothUtils;
039: import com.sun.midp.jsr082.SecurityInitializer;
040:
041: /**
042: * Emulates JSR 82 notifier.
043: */
044: public class NotifierEmul implements EmulUnit {
045: /** Integer handle that identifies notifier at native level. */
046: private int handle;
047:
048: /**
049: * Inner class to request security token from SecurityInitializer.
050: * SecurityInitializer should be able to check this inner class name.
051: */
052: static private class SecurityTrusted implements
053: ImplicitlyTrustedClass {
054: };
055:
056: /** Internal security token that grants access to restricted API. */
057: private static SecurityToken internalSecurityToken = SecurityInitializer
058: .requestToken(new SecurityTrusted());
059:
060: /** Device this notifier works at. */
061: DeviceEmul device;
062:
063: /** Server socet to accept connections. */
064: Socket serverSocket;
065:
066: /** next free socket port. */
067: static int nextSocketPort = Configuration.getIntProperty(
068: "com.sun.midp.jsr82emul.serverPort", 1234) + 1;
069:
070: /**
071: * Keeps options of service connection string used for this
072: * notifier creation.
073: */
074: private ServiceConnectionData serviceData;
075:
076: /** PSM or channel id. */
077: int port;
078:
079: /** An emulation of client connection. */
080: private ConnectionEmul clientConnection = null;
081:
082: /** Current connection acceptor, <code>null</code> if there is no one. */
083: Acceptor acceptor = null;
084:
085: /** Represents socket client acception that runs in a separate thread. */
086: private class Acceptor extends RunnableProcessor {
087: /**
088: * Processes acception.
089: * Implementation for abstract method of the superclass.
090: */
091: protected void process() {
092: try {
093: if (serverSocket == null) {
094: // normally it means that interruption is in progress
095: throw new IOException("Improper acceptor state");
096: }
097: SocketConnection sc = (SocketConnection) serverSocket
098: .acceptAndOpen();
099: clientConnection = new ConnectionEmul(serviceData);
100: clientConnection.open(sc);
101: } catch (IOException e) {
102: if (!interrupted) {
103: clientConnection.close();
104: }
105: clientConnection = null;
106: }
107:
108: if (!interrupted) {
109: if (clientConnection == null) {
110: notifyAccepted(handle, -1, null, -1, -1);
111: } else {
112: notifyAccepted(handle, clientConnection.handle,
113: BluetoothUtils
114: .getAddressBytes(clientConnection
115: .getRemoteAddress()),
116: clientConnection.getReceiveMTU(),
117: clientConnection.getTransmitMTU());
118: }
119: }
120: acceptor = null;
121: }
122: }
123:
124: /**
125: * Creates new instance and registers it in emulation environment with
126: * given handle. It is initialized by the next request to emulation.
127: *
128: * @param handle integer handle reserved for the new instance
129: * in native layer.
130: */
131: public NotifierEmul(int handle) {
132: this .handle = handle;
133: // IMPL_NOTE redundant?
134: device = DeviceEmul.getLocalDeviceEmul();
135:
136: // Registering this notifier as a processor for requests to emulation
137: ConnRegistry.getInstance().register(handle, this );
138: }
139:
140: /**
141: * Initializes this notifier emulation unit.
142: *
143: * @param serviceData packed info on service details
144: */
145: public void initialize(ServiceConnectionData serviceData) {
146: this .serviceData = serviceData;
147:
148: serverSocket = new Socket();
149:
150: success: {
151: final int maxTrials = 32;
152: for (int i = 0; i < maxTrials; i++, nextSocketPort++) {
153: try {
154: serverSocket.open(nextSocketPort,
155: internalSecurityToken);
156: } catch (IOException e) {
157: // consider port is busy and just continue trials
158: continue;
159: }
160:
161: serviceData.socketPort = nextSocketPort++;
162: break success;
163: }
164:
165: error();
166: }
167: }
168:
169: /** Rgisters error occued to pass it to code above the porting layer. */
170: private void error() {/*need revisit*/
171: }
172:
173: /**
174: * Starts accepting incoming connection.
175: * IMPL_NOTE it should completely substitute accept() when moving emul
176: * below porting layer completed
177: */
178: public void startAccept() {
179: acceptor = new Acceptor();
180: acceptor.start();
181:
182: try {
183: device.registerService(serviceData);
184:
185: } catch (IOException e) {
186: error();
187: // IMPL_NOTE
188: // add e details;
189: }
190: }
191:
192: /**
193: * Closes the notifier (emulation).
194: * @exception IOException if emulation server does not respond properly
195: */
196: public void close() {
197: if (acceptor != null) {
198: acceptor.interrupt();
199: acceptor = null;
200: }
201:
202: if (serverSocket != null) {
203: try {
204: serverSocket.close();
205: } catch (IOException e) {
206: error();
207: }
208:
209: serverSocket = null;
210: }
211:
212: clientConnection = null;
213:
214: ConnRegistry.getInstance().unregister(handle);
215: if (-1 != serviceData.socketPort) {
216: device.unregisterService(serviceData.socketPort);
217: }
218: }
219:
220: // IMPL_NOTE move to constants.xml
221: /** Accept request code. */
222: private static final byte NOTIF_ACCEPT = 0;
223: /** Close request code. */
224: private static final byte NOTIF_CLOSE = 1;
225: /** Initialize request code. */
226: private static final byte NOTIF_INIT = 2;
227:
228: /**
229: * Processes request from porting layer to emulation.
230: * @param request packed request to process
231: */
232: public void process(BytePack request) {
233: switch (request.extract()) {
234: case NOTIF_ACCEPT:
235: Log.log("processing NOTIF_ACCEPT");
236: startAccept();
237: Log.log("processing NOTIF_ACCEPT done");
238: break;
239: case NOTIF_CLOSE:
240: Log.log("processing NOTIF_CLOSE");
241: close();
242: Log.log("processing NOTIF_CLOSE done");
243: break;
244: case NOTIF_INIT:
245: Log.log("processing NOTIF_INIT");
246: initialize(new ServiceConnectionData(
247: request
248: .extractBytes(ServiceConnectionData.SERVER_DATA_SIZE),
249: ServiceConnectionData.SERVER_DATA));
250: Log.log("processing NOTIF_INIT done");
251: break;
252: default:
253: throw new EmulationException("Unknown Notifier request");
254: }
255: }
256:
257: /**
258: * Notifies porting layer on completing acception.
259: * @param thisHandle
260: * @param connHandle handle connection created as a result of acception,
261: * <code>-1</code> if acception failed.
262: * @param peerAddr bluetooth address of device connected.
263: * @param receiveMTU established ReceiveMTU of accepted connection.
264: * @param transmitMTU established TransmitMTU of accepted connection.
265: *
266: * IMPL_NOTE
267: * peerAddr may become useless when moving emul below porting layer
268: * completed; thisHandle may be retrieved thru KNI
269: *
270: */
271: private native void notifyAccepted(int this Handle, int connHandle,
272: byte[] peerAddr, int receiveMTU, int transmitMTU);
273: }
|