From 9a134ab03890d942d53b4121e31e2d37859fa42c Mon Sep 17 00:00:00 2001 From: wimpie Date: Tue, 04 Jan 2005 01:44:52 +0000 Subject: New bluetooth library OT2 (loosely based on kbluetooth) --- (limited to 'noncore/settings/networksettings2/opietooth2/OTPeer.cpp') 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 @@ +//-*-c++-*- +/*************************************************************************** + * Copyright (C) 2003 by Fred Schaettgen * + * kdebluetooth@schaettgen.de * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +using namespace Opietooth2; + +OTPeer::OTPeer( OTGateway * _OT ) { + OT = _OT; + State = Peer_Unknown; + ConnectedTo = 0; +} + +OTPeer::OTPeer( QTextStream & TS, OTGateway * _OT ) { + OT = _OT; + State = Peer_Unknown; + ConnectedTo = 0; + + load( TS ); +} + +OTPeer::~OTPeer( ) { + +} + +void OTPeer::updateServices( void ) { + sdp_session_t *session; + + serviceList.clear(); + + owarn << "Get services from " << Addr.toString() << oendl; + + session = sdp_connect( &(OTDeviceAddress::any.getBDAddr()), + &(Addr.getBDAddr()), + 0); + + if (!session) { + owarn << "sdp_connect(" + << Addr.toString() + << ") failed" + << oendl; + return; // error + } + + uint32_t range = 0x0000ffff; + sdp_list_t* attrId = sdp_list_append(0, &range); + + // search all public features + uuid_t grp; + sdp_uuid16_create( &grp, PUBLIC_BROWSE_GROUP ); + sdp_list_t * search = sdp_list_append(0, &grp ); + + // get data from peer + sdp_list_t* seq; + if (sdp_service_search_attr_req( session, + search, + SDP_ATTR_REQ_RANGE, + attrId, + &seq ) ) { + owarn << "Service Search failed" << oendl; + sdp_close(session); + return; + } + + sdp_list_free(attrId, 0); + sdp_list_free(search, 0); + + // process result + sdp_list_t* next = NULL; + + for (; seq; seq = next) { + sdp_record_t *rec = (sdp_record_t *) seq->data; + + sdp_list_t* attrlist = rec->attrlist; + AttributeVector alist; + OTSDPService * service; + + service = new OTSDPService(); + + for (; attrlist; attrlist = attrlist->next) { + int attrID = ((sdp_data_t*)(attrlist->data))->attrId; + service->addAttribute( + attrID, + new OTSDPAttribute( (sdp_data_t*)(attrlist->data) ) + ); + } + + serviceList.resize( serviceList.size() + 1 ); + serviceList.insert( serviceList.size() - 1, service ); + + next = seq->next; + free(seq); + sdp_record_free(rec); + } + sdp_close(session); +} + +bool OTPeer::hasServiceClassID( const OTUUID & uuid) { + for( unsigned int i = 0; + i < serviceList.count(); + i ++ ) { + if( serviceList[i]->hasClassID(uuid)) + return true; + } + return false; +} +/** Get a vector of Rfcomm channels of the services having "uuid" in the class ID List*/ +QArray OTPeer::rfcommList( const OTUUID & uuid) { + + QArray rfcommList; + unsigned int channel; + + for( unsigned int i = 0; + i < serviceList.count(); + i ++ ) { + if( serviceList[i]->hasClassID(uuid)) { + if( serviceList[i]->rfcommChannel(channel) ) { + rfcommList.resize( rfcommList.size()+1 ); + rfcommList[rfcommList.size()-1] = channel; + } + } + } + return rfcommList; +} + +void OTPeer::save( QTextStream & TS ) { + TS << "bdaddr " << address().toString() << endl; + TS << "name " << name() << endl; + TS << "class " << deviceClass() << endl; +} + +void OTPeer::load( QTextStream & TS ) { + QString S; + S = TS.readLine(); + setAddress( OTDeviceAddress( S.mid( 7 ) ) ); + + S = TS.readLine(); + setName( S.mid( 5 ) ); + + S = TS.readLine(); + setDeviceClass( S.mid( 6 ).toLong() ); +} + +#define MAGICNR -99999 +#define POLLDELAY 1000 +#define PREMAGICNR (MAGICNR+POLLDELAY) + +void OTPeer::findOutState( int timeoutInSec, bool Force ) { + ProbeFD = -1; + if( Force && ConnectedTo == 0 ) { + State = OTPeer::Peer_Unknown; + } // else keep state or is connected to us + + if( State == OTPeer::Peer_Unknown ) { + ProbePhase = 0; + ProbeTimeout = timeoutInSec*1000; + owarn << "Ping " << address().toString() << oendl; + startTimer( POLLDELAY ); + } else { + ProbeTimeout = 0; + startTimer( 0 ); + } +} + +#define PINGSIZE 20 +void OTPeer::timerEvent( QTimerEvent * ev ) { + + ProbeTimeout -= POLLDELAY; + + if( State == OTPeer::Peer_Unknown ) { + switch( ProbePhase ) { + case 0 : // connect nonblock + { struct sockaddr_l2 addr; + + if (( ProbeFD = ::socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP)) < 0) { + ProbeTimeout = 0; + break; + } + + memset(&addr, 0, sizeof(addr)); + + addr.l2_family = AF_BLUETOOTH; + addr.l2_bdaddr = OTDeviceAddress::any.getBDAddr(); + + if( ::bind( ProbeFD, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + ProbeTimeout = 0; + break; + } + + // non blocking + if( ::fcntl( ProbeFD, F_SETFL, O_NONBLOCK ) < 0 ) { + ProbeTimeout = 0; + break; + } + + // to this peer + addr.l2_bdaddr = address().getBDAddr(); + if( ::connect( ProbeFD, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + if( errno != EAGAIN && errno != EINPROGRESS ) { + ProbeTimeout = 0; + break; + } // wait for connect to fail or succeed + } + } + ProbePhase = 1; // wait for connect + break; + case 1 : + { struct pollfd pf[1]; + char buf[L2CAP_CMD_HDR_SIZE + PINGSIZE + 20]; + int n; + + pf[0].fd = ProbeFD; + pf[0].events = POLLOUT; + if( (n = ::poll(pf, 1, 0)) < 0 ) { + owarn << address().toString() + << " : errno " + << errno + << " " + << strerror(errno)< try again + break; + } + + // send ping + for( unsigned int i = L2CAP_CMD_HDR_SIZE; i < sizeof(buf); i++) + buf[i] = (i % 40) + 'A'; + + l2cap_cmd_hdr *cmd = (l2cap_cmd_hdr *) buf; + + /* Build command header */ + cmd->code = L2CAP_ECHO_REQ; + cmd->ident = *(char *)this; // get some byte + cmd->len = PINGSIZE; + + /* Send Echo Request */ + if( ::send(ProbeFD, buf, PINGSIZE + L2CAP_CMD_HDR_SIZE, 0) <= 0) { + if( errno == EACCES ) { + // permission denied means that we could not + // connect because the device does not allow us + // but it is UP + owarn << address().toString() + << " good send error " + << errno + << " " + << strerror( errno) + << oendl; + State = OTPeer::Peer_Up; + ProbeTimeout = 0; + break; + } else if( errno != EBUSY ) { + owarn << address().toString() + << " : errno " + << errno + << " " + << strerror(errno) + << oendl; + ProbeTimeout = 0; + break; + } // else want some more + } + + ProbePhase = 2; // wait for ping reply + } + break; + case 2 : // wait for reply + { struct pollfd pf[1]; + char buf[L2CAP_CMD_HDR_SIZE + PINGSIZE + 20]; + l2cap_cmd_hdr *cmd = (l2cap_cmd_hdr *) buf; + int n; + + pf[0].fd = ProbeFD; + pf[0].events = POLLIN; + if( (n = ::poll(pf, 1, 0)) < 0 ) { + owarn << address().toString() + << " : errno " + << errno + << " " + << strerror(errno) + < try again + break; + } + + if( (n = ::recv( ProbeFD, buf, sizeof(buf), 0)) < 0) { + owarn << address().toString() + << "errno " + << errno + << " " + << strerror(errno) + << oendl; + ProbeTimeout = 0; + break; + } + + /* Check for our id */ + if( cmd->ident != *(char *)this ) + // not our reply + break; + + owarn << "reply from " + << address().toString() + << oendl; + // whatever reply we get is a valid reply + State = OTPeer::Peer_Up; + ProbeTimeout = 0; + } + break; + } + + if( State != OTPeer::Peer_Unknown ) { + ProbeTimeout = 0; + } + } + + if( ProbeTimeout <= 0 ) { + // regular timeout + emit peerStateReport( this ); + if( State == Peer_Unknown ) { + State = Peer_Down; + } + if( ProbeFD >= 0 ) { + // requested to stop by caller -> stop probing + ::close( ProbeFD ); + } + // no more waiting + killTimer( ev->timerId() ); + } // else sleep some more +} + +void OTPeer::stopFindingOutState( void ) { + ProbeTimeout = PREMAGICNR; +} + -- cgit v0.9.0.2