summaryrefslogtreecommitdiff
path: root/noncore/settings/networksettings2/opietooth2/OTGateway.cpp
authorwimpie <wimpie>2005-01-04 01:42:25 (UTC)
committer wimpie <wimpie>2005-01-04 01:42:25 (UTC)
commit2487b0a05f502e7410715460f390cc80e7e76fd9 (patch) (unidiff)
tree430dce90a1bdff8eb85cbf1004db094ab6653ab9 /noncore/settings/networksettings2/opietooth2/OTGateway.cpp
parente2094d408c9102f8866aafbe725a65f25fdef063 (diff)
downloadopie-2487b0a05f502e7410715460f390cc80e7e76fd9.zip
opie-2487b0a05f502e7410715460f390cc80e7e76fd9.tar.gz
opie-2487b0a05f502e7410715460f390cc80e7e76fd9.tar.bz2
*** empty log message ***
Diffstat (limited to 'noncore/settings/networksettings2/opietooth2/OTGateway.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/settings/networksettings2/opietooth2/OTGateway.cpp773
1 files changed, 773 insertions, 0 deletions
diff --git a/noncore/settings/networksettings2/opietooth2/OTGateway.cpp b/noncore/settings/networksettings2/opietooth2/OTGateway.cpp
new file mode 100644
index 0000000..2d13ce9
--- a/dev/null
+++ b/noncore/settings/networksettings2/opietooth2/OTGateway.cpp
@@ -0,0 +1,773 @@
1#include <qmessagebox.h>
2#include <qfile.h>
3#include <qdir.h>
4#include <qtextstream.h>
5#include <qpixmap.h>
6#include <qvector.h>
7#include <qpe/resource.h>
8
9#include <opie2/odebug.h>
10
11#include <bluezlib.h>
12
13#include <OTDevice.h>
14#include <OTDriver.h>
15#include <OTInquiry.h>
16#include <OTDriverList.h>
17#include <OTDeviceAddress.h>
18#include <OTGateway.h>
19
20using namespace Opietooth2;
21
22// single instance
23OTGateway * OTGateway::SingleGateway = 0;
24int OTGateway::UseCount = 0;
25
26OTGateway * OTGateway::getOTGateway( void ) {
27 if(SingleGateway == 0 ) {
28 SingleGateway = new OTGateway();
29 }
30
31 UseCount ++;
32 return SingleGateway;
33}
34
35void OTGateway::releaseOTGateway( void ) {
36 UseCount --;
37 if( UseCount == 0 ) {
38 delete SingleGateway;
39 SingleGateway = 0;
40 }
41}
42
43// open bluetooth system
44OTGateway::OTGateway( void ) : QObject( 0, "OTGateway" ),
45 AllDrivers( this ),
46 AllPeers() {
47
48 ErrorConnectCount = 0;
49 TheOTDevice = 0;
50 Scanning = 0;
51 AllPeersModified = 0;
52 AllPeers.setAutoDelete( TRUE );
53
54 if ( ( HciCtl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0) {
55 SLOT_ShowError( tr( "error opening hci socket" ) );
56 return;
57 }
58
59 // load all known devices
60 updateDrivers();
61
62 // load all peers we have ever seen
63 loadKnownPeers();
64
65 // iterate over drivers and find active connections
66 // adding/updating peers
67 loadActiveConnections();
68
69 // check every 4 seconds the state of BT
70 timerEvent(0);
71 RefreshTimer = -1;
72 setRefreshTimer( 4000 );
73
74 // load known link keys
75 readLinkKeys();
76}
77
78// close bluetooth system
79OTGateway::~OTGateway( void ) {
80
81 if( AllPeersModified ) {
82 saveKnownPeers();
83 }
84
85 if( Scanning )
86 delete Scanning;
87
88 if( TheOTDevice )
89 delete TheOTDevice;
90
91 if( HciCtl >= 0 ) {
92 ::close( HciCtl );
93 }
94}
95
96void OTGateway::setRefreshTimer( int T ) {
97 if( RefreshTimer != -1 ) {
98 killTimer( RefreshTimer );
99 }
100
101 if( T == 0 )
102 T = 4000;
103 RefreshTimer = startTimer( T );
104}
105
106OTDevice * OTGateway::getOTDevice( ) {
107 if( TheOTDevice == 0 ) {
108 // load bluetooth device and check state
109 TheOTDevice = new OTDevice( this );
110 connect( TheOTDevice,
111 SIGNAL( isEnabled( int, bool ) ),
112 this,
113 SLOT( SLOT_Enabled( int, bool ) ) );
114
115 connect( TheOTDevice,
116 SIGNAL( error( const QString & ) ),
117 this,
118 SLOT( SLOT_ShowError( const QString & ) ) );
119 }
120
121 return TheOTDevice;
122}
123
124// start bluetooth (if stopped)
125// return TRUE if started
126void OTGateway::SLOT_SetEnabled( bool Mode ) {
127 if( Mode ) {
128 SLOT_Enable();
129 return;
130 }
131 SLOT_Disable();
132}
133
134void OTGateway::SLOT_Enable() {
135 getOTDevice()->attach();
136}
137
138void OTGateway::SLOT_Disable() {
139 getOTDevice()->detach();
140}
141
142bool OTGateway::needsEnabling() {
143 return getOTDevice()->needsAttach();
144}
145
146bool OTGateway::isEnabled() {
147 if( getOTDevice()->deviceNr() >= 0 &&
148 driver( getOTDevice()->deviceNr() )->isUp() )
149 return TRUE;
150
151 // else check system
152 return getOTDevice()->isAttached();
153}
154
155void OTGateway::SLOT_ShowError( const QString & S ) {
156
157 owarn << S << oendl;
158
159 if( ErrorConnectCount > 0 ) {
160 // pass error
161 emit error( QString( "<p>" ) + S + "</p>" );
162 return;
163 }
164
165 QMessageBox::warning( 0,
166 tr("OTGateway error"),
167 S );
168}
169
170void OTGateway::connectNotify( const char * S ) {
171 if( strcmp( S, "error(const QString&)" ) == 0 ) {
172 ErrorConnectCount ++;
173 }
174}
175
176void OTGateway::disconnectNotify( const char * S ) {
177 if( strcmp( S, "error(const QString&)" ) == 0 ) {
178 ErrorConnectCount --;
179 }
180}
181
182void OTGateway::timerEvent( QTimerEvent * ) {
183
184 OTDriver * D;
185 unsigned int oldc = AllDrivers.count();
186 bool old;
187
188 AllDrivers.update();
189
190 if( oldc != AllDrivers.count() ) {
191 updateDrivers();
192 } else {
193 for( unsigned int i = 0;
194 i < AllDrivers.count();
195 i ++ ) {
196 D = AllDrivers[i];
197 old = D->isUp();
198 if( D->currentState() >= 0 ) {
199 if( old != D->isUp() ) {
200 emit stateChange( D, D->isUp() );
201 }
202 } else {
203 // if one driver is unable to provide info
204 // we refresh all devices
205 updateDrivers();
206 return;
207 }
208 }
209 }
210}
211
212void OTGateway::SLOT_Enabled( int id, bool Up ) {
213 owarn << "device " << id << " state " << Up << oendl;
214 if( Up ) {
215 // device is up -> detect it
216 updateDrivers();
217 if( (unsigned)id >= AllDrivers.count() ) {
218 // to make sure that the driver really IS detected
219 AllDrivers[id]->bringUp();
220 }
221 } // if DOWN device already down
222 emit deviceEnabled( Up );
223}
224
225void OTGateway::updateDrivers( void ) {
226 OTDriver * D;
227
228 AllDrivers.update();
229
230 owarn << "updated drivers. now " << AllDrivers.count() << oendl;
231
232 // connect signals for each driver
233 for( unsigned int i = 0;
234 i < AllDrivers.count();
235 i ++ ) {
236 D = AllDrivers[i];
237
238 connect( D,
239 SIGNAL( error( const QString & ) ),
240 this,
241 SLOT( SLOT_ShowError( const QString & ) )
242 );
243
244 connect( D,
245 SIGNAL( stateChange( OTDriver *, bool ) ),
246 this,
247 SIGNAL( stateChange( OTDriver *, bool ) )
248 );
249
250 connect( D,
251 SIGNAL( driverDisappeared( OTDriver * ) ),
252 this,
253 SLOT( SLOT_DriverDisappeared( OTDriver * ) )
254 );
255 }
256
257 // verify main device too
258 if( TheOTDevice )
259 TheOTDevice->checkAttach();
260
261 // set to default scanning hardware
262 setScanWith( 0 );
263
264 emit driverListChanged();
265}
266
267void OTGateway::SLOT_DriverDisappeared( OTDriver * D ) {
268 owarn << "Driver " << D->devname() << " when offline" << oendl;
269 updateDrivers();
270}
271
272void OTGateway::scanNeighbourhood( OTDriver * D ) {
273
274 if( Scanning ) {
275 stopScanOfNeighbourhood();
276 }
277
278 if( D ) {
279 setScanWith( D );
280 }
281
282 Scanning = new OTInquiry( scanWith() );
283
284 connect( Scanning,
285 SIGNAL( peerFound( OTPeer *, bool )),
286 this,
287 SLOT( SLOT_PeerDetected( OTPeer *, bool ) )
288 );
289 connect( Scanning,
290 SIGNAL( finished()),
291 this,
292 SLOT( SLOT_FinishedDetecting() )
293 );
294
295 // start scanning
296 Scanning->inquire( 30.0 );
297}
298
299OTPeer* OTGateway::findPeer( const OTDeviceAddress & Addr ) {
300 for( unsigned int i = 0 ; i < AllPeers.count(); i ++ ) {
301 if( AllPeers[i]->address() == Addr ) {
302 return AllPeers[i];
303 }
304 }
305 return 0;
306}
307
308OTDriver* OTGateway::findDriver( const OTDeviceAddress & Addr ) {
309 for( unsigned int i = 0 ; i < AllDrivers.count(); i ++ ) {
310 if( AllDrivers[i]->address() == Addr ) {
311 return AllDrivers[i];
312 }
313 }
314 return 0;
315}
316
317void OTGateway::SLOT_PeerDetected( OTPeer * P, bool IsNew ) {
318
319 if( IsNew ) {
320 // new peer
321 owarn << "New peer " << P->name() << oendl;
322 addPeer( P );
323 }
324
325 emit detectedPeer( P, IsNew );
326}
327
328void OTGateway::addPeer( OTPeer * P ) {
329 AllPeers.resize( AllPeers.size()+1);
330 AllPeers.insert( AllPeers.size()-1, P );
331 AllPeersModified = 1;
332}
333
334void OTGateway::removePeer( OTPeer * P ) {
335 int i = AllPeers.find( P );
336 if( i ) {
337 AllPeers.remove( i );
338 AllPeersModified = 1;
339 }
340}
341
342void OTGateway::stopScanOfNeighbourhood( void ) {
343 if( Scanning ) {
344 delete Scanning;
345 Scanning = 0;
346 }
347}
348
349void OTGateway::SLOT_FinishedDetecting() {
350 stopScanOfNeighbourhood();
351 emit finishedDetecting();
352}
353
354const char * OTGateway::deviceTypeToName( int cls ) {
355 switch ( (cls & 0x001F00) >> 8) {
356 case 0x00:
357 return "misc";
358 case 0x01:
359 return "computer";
360 case 0x02:
361 return "phone";
362 case 0x03:
363 return "lan";
364 case 0x04:
365 return "av";
366 case 0x05:
367 return "peripheral";
368 case 0x06:
369 return "imaging";
370 case 0x07:
371 default :
372 break;
373 }
374 return "unknown";
375}
376
377PANConnectionVector OTGateway::getPANConnections( void ) {
378 PANConnectionVector V;
379
380 struct bnep_connlist_req req;
381 struct bnep_conninfo ci[48];
382
383 V.setAutoDelete(TRUE);
384
385 int ctl = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_BNEP);
386 if (ctl < 0) {
387 owarn << "Failed to open control socket" << oendl;
388 return V;
389 }
390
391 req.cnum = 48;
392 req.ci = ci;
393 if (ioctl(ctl, BNEPGETCONNLIST, &req)) {
394 owarn << "Failed to get connection list" << oendl;
395 ::close( ctl );
396 return V;
397 }
398
399 for ( unsigned i=0; i < req.cnum; i++) {
400 V.resize( V.size() + 1 );
401 if( ci[i].role == BNEP_SVC_PANU ) {
402 // we are the client
403 V.insert( V.size()-1, new OTPANConnection(
404 ci[i].device,
405 batostr((bdaddr_t *) ci[i].dst)
406 ) );
407 }
408 }
409
410 ::close( ctl );
411 return V;
412}
413
414struct link_key {
415 bdaddr_t sba;
416 bdaddr_t dba;
417 uint8_t key[16];
418 uint8_t type;
419 time_t time;
420};
421
422void OTGateway::readLinkKeys( void ) {
423
424 struct link_key k;
425 int rv;
426
427 AllKeys.truncate(0);
428
429 QFile F( "/etc/bluetooth/link_key" );
430
431 if( ! F.open( IO_ReadOnly ) ) {
432 emit error( tr("Cannot open link_key file") );
433 return;
434 }
435
436 while( 1 ) {
437 rv = F.readBlock( (char *)&k, sizeof( k ) );
438 if( rv == 0 )
439 // EOF
440 break;
441
442 if( rv < 0 ) {
443 emit error( tr("Read error in link key file") );
444 }
445
446 AllKeys.resize( AllKeys.size()+1 );
447 AllKeys[ AllKeys.size()-1 ].From.setBDAddr( k.sba );
448 AllKeys[ AllKeys.size()-1 ].To.setBDAddr( k.dba );
449 }
450}
451
452bool OTGateway::removeLinkKey( unsigned int Index ) {
453 OTLinkKey & LK = AllKeys[Index];
454
455 struct link_key k;
456 int rv;
457
458 QFile F( "/etc/bluetooth/link_key" );
459 QFile OutF( "/etc/bluetooth/newlink_key" );
460
461 if( ! F.open( IO_ReadOnly ) ) {
462 emit error( tr("Cannot open link_key file") );
463 return 0;
464 }
465
466 if( ! OutF.open( IO_WriteOnly | IO_Truncate ) ) {
467 emit error( tr("Cannot open temporary link_key file") );
468 return 0;
469 }
470
471 while( 1 ) {
472 rv = F.readBlock( (char *)&k, sizeof( k ) );
473 if( rv == 0 )
474 // EOF
475 break;
476
477 if( rv < 0 ) {
478 emit error( tr("Read error in link key file") );
479 return 0;
480 }
481
482 if( LK.from() != OTDeviceAddress( k.sba ) ||
483 LK.to() != OTDeviceAddress( k.dba ) ) {
484 // copy
485 OutF.writeBlock( (char *)&k, sizeof( k ) );
486 } // else remove this key
487 }
488
489 // rename files
490 QDir D( "/etc/bluetooth" );
491
492 D.remove( "link_key" );
493 D.rename( "newlink_key", "link_key" );
494
495 // restart hcid
496 system( "/etc/init.d/hcid stop" );
497 system( "/etc/init.d/hcid start" );
498
499 // remove from table
500 if( Index < (AllKeys.size()-1) ) {
501 // collapse array
502 AllKeys[Index] = AllKeys[AllKeys.size()-1];
503 }
504
505 // remove last element
506 AllKeys.resize( AllKeys.size()-1 );
507
508 return 1;
509}
510
511#define MAXCONNECTIONS 10
512void OTGateway::loadActiveConnections( void ) {
513
514 struct hci_conn_list_req *cl;
515 struct hci_conn_info *ci;
516 OTDeviceAddress Addr;
517 OTPeer * P;
518
519 if (!(cl = (struct hci_conn_list_req *)malloc(
520 MAXCONNECTIONS * sizeof(*ci) + sizeof(*cl)))) {
521 emit error( tr("Can't allocate memory") );
522 return;
523 }
524 memset( cl, 0, MAXCONNECTIONS * sizeof(*ci) + sizeof(*cl) );
525
526 for( unsigned int i = 0;
527 i < AllDrivers.count();
528 i ++ ) {
529
530 if( ! AllDrivers[i]->isUp() ) {
531 continue;
532 }
533
534 // driver is up -> check connections
535 cl->dev_id = AllDrivers[i]->devId();
536 cl->conn_num = MAXCONNECTIONS;
537 ci = cl->conn_info;
538
539 if (ioctl( getSocket(), HCIGETCONNLIST, (void *) cl)) {
540 emit error( tr("Can't get connection list") );
541 break;
542 }
543
544 for ( int k = 0; k < cl->conn_num; k++, ci++) {
545
546 if( ci->state != BT_CONNECTED ) {
547 // not yet connected
548 continue;
549 }
550
551 Addr.setBDAddr( ci->bdaddr );
552 P = findPeer( Addr );
553 if( ! P ) {
554 // peer not yet known -> add
555 P = new OTPeer( this );
556 addPeer( P );
557 P->setAddress( Addr );
558 // infoQueue.push_back(info);
559 P->setName( AllDrivers[i]->getPeerName( Addr ) );
560 }
561 P->setState( OTPeer::Peer_Up );
562 P->setConnectedTo( AllDrivers[i] );
563 }
564 }
565
566 free( cl );
567}
568
569void OTGateway::loadKnownPeers( void ) {
570 QDir SaveDir = QDir::home();
571
572 if( ! SaveDir.exists( "Settings" ) ) {
573 return;
574 }
575 SaveDir.cd( "Settings" );
576
577 if( ! SaveDir.exists( "opietooth" ) ) {
578 return;
579 }
580 SaveDir.cd( "opietooth" );
581
582 QFile F( SaveDir.path() + "/SeenDevices.conf" );
583
584 if( F.open( IO_ReadOnly ) ) {
585 QTextStream TS(&F);
586 long count;
587
588 count = TS.readLine().toLong();
589
590 while( count > 0 ) {
591 addPeer( new OTPeer( TS, this ) );
592 count --;
593 }
594 }
595
596 AllPeersModified = 0;
597}
598
599void OTGateway::saveKnownPeers( void ) {
600 QDir SaveDir = QDir::home();
601
602 if( ! SaveDir.exists( "Settings" ) ) {
603 SaveDir.mkdir( "Settings" );
604 }
605 SaveDir.cd( "Settings" );
606
607 if( ! SaveDir.exists( "opietooth" ) ) {
608 SaveDir.mkdir( "opietooth" );
609 }
610 SaveDir.cd( "opietooth" );
611
612 QFile F( SaveDir.path() + "/SeenDevices.conf" );
613
614 if( F.open( IO_WriteOnly | IO_Truncate ) ) {
615 QTextStream TS(&F);
616 QString S;
617
618 TS << AllPeers.count() << endl;
619
620 for( unsigned int i = 0;
621 i < AllPeers.count();
622 i ++ ) {
623 AllPeers[i]->save( TS );
624 }
625 AllPeersModified = 0;
626 }
627 AllPeersModified = 0;
628}
629
630int OTGateway::connectedToRFCommChannel( const OTDeviceAddress & Addr,
631 int channel ) {
632
633 int s;
634
635 if( (s = ::socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_RFCOMM)) < 0 ) {
636 emit error( tr("Can't open RFCOMM control socket") );
637 return 0;
638 }
639
640 // get all rfcomm devices
641 { struct rfcomm_dev_list_req *dl;
642 struct rfcomm_dev_info *di, *dr;
643 int i;
644
645 dl = (struct rfcomm_dev_list_req *)alloca(
646 sizeof(*dl) + RFCOMM_MAX_DEV * sizeof(*di));
647 memset( dl, 0, sizeof(*dl) + RFCOMM_MAX_DEV * sizeof(*di) );
648 dl->dev_num = RFCOMM_MAX_DEV;
649 di = dl->dev_info;
650
651 if( ::ioctl(s, RFCOMMGETDEVLIST, (void *) dl) < 0) {
652 emit error( tr("Can't get device list") );
653 ::close( s );
654 return 0;
655 }
656
657 dr = di;
658 for (i = 0; i < dl->dev_num; i++, dr++) {
659 // connected to Peer
660 if( Addr == OTDeviceAddress( dr->dst ) &&
661 channel == dr->channel &&
662 ( dr->state != 0 )
663 ) {
664 // return device ID
665 return dr->id;
666 }
667 }
668 }
669
670 // no device
671 return -1;
672}
673
674static int byID( struct rfcomm_dev_info * d1,
675 struct rfcomm_dev_info * d2 ) {
676 return d1->id - d2->id;
677}
678
679int OTGateway::getFreeRFCommDevice( void ) {
680
681 int s;
682
683 if( (s = ::socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_RFCOMM)) < 0 ) {
684 emit error( tr("Can't open RFCOMM control socket") );
685 return 0;
686 }
687
688 // get all rfcomm devices
689 { struct rfcomm_dev_list_req *dl;
690 struct rfcomm_dev_info *di, *dr;
691 int i;
692
693 dl = (struct rfcomm_dev_list_req *)alloca(
694 sizeof(*dl) + RFCOMM_MAX_DEV * sizeof(*di));
695
696 dl->dev_num = RFCOMM_MAX_DEV;
697 di = dl->dev_info;
698
699 if( ::ioctl(s, RFCOMMGETDEVLIST, (void *) dl) < 0) {
700 emit error( tr("Can't get device list") );
701 ::close( s );
702 return 0;
703 }
704
705 // s
706 if( dl->dev_num ) {
707 qsort( di, sizeof(struct rfcomm_dev_info),
708 dl->dev_num, (int(*)(const void*,const void*))byID );
709 int id = 0;
710
711 dr = di;
712 // find lowest free device number
713 for (i = 0; i < dl->dev_num; i++, dr++) {
714 if( id != dr->id ) {
715 return id;
716 }
717 id ++;
718 }
719 return id;
720 } else {
721 return 0;
722 }
723 }
724}
725
726int OTGateway::releaseRFCommDevice( int devnr ) {
727
728 int s;
729
730 if( (s = ::socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_RFCOMM)) < 0 ) {
731 emit error( tr("Can't open RFCOMM control socket") );
732 return 0;
733 }
734
735 // get all rfcomm devices
736 { struct rfcomm_dev_list_req *dl;
737 struct rfcomm_dev_info *di, *dr;
738 int i;
739
740 dl = (struct rfcomm_dev_list_req *)alloca(
741 sizeof(*dl) + RFCOMM_MAX_DEV * sizeof(*di));
742 memset( dl, 0, sizeof(*dl) + RFCOMM_MAX_DEV * sizeof(*di) );
743 dl->dev_num = RFCOMM_MAX_DEV;
744 di = dl->dev_info;
745
746 if( ::ioctl(s, RFCOMMGETDEVLIST, (void *) dl) < 0) {
747 emit error( tr("Can't get device list") );
748 ::close( s );
749 return 0;
750 }
751
752 dr = di;
753 for (i = 0; i < dl->dev_num; i++, dr++) {
754 if( dr->id == devnr ) {
755 // still in connection list
756 struct rfcomm_dev_req req;
757 int err;
758
759 memset(&req, 0, sizeof(req));
760 req.dev_id = devnr;
761
762 if ((err = ioctl(s, RFCOMMRELEASEDEV, &req)) < 0 ) {
763 return err;
764 }
765 return 0;
766 }
767 }
768 }
769
770 // no device -> nothing to release eiterh
771 return 0;
772}
773