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.kvem.jsr082.obex;
027:
028: import javax.obex.Authenticator;
029: import javax.obex.ServerRequestHandler;
030: import javax.obex.ResponseCodes;
031: import javax.obex.HeaderSet;
032: import java.io.IOException;
033: import javax.microedition.io.Connection;
034:
035: class ServerConnectionImpl extends ObexPacketStream implements
036: Connection, Runnable {
037:
038: /** Debug information, should be false for RR. */
039: private static final boolean DEBUG = false;
040:
041: ServerRequestHandler handler;
042:
043: private int owner;
044: private boolean isConnected;
045:
046: private long connId;
047:
048: /** Current operation header size overflow flag. */
049: boolean operationHeadersOverflow = false;
050:
051: /** Current operation state. */
052: boolean operationClosed;
053:
054: void headerTooLarge() throws IOException {
055: operationHeadersOverflow = true;
056: operationClosed = true;
057: }
058:
059: ServerConnectionImpl(ObexTransport transport,
060: ServerRequestHandler handler, Authenticator auth)
061: throws IOException {
062: super (transport);
063: this .handler = handler;
064: isClient = false;
065: authenticator = auth;
066:
067: // owner field of all created HeaderSets
068: owner = HeaderSetImpl.OWNER_SERVER;
069: new Thread(this ).start();
070: }
071:
072: public void run() {
073: try {
074: while (processRequest()) {
075: // if connection closed
076: if (isClosed()) {
077: break;
078: }
079: }
080: } catch (Throwable t) {
081: if (DEBUG) {
082: System.out
083: .println("ServerConnectionImpl thread exception");
084: t.printStackTrace();
085: }
086: }
087: if (DEBUG) {
088: System.out
089: .println("ServerConnectionImpl: client disconnected");
090: }
091: close();
092: }
093:
094: /**
095: * Modified sendPacket() function.
096: * If packet is too large - sends OBEX_HTTP_REQ_TOO_LARGE response.
097: */
098: private int sendResponsePacket(byte[] head, HeaderSetImpl headers)
099: throws IOException {
100: int status = head[0] & 0xFF;
101: packetBegin(head);
102: packetAddConnectionID(getConnectionID(), headers);
103: packetAddAuthResponses();
104: packetAddHeaders(headers);
105: if (!queuedHeaders.isEmpty() || operationHeadersOverflow) {
106: queuedHeaders.removeAllElements();
107: setPacketType(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE);
108: }
109: packetEnd();
110: return status;
111: }
112:
113: private void doConnect() throws IOException {
114: // NOTE client may not authenticated the server and wants to
115: // so allow multiple connect requests
116: HeaderSetImpl inputHeaderSet = new HeaderSetImpl(owner);
117: HeaderSetImpl responseHeaderSet = new HeaderSetImpl(owner);
118:
119: // server side check
120: if (buffer[3] != 0x10 || packetLength < 7) {
121: // IMPL_NOTE: It is not decided what to do if the OBEX version number
122: // is different from the one we support (which is presumably 1.0).
123: // Windows uses version 1.2, Linux uses version 1.1, and we
124: // probably want to work with both.
125: // throw new IOException("unsupported client obex version");
126: }
127: // ignore flags
128: // save maximum client supported packet size
129: maxSendLength = decodeLength16(5);
130:
131: if (maxSendLength > OBEX_MAXIMUM_PACKET_LENGTH) {
132: maxSendLength = OBEX_MAXIMUM_PACKET_LENGTH;
133: }
134: parsePacketHeaders(inputHeaderSet, 7);
135: // processMissingAuthentications();
136:
137: int status = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
138:
139: try {
140: status = handler.onConnect(inputHeaderSet,
141: responseHeaderSet);
142: } catch (Throwable t) {
143: t.printStackTrace();
144: }
145: status = validateStatus(status);
146:
147: if (status != ResponseCodes.OBEX_HTTP_OK) {
148: // lets client will authenticate first
149: authResponses.removeAllElements();
150: }
151:
152: byte[] head = new byte[] { (byte) status, 0, 0, // length will be here
153: 0x10, // version 1.0 of OBEX
154: 0x0, // flags
155: (byte) (OBEX_MAXIMUM_PACKET_LENGTH / 0x100), // maximum client
156: (byte) (OBEX_MAXIMUM_PACKET_LENGTH % 0x100), // supported packet
157: // length
158: };
159:
160: status = sendResponsePacket(head, responseHeaderSet);
161:
162: if (status == ResponseCodes.OBEX_HTTP_OK) {
163: isConnected = true;
164: }
165: }
166:
167: private boolean notConnected() throws IOException {
168: if (!isConnected) {
169: HeaderSetImpl headers = new HeaderSetImpl(owner);
170: headers.setHeader(HeaderSet.DESCRIPTION, "not connected");
171: sendPacket(PACKET_BAD_REQUEST, getConnectionID(), headers,
172: true);
173: return true;
174: }
175: return false;
176: }
177:
178: void onAuthenticationFailure(byte[] username) throws IOException {
179: try {
180: if (DEBUG) {
181: System.out.println("ServerConnectionImpl:"
182: + " handler.onAuthenticationFailure()");
183: }
184: handler.onAuthenticationFailure(username);
185: } catch (Throwable t) {
186: t.printStackTrace();
187: }
188: operationClosed = true;
189: }
190:
191: private void doDisconnect() throws IOException {
192: if (notConnected()) {
193: return;
194: }
195: HeaderSetImpl inputHeaderSet = new HeaderSetImpl(owner);
196: HeaderSetImpl responseHeaderSet = new HeaderSetImpl(owner);
197:
198: parsePacketHeaders(inputHeaderSet, 3);
199: // processMissingAuthentications();
200:
201: try {
202: handler.onDisconnect(inputHeaderSet, responseHeaderSet);
203: } catch (Throwable t) {
204: t.printStackTrace();
205: }
206: byte[] head = new byte[] { (byte) ResponseCodes.OBEX_HTTP_OK,
207: 0, 0, // length will be here
208: };
209:
210: int status = sendResponsePacket(head, responseHeaderSet);
211:
212: if (status == ResponseCodes.OBEX_HTTP_OK) {
213: isConnected = false;
214: }
215: }
216:
217: private void doPut(HeaderSetImpl inputHeaderSet) throws IOException {
218: int status = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
219: ServerOperation op = new ServerOperation(this , inputHeaderSet);
220: try {
221: status = handler.onPut(op);
222: } catch (Throwable t) {
223: t.printStackTrace();
224: }
225: status = validateStatus(status);
226: if (operationHeadersOverflow) {
227: status = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
228: }
229: op.destroy(status);
230: }
231:
232: private void doDelete(HeaderSetImpl inputHeaderSet)
233: throws IOException {
234: HeaderSetImpl responseHeaderSet = new HeaderSetImpl(owner);
235: int status = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
236: try {
237: status = handler
238: .onDelete(inputHeaderSet, responseHeaderSet);
239: } catch (Throwable t) {
240: t.printStackTrace();
241: }
242: status = validateStatus(status);
243: byte[] head = new byte[] { (byte) status, 0, 0, // length will be here
244: };
245:
246: sendResponsePacket(head, responseHeaderSet);
247: }
248:
249: private void doPutOrDelete() throws IOException {
250: if (notConnected()) {
251: return;
252: }
253: HeaderSetImpl inputHeaderSet = new HeaderSetImpl(owner);
254:
255: int mode = ServerOperation.waitForData(this , inputHeaderSet,
256: OPCODE_PUT);
257:
258: switch (mode) {
259: case 0:
260: sendPacket(PACKET_SUCCESS, getConnectionID(), null, true);
261: return;
262: case 1:
263: doPut(inputHeaderSet);
264: return;
265: case 2:
266: doDelete(inputHeaderSet);
267: return;
268: default:
269: return;
270: }
271: }
272:
273: private void doGet() throws IOException {
274: if (notConnected()) {
275: return;
276: }
277: int status = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
278: ServerOperation op = new ServerOperation(this );
279: try {
280: status = handler.onGet(op);
281: } catch (Throwable t) {
282: t.printStackTrace();
283: }
284: status = validateStatus(status);
285: if (operationHeadersOverflow) {
286: status = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
287: }
288: op.destroy(status);
289: }
290:
291: private void doSetPath() throws IOException {
292: if (notConnected()) {
293: return;
294: }
295: HeaderSetImpl inputHeaderSet = new HeaderSetImpl(owner);
296: HeaderSetImpl responseHeaderSet = new HeaderSetImpl(owner);
297:
298: // check flags
299: boolean create = ((buffer[3] & 2) == 0);
300: boolean backup = ((buffer[3] & 1) == 1);
301:
302: parsePacketHeaders(inputHeaderSet, 5);
303: // processMissingAuthentications();
304: int status = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
305: try {
306: status = handler.onSetPath(inputHeaderSet,
307: responseHeaderSet, backup, create);
308: } catch (Throwable t) {
309: t.printStackTrace();
310: }
311: status = validateStatus(status);
312: byte[] head = new byte[] { (byte) status, 0, 0, // length will be here
313: };
314: sendResponsePacket(head, responseHeaderSet);
315: }
316:
317: /**
318: * Process one client request
319: * @return false when connection closed
320: */
321: private boolean processRequest() throws IOException {
322: try {
323: recvPacket();
324: } catch (IOException e) {
325: return false;
326: }
327: HeaderSetImpl inputHeaderSet = new HeaderSetImpl(owner);
328: operationHeadersOverflow = false;
329: operationClosed = false;
330: isEof = false;
331:
332: switch (packetType) {
333: case OPCODE_CONNECT:
334: doConnect();
335: break;
336:
337: case OPCODE_DISCONNECT:
338: doDisconnect();
339: break;
340:
341: case OPCODE_PUT:
342: case OPCODE_PUT | OPCODE_FINAL:
343: doPutOrDelete();
344: break;
345:
346: case OPCODE_GET:
347: case OPCODE_GET | OPCODE_FINAL:
348: doGet();
349: break;
350: case OPCODE_SETPATH:
351: doSetPath();
352: break;
353:
354: case OPCODE_ABORT:
355: // ignore abort, it is too late, any of the operations is
356: // finished
357: byte[] head = new byte[] {
358: (byte) ResponseCodes.OBEX_HTTP_OK, 0, 0, // length will be here
359: };
360: sendResponsePacket(head, null);
361: break;
362:
363: default:
364: // wrong packet received, ignoring
365: if (DEBUG) {
366: System.out.println("Wrong packet: id = "
367: + inputHeaderSet.packetType + " length = "
368: + packetLength);
369: }
370: sendPacket(PACKET_NOT_IMPLEMENTED, getConnectionID(), null,
371: true);
372: }
373: return true;
374: }
375:
376: public void setConnectionID(long id) {
377: try { // may by overloaded by user and throw exception
378: connId = id;
379: handler.setConnectionID(id);
380: } catch (Throwable e) {
381: // nothing
382: }
383: }
384:
385: public long getConnectionID() {
386: try { // may by overloaded by user and throw exception
387: long id = handler.getConnectionID();
388: if (connId == id) {
389: return -1;
390: }
391: connId = id;
392: return id;
393: } catch (Throwable e) {
394: return -1;
395: }
396: }
397: }
|