📄 csocket.cpp
字号:
}
CSocketRx* CSocketRx::NewL(CSocket* pOwner, TBool autoRestart)
{
CSocketRx* self = new (ELeave) CSocketRx(pOwner, autoRestart);
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(); // self
return self;
}
CSocketRx::CSocketRx(CSocket* pOwner, TBool autoRestart)
: CActive(EPriorityStandard), iSocket(pOwner), iAutoRestart(autoRestart)
{
}
CSocketRx::~CSocketRx()
{
Cancel();
}
void CSocketRx::ConstructL()
{
CActiveScheduler::Add(this);
}
TBool CSocketRx::Read(TBool bEnabled)
{
__ASSERT_ALWAYS(iSocket->State() == CSocket::EConnected,
CSocketPanic(CSocket::INVFAILED));
if (bEnabled && (!IsActive())) {
if (iSendLastChar && (iSocket->State() == CSocket::EConnected)) {
// REDFLAG: test this code path.
// Special case send of last character if the buffer
// was completely full.
iBuffer.SetLength(2);
iBuffer[0] = iLastChar;
iBuffer[1] = 0;
iSendLastChar = EFalse;
if (iSocket->Notify(MSocketObserver::ERead)) { return ETrue; }
if (iSocket->State() != CSocket::EConnected) { return EFalse; }
}
EnqueueRead();
}
else if ((!bEnabled) && IsActive()) {
// REDFLAG think this through. I am not sure that this code
// path has ever been tested.
CSOCKET_LOG(this, "CSocketRx::Read -- canceled.");
Cancel();
}
return EFalse;
}
const TDesC8& CSocketRx::RecvdData() const
{
return iBuffer;
}
void CSocketRx::DoCancel()
{
iSocket->Socket()->CancelRecv();
}
void CSocketRx::RunL()
{
iSendLastChar = EFalse;
iLastChar = '\0';
TInt len = 0;
if (iStatus == KErrNone) {
if (iXfrLen() == RX_BUFFER_LEN) {
CSOCKET_LOG(this, "CSocketRx::RunL -- Hit buffer wrap case.");
// Special case to handle full buffer.
iLastChar = iBuffer[RX_BUFFER_LEN - 1];
iSendLastChar = ETrue;
len = RX_BUFFER_LEN - 1;
}
else {
__ASSERT_ALWAYS(iXfrLen() < RX_BUFFER_LEN, CSocketPanic(CSocket::INVFAILED));
len = iXfrLen();
}
// Set the length of the buffer.
iBuffer.SetLength(len + 1);
// Push a \0 ahead of the end of the
// buffer so that we can read the
// buffer constents as an old school
// C string.
iBuffer[len] = 0;
if (iSocket->State() == CSocket::EConnected) {
// Notify client.
// They can call CSocket::RecvdData() to
// get the data, but only within the scope of this
// callback. OBC
if (iSocket->Notify(MSocketObserver::ERead)) {return;}
if (iSocket->State() != CSocket::EConnected) { return; }
if (iSendLastChar && (iSocket->State() == CSocket::EConnected)) {
// Special case send of last character if the buffer
// was completely full.
iBuffer.SetLength(2);
iBuffer[0] = iLastChar;
iBuffer[1] = 0;
iSendLastChar = EFalse;
if (iSocket->Notify(MSocketObserver::ERead)) { return; }
if (iSocket->State() != CSocket::EConnected) { return; }
}
if (iSocket->State() == CSocket::EConnected && iAutoRestart) {
// Kick off the next read.
EnqueueRead();
}
}
else {
CSOCKET_LOG_ERR(this, "CSocketRx::RunL -- Unexpected state!, state: ", iSocket->State());
}
}
else {
iSocket->HandleError(iStatus.Int());
}
}
TInt CSocketRx::RunError()
{
CSOCKET_LOG(this, "CSocketRx::RunError -- called");
// Underwhelming. But this shouldn't happen
iSocket->HandleError(KErrUnknown);
return KErrNone;
}
void CSocketRx::EnqueueRead()
{
__ASSERT_ALWAYS(!IsActive(),
CSocketPanic(CSocket::INVFAILED));
iBuffer.Zero();
iSocket->Socket()->RecvOneOrMore(iBuffer,0,iStatus, iXfrLen);
SetActive();
}
////////////////////////////////////////////////////////////
// CSocket implementation.
// Almost all of CSocket's actual functionality is
// delegated to the Active Object implementations.
////////////////////////////////////////////////////////////
EXPORT_C CSocket* CSocket::NewL()
{
CSocket* self = new (ELeave) CSocket();
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(); // self
return self;
}
CSocket::CSocket() :
iObserver(NULL),
iSetupAO(NULL), iTxAO(NULL), iRxAO(NULL), iState(CSocket::EClosed), iLastError(0)
{
__ASSERT_DEBUG(sizeof(char) == sizeof(TUint8),
CSocketPanic(INVFAILED));
CSOCKET_LOG(this, "CSocket::CSocket");
}
EXPORT_C CSocket::~CSocket()
{
CSOCKET_LOG(this, "CSocket::~CSocket");
// This lets callers up the stack know that
// the instance has been deleted.
CNotifyOnDelete* victim = iDeletionNotifier;
iDeletionNotifier = NULL;
delete victim;
Close();
DeleteDelegates();
iSocketServ.Close();
iState = EClosed;
}
void CSocket::ConstructL()
{
// Make a connection to the socket server
TInt err=iSocketServ.Connect();
User::LeaveIfError(err);
iDeletionNotifier = new (ELeave) CNotifyOnDelete;
}
EXPORT_C void CSocket::SetObserver(MSocketObserver* pObserver)
{
iObserver = pObserver;
}
EXPORT_C TBool CSocket::ConnectL(const TDesC& host, TInt port, TBool readAutoRestart)
{
CSOCKET_LOG(this, "CSocket::ConnectL -- called");
// Reset to a known state.
if (Close()) {
return ETrue;
}
DeleteDelegates();
// Open a socket
TInt err=iSocket.Open(iSocketServ, KAfInet, KSockStream, KProtocolInetTcp);
User::LeaveIfError(err);
iSetupAO = CSocketSetup::NewL(this);
iTxAO = CSocketTx::NewL(this);
iRxAO = CSocketRx::NewL(this, readAutoRestart);
return iSetupAO->ResolveL(host, port);
}
EXPORT_C const TDesC8& CSocket::RecvdData() const
{
return iRxAO->RecvdData();
}
EXPORT_C TInt CSocket::SendLen() const
{
return iTxAO->SendLen();
}
EXPORT_C TInt CSocket::BytesBuffered() const
{
return iTxAO->BytesBuffered();
}
EXPORT_C TInt CSocket::BytesWriteable() const
{
return TX_BUFFER_LEN - iTxAO->BytesBuffered();
}
EXPORT_C TInt CSocket::LastError() const
{
return iLastError;
}
EXPORT_C TBool CSocket::EnableRead(TBool bEnabled)
{
return iRxAO->Read(bEnabled);
}
EXPORT_C void CSocket::Write(const TDesC8& data)
{
iTxAO->Write(data);
}
EXPORT_C TBool CSocket::Close()
{
CSOCKET_LOG(this, "CSocket::Close -- called");
if (iState == EClosed) {
return EFalse;
}
CSOCKET_LOG(this, "CSocket::Close -- closing");
iSetupAO->Cancel();
iTxAO->Cancel();
iRxAO->Cancel();
iSocket.CancelAll();
iSocket.Close();
iState = EClosed;
if (Notify(MSocketObserver::EClosed)) { return ETrue; }
return EFalse;
}
EXPORT_C CSocket::TState CSocket::State() const
{
return iState;
}
RSocket* CSocket::Socket()
{
return &iSocket;
}
RSocketServ* CSocket::SocketServ()
{
return &iSocketServ;
}
TBool CSocket::Notify(const MSocketObserver::TSocketReason& r)
{
// Don't do this if you are logging over the socket! or you get a loop.
CSOCKET_LOG_ERR(this, "CSocket::Notify -- called, reason: ", (TInt)r);
if (iObserver) {
if (iDeletionNotifier) {
TDeletionMonitor monitor(iDeletionNotifier);
iObserver->SocketNotify(this, r);
return monitor.WasDeleted();
}
else {
iObserver->SocketNotify(NULL, r);
return ETrue;
}
}
return EFalse;
}
void CSocket::HandleError(TInt error)
{
CSOCKET_LOG_ERR(this, "CSocket::HandleError -- error: ", error);
iLastError = error;
iState = EError;
if (Notify(MSocketObserver::EError)) {
return;
}
// It is up to the client code to call Close at this point.
}
void CSocket::DeleteDelegates()
{
if (iSetupAO) {
delete iSetupAO;
iSetupAO = NULL;
}
if (iTxAO) {
delete iTxAO;
iTxAO = NULL;
}
if (iRxAO) {
delete iRxAO;
iRxAO = NULL;
}
}
void CSocket::SetState(const TState& state)
{
iState = state;
}
////////////////////////////////////////////////////////////
// Quick and dirty logging to file.
#ifdef ENABLE_CSOCKET_LOGGING
#include <stdio.h>
void DumpStringToFile(const char* msg)
{
FILE* fOut = fopen("c:/csocket.log", "a+");
if (fOut) {
fprintf(fOut, msg);
fflush(fOut);
fclose(fOut);
}
}
void Log(void* p, const char* txt)
{
TBuf8<256> msg;
msg.AppendNum((TUint)p, EHex);
msg.Append(_L8(" "));
msg.Append(TPtrC8((const TUint8*)txt, strlen(txt)));
msg.Append(_L8("\n"));
DumpStringToFile((const char*)msg.PtrZ());
}
void Log(void* p, const char* txt, TInt errCode)
{
TBuf8<256> msg;
msg.AppendNum((TUint)p, EHex);
msg.Append(_L8(" "));
msg.Append(TPtrC8((const TUint8*)txt, strlen(txt)));
msg.Append(_L8(" "));
msg.AppendNum(errCode);
msg.Append(_L8("\n"));
DumpStringToFile((const char*)msg.PtrZ());
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -