View Javadoc

1   /**
2    *  BlueCove - Java library for Bluetooth
3    *  Copyright (C) 2008 Michael Lifshits
4    *  Copyright (C) 2008 Vlad Skarzhevskyy
5    *
6    *  Licensed to the Apache Software Foundation (ASF) under one
7    *  or more contributor license agreements.  See the NOTICE file
8    *  distributed with this work for additional information
9    *  regarding copyright ownership.  The ASF licenses this file
10   *  to you under the Apache License, Version 2.0 (the
11   *  "License"); you may not use this file except in compliance
12   *  with the License.  You may obtain a copy of the License at
13   *
14   *    http://www.apache.org/licenses/LICENSE-2.0
15   *
16   *  Unless required by applicable law or agreed to in writing,
17   *  software distributed under the License is distributed on an
18   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
19   *  KIND, either express or implied.  See the License for the
20   *  specific language governing permissions and limitations
21   *  under the License.
22   *
23   *  @author vlads
24   *  @version $Id: ServiceListener.java 2599 2008-12-16 21:34:57Z skarzhevskyy $
25   */
26  package com.intel.bluetooth.emu;
27  
28  import java.io.IOException;
29  import java.io.InterruptedIOException;
30  
31  import javax.bluetooth.BluetoothConnectionException;
32  
33  import com.intel.bluetooth.DebugLog;
34  import com.intel.bluetooth.RemoteDeviceHelper;
35  import com.intel.bluetooth.Utils;
36  
37  /**
38   * 
39   */
40  class ServiceListener {
41  
42  	private static final String RFCOMM_PREFIX = "rfcomm-";
43  
44  	private static final String L2CAP_PREFIX = "l2cap-";
45  
46  	private final String portID;
47  
48  	private boolean rfcomm;
49  
50  	private Object lock = new Object();
51  
52  	private Device serverDevice;
53  
54  	private static long connectionCount = 0;
55  
56  	private boolean connected = false;
57  
58  	private boolean closed = false;
59  
60  	private boolean interrupted = false;
61  
62  	private long connectionId = 0;
63  
64  	private int serverSecurityOpt;
65  
66  	private int serverReceiveMTU;
67  
68  	static String rfPrefix(int channel) {
69  		return RFCOMM_PREFIX + channel;
70  	}
71  
72  	static String l2Prefix(int pcm) {
73  		return L2CAP_PREFIX + Integer.toHexString(pcm);
74  	}
75  
76  	ServiceListener(String portID) {
77  		this.portID = portID;
78  		this.rfcomm = this.portID.startsWith(RFCOMM_PREFIX);
79  	}
80  
81  	String getPortID() {
82  		return this.portID;
83  	}
84  
85  	long accept(Device serverDevice, boolean authenticate, boolean encrypt, int serverReceiveMTU) throws IOException {
86  		this.serverDevice = serverDevice;
87  		this.serverReceiveMTU = serverReceiveMTU;
88  		this.serverSecurityOpt = Utils.securityOpt(authenticate, encrypt);
89  
90  		serverDevice.serviceListenerAccepting(getPortID());
91  		while ((!closed) && (!interrupted) && (!connected)) {
92  			synchronized (lock) {
93  				try {
94  					lock.wait();
95  				} catch (InterruptedException e) {
96  					throw new InterruptedIOException("accept interrupted");
97  				}
98  			}
99  		}
100 		if (closed || interrupted || !connected) {
101 			throw new InterruptedIOException("accept closed");
102 		}
103 		return connectionId;
104 	}
105 
106 	long connect(Device clientDevice, boolean authenticate, boolean encrypt, int cilentReceiveMTU, long timeout)
107 			throws IOException {
108 		ConnectionBuffer cb = null;
109 		boolean clientConnected = false;
110 		try {
111 			int securityOpt = Utils.securityOpt(authenticate, encrypt);
112 			if (this.serverSecurityOpt > securityOpt) {
113 				securityOpt = this.serverSecurityOpt;
114 			}
115 
116 			int bsize = DeviceManagerServiceImpl.configuration.getConnectionBufferSize();
117 			boolean senderFlushBlock = DeviceManagerServiceImpl.configuration.isSenderFlushBlock();
118 			ConnectedInputStream cis = new ConnectedInputStream(bsize, senderFlushBlock);
119 			ConnectedOutputStream sos = new ConnectedOutputStream(cis);
120 
121 			ConnectedInputStream sis = new ConnectedInputStream(bsize, senderFlushBlock);
122 			ConnectedOutputStream cos = new ConnectedOutputStream(sis);
123 
124 			ConnectionBuffer sb;
125 			if (this.rfcomm) {
126 				cb = new ConnectionBufferRFCOMM(serverDevice.getDescriptor().getAddress(), getPortID(), cis, cos);
127 				sb = new ConnectionBufferRFCOMM(clientDevice.getDescriptor().getAddress(), getPortID(), sis, sos);
128 			} else {
129 				cb = new ConnectionBufferL2CAP(serverDevice.getDescriptor().getAddress(), getPortID(), cis, cos,
130 						this.serverReceiveMTU);
131 				sb = new ConnectionBufferL2CAP(clientDevice.getDescriptor().getAddress(), getPortID(), sis, sos,
132 						cilentReceiveMTU);
133 			}
134 			cb.connect(sb);
135 			cb.setSecurityOpt(securityOpt);
136 			sb.setSecurityOpt(securityOpt);
137 
138 			sb.setServerSide(true);
139 
140 			long id;
141 			synchronized (ServiceListener.class) {
142 				connectionCount++;
143 				id = connectionCount;
144 			}
145 			MonitorConnection monitor = new MonitorConnection(clientDevice.getDescriptor().getAddress(), serverDevice
146 					.getDescriptor().getAddress(), getPortID(), id);
147 			cb.setMonitor(monitor.getClientBuffer());
148 			sb.setMonitor(monitor.getServerBuffer());
149 
150 			serverDevice.addConnectionBuffer(id, sb);
151 			connectionId = id;
152 			connected = true;
153 			synchronized (lock) {
154 				lock.notifyAll();
155 			}
156 			long endOfDellay = System.currentTimeMillis() + timeout;
157 			while ((!sb.isServerAccepted()) && (!sb.isClosed())) {
158 				long timeleft = endOfDellay - System.currentTimeMillis();
159 				if (timeleft <= 0) {
160 					throw new BluetoothConnectionException(BluetoothConnectionException.TIMEOUT, "Service "
161 							+ getPortID() + " not ready");
162 				}
163 				synchronized (sb) {
164 					try {
165 						sb.wait(timeleft);
166 					} catch (InterruptedException e) {
167 						throw new InterruptedIOException();
168 					}
169 				}
170 			}
171 			if (!sb.isServerAccepted()) {
172 				throw new BluetoothConnectionException(BluetoothConnectionException.FAILED_NOINFO,
173 						"Connection rejected");
174 			}
175 
176 			MonitoringServiceImpl.registerConnection(monitor);
177 			clientDevice.addConnectionBuffer(id, cb);
178 			clientConnected = true;
179 
180 			StringBuffer logMsg = new StringBuffer();
181 			logMsg.append(RemoteDeviceHelper.getBluetoothAddress(clientDevice.getDescriptor().getAddress()));
182 			logMsg.append(" connected to ");
183 			logMsg.append(RemoteDeviceHelper.getBluetoothAddress(serverDevice.getDescriptor().getAddress()));
184 			logMsg.append(" ").append(this.getPortID());
185 			DebugLog.debug(logMsg.toString());
186 
187 			return id;
188 		} finally {
189 			if (!connected) {
190 				interrupted = true;
191 			}
192 			if (!clientConnected) {
193 				cb.close();
194 			}
195 			synchronized (lock) {
196 				lock.notifyAll();
197 			}
198 		}
199 	}
200 
201 	void close() {
202 		closed = true;
203 		synchronized (lock) {
204 			lock.notifyAll();
205 		}
206 	}
207 }