📄 e32socketmodule.cpp
字号:
/*
* ====================================================================
* e32socketmodule.cpp
*
* Copyright (c) 2005 - 2008 Nokia Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
#include "Python.h"
#include "symbian_python_ext_util.h"
#if SERIES60_VERSION>=26
#define __BC70s__
#endif
#include <eikenv.h>
#include <e32std.h>
#include <es_sock.h>
#include <in_sock.h>
#include <bt_sock.h>
#include <btmanclient.h>
#include <bttypes.h>
#include <btextnotifiers.h>
#include <btsdp.h>
#include <OBEX.h>
#include "staticarrayc.h"
#ifdef HAVE_SSL
#include <SecureSocket.h>
#endif
#include <CommDbConnPref.h>
// If building for 2.8. These headers must be copied from 2.6 SDk
#include <aplistitemlist.h>
#include <aputils.h>
#include <apselect.h>
#include <COMMDB.H>
#include "apselection.h"
#ifdef PRESDK20
#define KProtocolUnknown 0xdead
#endif
#define MaxIPAddrLength 16
#define MaxBufferSize 1024
#define MaxAttributeSize 48
#define MaxServiceNameSize 48
#define KAfBT 0
#define KWaitAll 0x100 //random number to implement socket flag MSG_WAITALL
#define RfcommService 101 //random numbers
#define ObexService 102
#define KAUT 0x0001
#define KENC 0x0002
#define KAUTHOR 0x0004
const TInt KRfcommChannel = 1;
const TUint KBtProtocolIdOBEX = 0x0008;
const TUint KObServiceClass = 0x1105;
const TInt KRFCServiceClass = 0x1101;
//#define KProtocol_TLS 1502 //random numbers
//#define KProtocol_SSL 1503
_LIT(KRFCServiceDescription,"Rfcomm Transfer");
_LIT(KObServiceDescription,"Object Exchange");
_LIT(KServerTransportName,"RFCOMM");
static PyObject * PySocket_Err(TInt);
static PyObject * PySocket_Err(char*);
/*
*.........................Bluetooth.............................*
*/
/*
* implementation of virtual class MSdpAttributeValueVisitor
*/
enum TSdpAttributeParserPanics
{
ESdpAttributeParserInvalidCommand = 1,
ESdpAttributeParserNoValue,
ESdpAttributeParserValueIsList,
ESdpAttributeParserValueTypeUnsupported
};
enum TBTServiceSearcherPanics
{
EBTServiceSearcherNextRecordRequestComplete = 1,
EBTServiceSearcherAttributeRequestResult,
EBTServiceSearcherAttributeRequestComplete,
EBTServiceSearcherInvalidControlIndex,
EBTServiceSearcherProtocolRead,
EBTServiceSearcherAttributeRequest,
EBTServiceSearcherSdpRecordDelete
};
class MSdpAttributeNotifier
{
public:
virtual void FoundElementL(TInt aKey, CSdpAttrValue& aValue) = 0;
};
#ifndef EKA2
class TSdpAttributeParser : public MSdpAttributeValueVisitor
#else
NONSHARABLE_CLASS(TSdpAttributeParser) : public MSdpAttributeValueVisitor
#endif
{
public:
enum TNodeCommand { ECheckType, ECheckValue, ECheckEnd, ESkip, EReadValue, EFinished };
struct SSdpAttributeNode { TNodeCommand iCommand; TSdpElementType iType; TInt iValue; };
typedef const TStaticArrayC<SSdpAttributeNode> TSdpAttributeList;
TSdpAttributeParser(TSdpAttributeList& aNodeList, MSdpAttributeNotifier& aObserver):
iObserver(aObserver), iNodeList(aNodeList), iCurrentNodeIndex(0) {};
TBool HasFinished() const { return CurrentNode().iCommand == EFinished; };
public: // from MSdpAttributeValueVisitor
void VisitAttributeValueL(CSdpAttrValue& aValue, TSdpElementType aType);
void StartListL(CSdpAttrValueList& /*aList*/) {};
void EndListL();
private:
void CheckTypeL(TSdpElementType aElementType) const;
void CheckValueL(CSdpAttrValue& aValue) const;
void ReadValueL(CSdpAttrValue& aValue) const
{ iObserver.FoundElementL(CurrentNode().iValue, aValue); };
const SSdpAttributeNode& CurrentNode() const
{ return iNodeList[iCurrentNodeIndex]; };
void AdvanceL();
private:
MSdpAttributeNotifier& iObserver;
TSdpAttributeList& iNodeList;
TInt iCurrentNodeIndex;
};
const TSdpAttributeParser::SSdpAttributeNode gRfcommProtocolListData[] =
{
{ TSdpAttributeParser::ECheckType, ETypeDES },
{ TSdpAttributeParser::ECheckType, ETypeDES },
{ TSdpAttributeParser::ECheckValue, ETypeUUID, KL2CAP },
{ TSdpAttributeParser::ECheckEnd },
{ TSdpAttributeParser::ECheckType, ETypeDES },
{ TSdpAttributeParser::ECheckValue, ETypeUUID, KRFCOMM },
{ TSdpAttributeParser::EReadValue, ETypeUint, KRfcommChannel },
{ TSdpAttributeParser::ECheckEnd },
{ TSdpAttributeParser::ECheckEnd },
{ TSdpAttributeParser::EFinished }
};
const TSdpAttributeParser::SSdpAttributeNode gObexProtocolListData[] =
{
{ TSdpAttributeParser::ECheckType, ETypeDES },
{ TSdpAttributeParser::ECheckType, ETypeDES },
{ TSdpAttributeParser::ECheckValue, ETypeUUID, KL2CAP },
{ TSdpAttributeParser::ECheckEnd },
{ TSdpAttributeParser::ECheckType, ETypeDES },
{ TSdpAttributeParser::ECheckValue, ETypeUUID, KRFCOMM },
{ TSdpAttributeParser::EReadValue, ETypeUint, KRfcommChannel },
{ TSdpAttributeParser::ECheckEnd },
{ TSdpAttributeParser::ECheckType, ETypeDES },
{ TSdpAttributeParser::ECheckValue, ETypeUUID, KBtProtocolIdOBEX },
{ TSdpAttributeParser::ECheckEnd },
{ TSdpAttributeParser::ECheckEnd },
{ TSdpAttributeParser::EFinished }
};
const TStaticArrayC<TSdpAttributeParser::SSdpAttributeNode> gRfcommProtocolList =
CONSTRUCT_STATIC_ARRAY_C(
gRfcommProtocolListData
);
const TStaticArrayC<TSdpAttributeParser::SSdpAttributeNode> gObexProtocolList =
CONSTRUCT_STATIC_ARRAY_C(
gObexProtocolListData
);
void TSdpAttributeParser::VisitAttributeValueL(CSdpAttrValue& aValue, TSdpElementType aType)
{
switch(CurrentNode().iCommand)
{
case ECheckType:
CheckTypeL(aType);
break;
case ECheckValue:
CheckTypeL(aType);
CheckValueL(aValue);
break;
case EReadValue:
CheckTypeL(aType);
ReadValueL(aValue);
break;
case ECheckEnd:
case EFinished:
User::Leave(KErrGeneral);
break;
case ESkip:
break;
default:
SPyErr_SetFromSymbianOSErr(ESdpAttributeParserInvalidCommand);
}
AdvanceL();
}
void TSdpAttributeParser::EndListL()
{
if (CurrentNode().iCommand != ECheckEnd)
User::Leave(KErrGeneral);
AdvanceL();
}
void TSdpAttributeParser::CheckTypeL(TSdpElementType aElementType) const
{
if (CurrentNode().iType != aElementType)
User::Leave(KErrGeneral);
}
void TSdpAttributeParser::CheckValueL(CSdpAttrValue& aValue) const
{
switch(aValue.Type())
{
case ETypeNil:
SPyErr_SetFromSymbianOSErr(ESdpAttributeParserNoValue);
break;
case ETypeUint:
if (aValue.Uint() != (TUint)CurrentNode().iValue)
User::Leave(KErrArgument);
break;
case ETypeInt:
if (aValue.Int() != CurrentNode().iValue)
User::Leave(KErrArgument);
break;
case ETypeBoolean:
if (aValue.Bool() != CurrentNode().iValue)
User::Leave(KErrArgument);
break;
case ETypeUUID:
if (aValue.UUID() != TUUID(CurrentNode().iValue))
User::Leave(KErrArgument);
break;
case ETypeDES:
case ETypeDEA:
SPyErr_SetFromSymbianOSErr(ESdpAttributeParserValueIsList);
break;
default:
SPyErr_SetFromSymbianOSErr(ESdpAttributeParserValueTypeUnsupported);
break;
}
}
void TSdpAttributeParser::AdvanceL()
{
if (CurrentNode().iCommand == EFinished)
User::Leave(KErrEof);
++iCurrentNodeIndex;
}
/* Dictionary to store remotely advertised services and relative port numbers */
struct DictElement {
TBuf8<MaxServiceNameSize> key;
int value;
};
class Dictionary: CBase {
public:
static Dictionary* NewL();
int GetValue() { return item.value; };
TBuf8<MaxServiceNameSize>& GetKey() { return item.key; };
static const TInt iOffset;
DictElement item;
private:
Dictionary(){};
TSglQueLink* iLink;
};
Dictionary* Dictionary::NewL() {
Dictionary* self = new (ELeave) Dictionary();
self->item.key.FillZ(MaxServiceNameSize);
self->item.value = 0;
return self;
}
/* It sets the offset of the link object from the start of a list element */
const TInt Dictionary::iOffset = _FOFF(Dictionary,iLink);
#ifndef EKA2
class CStack: public CBase {
#else
NONSHARABLE_CLASS(CStack): public CBase {
#endif
public:
static CStack* NewL();
~CStack();
TSglQue<Dictionary> iStack;
TSglQueIter<Dictionary> iStackIter;
private:
CStack();
};
CStack* CStack::NewL() {
CStack* self = new (ELeave) CStack;
return self;
}
CStack::CStack()
:iStack(Dictionary::iOffset), iStackIter(iStack)
{}
CStack::~CStack(){
Dictionary* d;
iStackIter.SetToFirst();
while ( (d = iStackIter++) != NULL) {
iStack.Remove(*d);
delete d;
};
}
/*
* implementation of virtual classes needed by CSdpAgent
*/
#ifndef EKA2
class BTSearcher: public CBase,
public MSdpAgentNotifier,
public MSdpAttributeNotifier
#else
NONSHARABLE_CLASS(BTSearcher): public CBase,
public MSdpAgentNotifier,
public MSdpAttributeNotifier
#endif
{
public:
BTSearcher(int);
~BTSearcher();
void SelectDeviceByDiscoveryL(TRequestStatus& aObserverRequestStatus);
void FindServiceL(TRequestStatus&);
void FindServiceL(TRequestStatus&, const TBTDevAddr&);
void AttributeRequestComplete(TSdpServRecordHandle aHandle, TInt aError);
void AttributeRequestResult(TSdpServRecordHandle aHandle, TSdpAttributeID aAttrID, CSdpAttrValue* aAttrValue);
void NextRecordRequestComplete(TInt aError, TSdpServRecordHandle aHandle, TInt aTotalRecordsCount);
TBool ReadNotStatus() { return iIsNotifierConnected; };
void WriteNotStatus(TBool aStatus) { iIsNotifierConnected = aStatus; };
TInt Port() { return iPort; };
CStack* SDPDict;
protected:
virtual const TSdpAttributeParser::TSdpAttributeList& ProtocolList()
{ return aServiceType == RfcommService ? gRfcommProtocolList : gObexProtocolList; };
virtual void FoundElementL(TInt, CSdpAttrValue&);
virtual const TUUID& ServiceClass() const { return iServiceClass; };
virtual TBool HasFinishedSearching() const { return EFalse; };
void Finished(TInt aError = KErrNone);
private:
void NextRecordRequestCompleteL(TInt aError, TSdpServRecordHandle aHandle, TInt aTotalRecordsCount);
void AttributeRequestResultL(TSdpServRecordHandle aHandle, TSdpAttributeID aAttrID, CSdpAttrValue* aAttrValue);
void AttributeRequestCompleteL(TSdpServRecordHandle, TInt aError);
public:
TBTDeviceResponseParamsPckg aResponse;
RNotifier notifier;
TBTDeviceSelectionParamsPckg selectionFilter;
private:
CSdpAgent *iAgent;
CSdpSearchPattern *iSdpSearchPattern;
TBool iIsNotifierConnected;
TBool iIsNameFound;
TBool iIsServiceFound;
TRequestStatus *iStatusObserver;
TUUID iServiceClass;
TInt iPort;
int aServiceType;
TBuf8<MaxAttributeSize> attribute;
/* since the parsing is done first at the port and later at service names, this variables is needed to avoid
to get in the dictionary an item with the right port number but meaningless name */
enum TSequence { NONE, ADDNAME, ADDATTR };
TSequence sequence;
CSdpAttrIdMatchList *iMatchList;
};
BTSearcher::BTSearcher(int s):
iIsNotifierConnected(EFalse),
iIsNameFound(EFalse),
iIsServiceFound(EFalse),
iPort(-1),
aServiceType(s)
{
if (aServiceType == RfcommService)
iServiceClass = KRFCServiceClass;
else
iServiceClass = KObServiceClass;
TRAPD(error, ( SDPDict = CStack::NewL()));
if (error != KErrNone) {
SPyErr_SetFromSymbianOSErr(error);
return;
}
attribute.FillZ(MaxAttributeSize);
sequence = NONE;
}
BTSearcher::~BTSearcher()
{
if (iIsNotifierConnected)
{
notifier.CancelNotifier(KDeviceSelectionNotifierUid);
notifier.Close();
WriteNotStatus(EFalse);
}
delete iAgent;
iAgent = NULL;
delete iMatchList;
iMatchList = NULL;
delete iSdpSearchPattern;
iSdpSearchPattern = NULL;
delete SDPDict;
}
void BTSearcher::SelectDeviceByDiscoveryL(TRequestStatus &aStatus)
{
if (!ReadNotStatus())
{
User::LeaveIfError(notifier.Connect());
WriteNotStatus(ETrue);
}
selectionFilter().SetUUID(ServiceClass());
notifier.StartNotifierAndGetResponse(aStatus, KDeviceSelectionNotifierUid, selectionFilter, aResponse);
}
void BTSearcher::FindServiceL(TRequestStatus &aStatus)
{
if (!aResponse().IsValidBDAddr())
User::Leave(KErrNotFound);
iIsServiceFound = EFalse;
iAgent = CSdpAgent::NewL(*this, aResponse().BDAddr());
if (iSdpSearchPattern != NULL) {
delete iSdpSearchPattern;
iSdpSearchPattern = NULL;
}
iSdpSearchPattern = CSdpSearchPattern::NewL();
iSdpSearchPattern->AddL(ServiceClass());
iAgent->SetRecordFilterL(*iSdpSearchPattern);
iStatusObserver = &aStatus;
iAgent->NextRecordRequestL();
}
void BTSearcher::FindServiceL(TRequestStatus &aStatus, const TBTDevAddr &address)
{
iIsServiceFound = EFalse;
iAgent = CSdpAgent::NewL(*this, address);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -