summaryrefslogtreecommitdiff
path: root/noncore/settings/networksettings2/opietooth2/OTPeer.cpp
Unidiff
Diffstat (limited to 'noncore/settings/networksettings2/opietooth2/OTPeer.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/settings/networksettings2/opietooth2/OTPeer.cpp366
1 files changed, 366 insertions, 0 deletions
diff --git a/noncore/settings/networksettings2/opietooth2/OTPeer.cpp b/noncore/settings/networksettings2/opietooth2/OTPeer.cpp
new file mode 100644
index 0000000..0d7e943
--- a/dev/null
+++ b/noncore/settings/networksettings2/opietooth2/OTPeer.cpp
@@ -0,0 +1,366 @@
1//-*-c++-*-
2/***************************************************************************
3 * Copyright (C) 2003 by Fred Schaettgen *
4 * kdebluetooth@schaettgen.de *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 ***************************************************************************/
11
12#include <assert.h>
13#include <sys/poll.h>
14#include <string.h>
15
16#include <bluezlib.h>
17#include <qarray.h>
18#include <qtextstream.h>
19
20#include <opie2/odebug.h>
21
22#include <OTDeviceAddress.h>
23#include <OTSDPAttribute.h>
24#include <OTSDPService.h>
25#include <OTPeer.h>
26#include <OTGateway.h>
27#include <OTDriver.h>
28
29using namespace Opietooth2;
30
31OTPeer::OTPeer( OTGateway * _OT ) {
32 OT = _OT;
33 State = Peer_Unknown;
34 ConnectedTo = 0;
35}
36
37OTPeer::OTPeer( QTextStream & TS, OTGateway * _OT ) {
38 OT = _OT;
39 State = Peer_Unknown;
40 ConnectedTo = 0;
41
42 load( TS );
43}
44
45OTPeer::~OTPeer( ) {
46
47}
48
49void OTPeer::updateServices( void ) {
50 sdp_session_t *session;
51
52 serviceList.clear();
53
54 owarn << "Get services from " << Addr.toString() << oendl;
55
56 session = sdp_connect( &(OTDeviceAddress::any.getBDAddr()),
57 &(Addr.getBDAddr()),
58 0);
59
60 if (!session) {
61 owarn << "sdp_connect("
62 << Addr.toString()
63 << ") failed"
64 << oendl;
65 return; // error
66 }
67
68 uint32_t range = 0x0000ffff;
69 sdp_list_t* attrId = sdp_list_append(0, &range);
70
71 // search all public features
72 uuid_t grp;
73 sdp_uuid16_create( &grp, PUBLIC_BROWSE_GROUP );
74 sdp_list_t * search = sdp_list_append(0, &grp );
75
76 // get data from peer
77 sdp_list_t* seq;
78 if (sdp_service_search_attr_req( session,
79 search,
80 SDP_ATTR_REQ_RANGE,
81 attrId,
82 &seq ) ) {
83 owarn << "Service Search failed" << oendl;
84 sdp_close(session);
85 return;
86 }
87
88 sdp_list_free(attrId, 0);
89 sdp_list_free(search, 0);
90
91 // process result
92 sdp_list_t* next = NULL;
93
94 for (; seq; seq = next) {
95 sdp_record_t *rec = (sdp_record_t *) seq->data;
96
97 sdp_list_t* attrlist = rec->attrlist;
98 AttributeVector alist;
99 OTSDPService * service;
100
101 service = new OTSDPService();
102
103 for (; attrlist; attrlist = attrlist->next) {
104 int attrID = ((sdp_data_t*)(attrlist->data))->attrId;
105 service->addAttribute(
106 attrID,
107 new OTSDPAttribute( (sdp_data_t*)(attrlist->data) )
108 );
109 }
110
111 serviceList.resize( serviceList.size() + 1 );
112 serviceList.insert( serviceList.size() - 1, service );
113
114 next = seq->next;
115 free(seq);
116 sdp_record_free(rec);
117 }
118 sdp_close(session);
119}
120
121bool OTPeer::hasServiceClassID( const OTUUID & uuid) {
122 for( unsigned int i = 0;
123 i < serviceList.count();
124 i ++ ) {
125 if( serviceList[i]->hasClassID(uuid))
126 return true;
127 }
128 return false;
129}
130/** Get a vector of Rfcomm channels of the services having "uuid" in the class ID List*/
131QArray<int> OTPeer::rfcommList( const OTUUID & uuid) {
132
133 QArray<int> rfcommList;
134 unsigned int channel;
135
136 for( unsigned int i = 0;
137 i < serviceList.count();
138 i ++ ) {
139 if( serviceList[i]->hasClassID(uuid)) {
140 if( serviceList[i]->rfcommChannel(channel) ) {
141 rfcommList.resize( rfcommList.size()+1 );
142 rfcommList[rfcommList.size()-1] = channel;
143 }
144 }
145 }
146 return rfcommList;
147}
148
149void OTPeer::save( QTextStream & TS ) {
150 TS << "bdaddr " << address().toString() << endl;
151 TS << "name " << name() << endl;
152 TS << "class " << deviceClass() << endl;
153}
154
155void OTPeer::load( QTextStream & TS ) {
156 QString S;
157 S = TS.readLine();
158 setAddress( OTDeviceAddress( S.mid( 7 ) ) );
159
160 S = TS.readLine();
161 setName( S.mid( 5 ) );
162
163 S = TS.readLine();
164 setDeviceClass( S.mid( 6 ).toLong() );
165}
166
167#define MAGICNR -99999
168#define POLLDELAY 1000
169#define PREMAGICNR (MAGICNR+POLLDELAY)
170
171void OTPeer::findOutState( int timeoutInSec, bool Force ) {
172 ProbeFD = -1;
173 if( Force && ConnectedTo == 0 ) {
174 State = OTPeer::Peer_Unknown;
175 } // else keep state or is connected to us
176
177 if( State == OTPeer::Peer_Unknown ) {
178 ProbePhase = 0;
179 ProbeTimeout = timeoutInSec*1000;
180 owarn << "Ping " << address().toString() << oendl;
181 startTimer( POLLDELAY );
182 } else {
183 ProbeTimeout = 0;
184 startTimer( 0 );
185 }
186}
187
188#define PINGSIZE 20
189void OTPeer::timerEvent( QTimerEvent * ev ) {
190
191 ProbeTimeout -= POLLDELAY;
192
193 if( State == OTPeer::Peer_Unknown ) {
194 switch( ProbePhase ) {
195 case 0 : // connect nonblock
196 { struct sockaddr_l2 addr;
197
198 if (( ProbeFD = ::socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP)) < 0) {
199 ProbeTimeout = 0;
200 break;
201 }
202
203 memset(&addr, 0, sizeof(addr));
204
205 addr.l2_family = AF_BLUETOOTH;
206 addr.l2_bdaddr = OTDeviceAddress::any.getBDAddr();
207
208 if( ::bind( ProbeFD, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
209 ProbeTimeout = 0;
210 break;
211 }
212
213 // non blocking
214 if( ::fcntl( ProbeFD, F_SETFL, O_NONBLOCK ) < 0 ) {
215 ProbeTimeout = 0;
216 break;
217 }
218
219 // to this peer
220 addr.l2_bdaddr = address().getBDAddr();
221 if( ::connect( ProbeFD, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
222 if( errno != EAGAIN && errno != EINPROGRESS ) {
223 ProbeTimeout = 0;
224 break;
225 } // wait for connect to fail or succeed
226 }
227 }
228 ProbePhase = 1; // wait for connect
229 break;
230 case 1 :
231 { struct pollfd pf[1];
232 char buf[L2CAP_CMD_HDR_SIZE + PINGSIZE + 20];
233 int n;
234
235 pf[0].fd = ProbeFD;
236 pf[0].events = POLLOUT;
237 if( (n = ::poll(pf, 1, 0)) < 0 ) {
238 owarn << address().toString()
239 << " : errno "
240 << errno
241 << " "
242 << strerror(errno)<<oendl;
243 ProbeTimeout = 0;
244 break;
245 }
246
247 if( ! n ) {
248 // not ready -> try again
249 break;
250 }
251
252 // send ping
253 for( unsigned int i = L2CAP_CMD_HDR_SIZE; i < sizeof(buf); i++)
254 buf[i] = (i % 40) + 'A';
255
256 l2cap_cmd_hdr *cmd = (l2cap_cmd_hdr *) buf;
257
258 /* Build command header */
259 cmd->code = L2CAP_ECHO_REQ;
260 cmd->ident = *(char *)this; // get some byte
261 cmd->len = PINGSIZE;
262
263 /* Send Echo Request */
264 if( ::send(ProbeFD, buf, PINGSIZE + L2CAP_CMD_HDR_SIZE, 0) <= 0) {
265 if( errno == EACCES ) {
266 // permission denied means that we could not
267 // connect because the device does not allow us
268 // but it is UP
269 owarn << address().toString()
270 << " good send error "
271 << errno
272 << " "
273 << strerror( errno)
274 << oendl;
275 State = OTPeer::Peer_Up;
276 ProbeTimeout = 0;
277 break;
278 } else if( errno != EBUSY ) {
279 owarn << address().toString()
280 << " : errno "
281 << errno
282 << " "
283 << strerror(errno)
284 << oendl;
285 ProbeTimeout = 0;
286 break;
287 } // else want some more
288 }
289
290 ProbePhase = 2; // wait for ping reply
291 }
292 break;
293 case 2 : // wait for reply
294 { struct pollfd pf[1];
295 char buf[L2CAP_CMD_HDR_SIZE + PINGSIZE + 20];
296 l2cap_cmd_hdr *cmd = (l2cap_cmd_hdr *) buf;
297 int n;
298
299 pf[0].fd = ProbeFD;
300 pf[0].events = POLLIN;
301 if( (n = ::poll(pf, 1, 0)) < 0 ) {
302 owarn << address().toString()
303 << " : errno "
304 << errno
305 << " "
306 << strerror(errno)
307 <<oendl;
308 ProbeTimeout = 0;
309 break;
310 }
311
312 if( ! n ) {
313 // not ready -> try again
314 break;
315 }
316
317 if( (n = ::recv( ProbeFD, buf, sizeof(buf), 0)) < 0) {
318 owarn << address().toString()
319 << "errno "
320 << errno
321 << " "
322 << strerror(errno)
323 << oendl;
324 ProbeTimeout = 0;
325 break;
326 }
327
328 /* Check for our id */
329 if( cmd->ident != *(char *)this )
330 // not our reply
331 break;
332
333 owarn << "reply from "
334 << address().toString()
335 << oendl;
336 // whatever reply we get is a valid reply
337 State = OTPeer::Peer_Up;
338 ProbeTimeout = 0;
339 }
340 break;
341 }
342
343 if( State != OTPeer::Peer_Unknown ) {
344 ProbeTimeout = 0;
345 }
346 }
347
348 if( ProbeTimeout <= 0 ) {
349 // regular timeout
350 emit peerStateReport( this );
351 if( State == Peer_Unknown ) {
352 State = Peer_Down;
353 }
354 if( ProbeFD >= 0 ) {
355 // requested to stop by caller -> stop probing
356 ::close( ProbeFD );
357 }
358 // no more waiting
359 killTimer( ev->timerId() );
360 } // else sleep some more
361}
362
363void OTPeer::stopFindingOutState( void ) {
364 ProbeTimeout = PREMAGICNR;
365}
366