Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

OTPeer.cpp

Go to the documentation of this file.
00001 //-*-c++-*-
00002 /***************************************************************************
00003  *   Copyright (C) 2003 by Fred Schaettgen                                 *
00004  *   kdebluetooth@schaettgen.de                                            *
00005  *                                                                         *
00006  *   This program is free software; you can redistribute it and/or modify  *
00007  *   it under the terms of the GNU General Public License as published by  *
00008  *   the Free Software Foundation; either version 2 of the License, or     *
00009  *   (at your option) any later version.                                   *
00010  ***************************************************************************/
00011 
00012 #include <assert.h>
00013 #include <sys/poll.h>
00014 #include <string.h>
00015 
00016 #include <bluezlib.h>
00017 #include <qarray.h>
00018 #include <qtextstream.h>
00019 
00020 #include <opie2/odebug.h>
00021 
00022 #include <OTDeviceAddress.h>
00023 #include <OTSDPAttribute.h>
00024 #include <OTSDPService.h>
00025 #include <OTPeer.h>
00026 #include <OTGateway.h>
00027 #include <OTDriver.h>
00028 
00029 using namespace Opietooth2;
00030 
00031 OTPeer::OTPeer( OTGateway * _OT ) {
00032       OT = _OT;
00033       State = Peer_Unknown;
00034       ConnectedTo = 0;
00035 }
00036 
00037 OTPeer::OTPeer( QTextStream & TS, OTGateway * _OT ) {
00038       OT = _OT;
00039       State = Peer_Unknown;
00040       ConnectedTo = 0;
00041 
00042       load( TS );
00043 }
00044 
00045 OTPeer::~OTPeer( ) {
00046 
00047 }
00048 
00049 void OTPeer::updateServices( void ) {
00050     sdp_session_t *session;
00051 
00052     serviceList.clear();
00053 
00054     odebug << "Get services from " << Addr.toString() << oendl;
00055 
00056     session = sdp_connect( &(OTDeviceAddress::any.getBDAddr()), 
00057                            &(Addr.getBDAddr()),
00058                            0);
00059 
00060     if (!session) {
00061       odebug << "sdp_connect(" 
00062             << Addr.toString()
00063             << ") failed"  
00064             << oendl;
00065         return; // error
00066     }
00067 
00068     uint32_t range = 0x0000ffff;
00069     sdp_list_t* attrId = sdp_list_append(0, &range);
00070 
00071     // search all public features
00072     uuid_t grp;
00073     sdp_uuid16_create( &grp, PUBLIC_BROWSE_GROUP );
00074     sdp_list_t * search = sdp_list_append(0, &grp );
00075 
00076     // get data from peer
00077     sdp_list_t* seq;
00078     if (sdp_service_search_attr_req( session, 
00079                                      search,
00080                                      SDP_ATTR_REQ_RANGE, 
00081                                      attrId, 
00082                                      &seq ) ) {
00083       odebug << "Service Search failed" << oendl;
00084       sdp_close(session);
00085       return;
00086     }
00087 
00088     sdp_list_free(attrId, 0);
00089     sdp_list_free(search, 0);
00090 
00091     // process result
00092     sdp_list_t* next = NULL;
00093 
00094     for (; seq; seq = next) {
00095       sdp_record_t *rec = (sdp_record_t *) seq->data;
00096 
00097       sdp_list_t* attrlist = rec->attrlist;
00098       AttributeVector alist;
00099       OTSDPService * service;
00100 
00101       service = new OTSDPService();
00102 
00103       for (; attrlist; attrlist = attrlist->next) {
00104         int attrID = ((sdp_data_t*)(attrlist->data))->attrId;
00105         service->addAttribute( 
00106               attrID, 
00107               new OTSDPAttribute( (sdp_data_t*)(attrlist->data) )
00108             );
00109       }
00110 
00111       serviceList.resize( serviceList.size() + 1 );
00112       serviceList.insert( serviceList.size() - 1, service );
00113 
00114       next = seq->next;
00115       free(seq);
00116       sdp_record_free(rec);
00117     }
00118     sdp_close(session);
00119 }
00120 
00121 bool OTPeer::hasServiceClassID( const OTUUID & uuid) {
00122     for( unsigned int i = 0;
00123          i < serviceList.count();
00124          i ++ ) {
00125       if( serviceList[i]->hasClassID(uuid))
00126         return true;
00127     }
00128     return false;
00129 }
00131 QArray<int> OTPeer::rfcommList( const OTUUID & uuid) {
00132 
00133     QArray<int> rfcommList;
00134     unsigned int channel;
00135 
00136     for( unsigned int i = 0;
00137          i < serviceList.count();
00138          i ++ ) {
00139       if( serviceList[i]->hasClassID(uuid)) {
00140         if( serviceList[i]->rfcommChannel(channel) ) {
00141           rfcommList.resize( rfcommList.size()+1 );
00142           rfcommList[rfcommList.size()-1] = channel;
00143         }
00144       }
00145     }
00146     return rfcommList;
00147 }
00148 
00149 void OTPeer::save( QTextStream & TS ) {
00150         TS << "bdaddr " << address().toString() << endl;
00151         TS << "name " << name() << endl;
00152         TS << "class " << deviceClass() << endl;
00153 }
00154 
00155 void OTPeer::load( QTextStream & TS ) {
00156       QString S;
00157       S = TS.readLine();
00158       setAddress( OTDeviceAddress( S.mid( 7 ) ) );
00159 
00160       S = TS.readLine();
00161       setName( S.mid( 5 ) );
00162 
00163       S = TS.readLine();
00164       setDeviceClass( S.mid( 6 ).toLong() );
00165 }
00166 
00167 #define MAGICNR         -99999
00168 #define POLLDELAY       1000
00169 #define PREMAGICNR      (MAGICNR+POLLDELAY)
00170 
00171 void OTPeer::findOutState( int timeoutInSec, bool Force ) {
00172       ProbeFD = -1;
00173       if( Force && ConnectedTo == 0 ) {
00174         State = OTPeer::Peer_Unknown;
00175       } // else keep state or is connected to us
00176 
00177       if( State == OTPeer::Peer_Unknown ) {
00178         ProbePhase = 0;
00179         ProbeTimeout = timeoutInSec*1000;
00180         odebug << "Ping " << address().toString() << oendl;
00181         startTimer( POLLDELAY );
00182       } else {
00183         ProbeTimeout = 0;
00184         startTimer( 0 );
00185       }
00186 }
00187 
00188 #define PINGSIZE        20
00189 void OTPeer::timerEvent( QTimerEvent * ev ) {
00190 
00191       ProbeTimeout -= POLLDELAY;
00192 
00193       if( State == OTPeer::Peer_Unknown ) {
00194         switch( ProbePhase ) {
00195           case 0 : // connect nonblock
00196             { struct sockaddr_l2 addr;
00197 
00198               if (( ProbeFD = ::socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP)) < 0) {
00199                 ProbeTimeout = 0;
00200                 break;
00201               }
00202 
00203               memset(&addr, 0, sizeof(addr));
00204 
00205               addr.l2_family = AF_BLUETOOTH;
00206               addr.l2_bdaddr = OTDeviceAddress::any.getBDAddr();
00207 
00208               if( ::bind( ProbeFD, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
00209                 ProbeTimeout = 0;
00210                 break;
00211               }
00212 
00213               // non blocking
00214               if( ::fcntl( ProbeFD, F_SETFL, O_NONBLOCK ) < 0 ) {
00215                 ProbeTimeout = 0;
00216                 break;
00217               }
00218 
00219               // to this peer
00220               addr.l2_bdaddr = address().getBDAddr();
00221               if( ::connect( ProbeFD, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
00222                 if( errno != EAGAIN && errno != EINPROGRESS ) {
00223                   ProbeTimeout = 0;
00224                   break;
00225                 } // wait for connect to fail or succeed
00226               }
00227             }
00228             ProbePhase = 1; // wait for connect
00229             break;
00230           case 1 :
00231             { struct pollfd pf[1];
00232               char buf[L2CAP_CMD_HDR_SIZE + PINGSIZE + 20];
00233               int n;
00234 
00235               pf[0].fd = ProbeFD; 
00236               pf[0].events = POLLOUT;
00237               if( (n = ::poll(pf, 1, 0)) < 0 ) {
00238                 odebug << address().toString()
00239                       << " : errno " 
00240                       << errno 
00241                       << " " 
00242                       << strerror(errno)<<oendl;
00243                 ProbeTimeout = 0;
00244                 break;
00245               }
00246 
00247               if( ! n ) {
00248                 // not ready -> try again
00249                 break;
00250               }
00251 
00252               // send ping
00253               for( unsigned int i = L2CAP_CMD_HDR_SIZE; i < sizeof(buf); i++)
00254                   buf[i] = (i % 40) + 'A';
00255 
00256               l2cap_cmd_hdr *cmd = (l2cap_cmd_hdr *) buf;
00257 
00258               /* Build command header */
00259               cmd->code  = L2CAP_ECHO_REQ;
00260               cmd->ident = *(char *)this; // get some byte
00261               cmd->len   = PINGSIZE;
00262 
00263               /* Send Echo Request */
00264               if( ::send(ProbeFD, buf, PINGSIZE + L2CAP_CMD_HDR_SIZE, 0) <= 0) {
00265                 if( errno == EACCES ) {
00266                   // permission denied means that we could not
00267                   // connect because the device does not allow us
00268                   // but it is UP
00269                   odebug << address().toString()
00270                         << " good send error " 
00271                         << errno 
00272                         << " " 
00273                         << strerror( errno) 
00274                         << oendl;
00275                   State = OTPeer::Peer_Up;
00276                   ProbeTimeout = 0;
00277                   break;
00278                 } else if( errno != EBUSY ) {
00279                   odebug << address().toString()
00280                         << " : errno " 
00281                         << errno 
00282                         << " " 
00283                         << strerror(errno)
00284                         << oendl;
00285                   ProbeTimeout = 0;
00286                   break;
00287                 } // else want some more
00288               }
00289 
00290               ProbePhase = 2; // wait for ping reply
00291             }
00292             break;
00293           case 2 : // wait for reply
00294             { struct pollfd pf[1];
00295               char buf[L2CAP_CMD_HDR_SIZE + PINGSIZE + 20];
00296               l2cap_cmd_hdr *cmd = (l2cap_cmd_hdr *) buf;
00297               int n;
00298 
00299               pf[0].fd = ProbeFD; 
00300               pf[0].events = POLLIN;
00301               if( (n = ::poll(pf, 1, 0)) < 0 ) {
00302                 odebug << address().toString()
00303                       << " : errno " 
00304                       << errno 
00305                       << " " 
00306                       << strerror(errno)
00307                       <<oendl;
00308                 ProbeTimeout = 0;
00309                 break;
00310               }
00311 
00312               if( ! n ) {
00313                 // not ready -> try again
00314                 break;
00315               }
00316 
00317               if( (n = ::recv( ProbeFD, buf, sizeof(buf), 0)) < 0) {
00318                 odebug << address().toString()
00319                       << "errno " 
00320                       << errno 
00321                       << " " 
00322                       << strerror(errno) 
00323                       << oendl;
00324                 ProbeTimeout = 0;
00325                 break;
00326               }
00327 
00328               /* Check for our id */
00329               if( cmd->ident != *(char *)this )
00330                 // not our reply
00331                 break;
00332 
00333               odebug << "reply from " 
00334                     << address().toString()
00335                     << oendl;
00336               // whatever reply we get is a valid reply 
00337               State = OTPeer::Peer_Up;
00338               ProbeTimeout = 0;
00339             }
00340             break;
00341         }
00342 
00343         if( State != OTPeer::Peer_Unknown ) {
00344           ProbeTimeout = 0;
00345         }
00346       } 
00347 
00348       if( ProbeTimeout <= 0 ) {
00349         // regular timeout
00350         emit peerStateReport( this );
00351         if( State == Peer_Unknown ) {
00352           State = Peer_Down;
00353         }
00354         if( ProbeFD >= 0 ) {
00355           // requested to stop by caller -> stop probing
00356           ::close( ProbeFD );
00357         } 
00358         // no more waiting
00359         killTimer( ev->timerId() );
00360       }  // else sleep some more
00361 }
00362 
00363 void OTPeer::stopFindingOutState( void ) {
00364       ProbeTimeout = PREMAGICNR;
00365 }
00366 

Generated on Sat Nov 5 16:17:55 2005 for OPIE by  doxygen 1.4.2