⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 csocket.cpp

📁 symbina上可以使用一个xml解析器,对开发网络应用很有好处
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/* External socket implementation using Symbian sockets.
** Copyright (C) 2004-2005 Darrell Karbott (djk2005@users.sf.net)
** This code is free software; you can redistribute it and/or
** modify it under the terms of GNU Lesser General Public License.
** See http://www.gnu.org/ for further details of the LGPL.
*/

#include "CSocket.h"
#include "delmon.h"

#include <e32svr.h>
#include <in_sock.h>
#include <eikenv.h>

////////////////////////////////////////////////////////////
// Debug logging.
// #define ENABLE_CSOCKET_LOGGING 1
#ifdef ENABLE_CSOCKET_LOGGING
void Log(void* p, const char* msg);
void Log(void* p, const char* msg, TInt errCode);
#define CSOCKET_LOG( p, msg ) { Log( p, msg ); }
#define CSOCKET_LOG_ERR( p, msg, errCode ) { Log( p, msg, errCode ); }
#else 
#define CSOCKET_LOG( p, msg )
#define CSOCKET_LOG_ERR( p, msg, errCode )
#endif 
////////////////////////////////////////////////////////////

// The size of the buffer we use to read the socket.
const TInt RX_BUFFER_LEN = 32768;

// The size of the buffer we keep for writing to 
// the socket.  If the client manages to write more
// than this much data ahead of the socket, it
// will panic. The client should check BytesWriteable() 
// before writing in order to keep this from happening.
// NOTE: I bumped this from 16k.
const TInt TX_BUFFER_LEN = 32768;

// placate linker.
EXPORT_C MSocketObserver::~MSocketObserver() {}

// Helper function to dispatch panics.
static void CSocketPanic(TInt aPanic) 
{
  User::Panic(KCSocketPanicCategory, aPanic);
}

////////////////////////////////////////////////////////////
// Active Objects to handle name resolution, connecting
// reading and writing.
////////////////////////////////////////////////////////////

class CSocketSetup  : public CActive {
public:
  CSocketSetup(CSocket* pOwner);
  ~CSocketSetup();

  void ConstructL();

  TBool ResolveL(const TDesC& host, TInt port);
  TBool ConnectL();
  void DoCancel();
  void RunL();
  TInt RunError();

  static CSocketSetup* NewL(CSocket* pOwner);
private:
  CSocket* iSocket;

  // Members for name resolution.
  RHostResolver iResolver;
  TNameEntry iHostEntry;
  TBufC<128> iAddressName;
  TInetAddr iAddr;
  TInt iPort;
};

class CSocketTx  : public CActive {
public:
  CSocketTx(CSocket* pOwner);
  ~CSocketTx();
  void ConstructL();
  void EnqueueWrite();
  void Write(const TDesC8&);
  TInt SendLen() const;
  TInt BytesBuffered() const;
  void DoCancel();
  // calls CSocket::Notify
  void RunL();
  TInt RunError();
  static CSocketTx* NewL(CSocket* pOwner);
private:
  CSocket* iSocket;
  TInt iBytesSent;
  HBufC8* iBuffer;
  TPtrC8 iCurrentWrite;
};

class CSocketRx  : public CActive {
public:
  CSocketRx(CSocket* pOwner, TBool autoRestart);
  ~CSocketRx();
  void ConstructL();
  TBool Read(TBool bEnabled);
  const TDesC8& RecvdData() const;
  void DoCancel();
  // calls CSocket::Notify
  void RunL();
  TInt RunError();

  static CSocketRx* NewL(CSocket* pOwner, TBool autoRestart = ETrue);
  
private:
  void EnqueueRead();

  TSockXfrLength iXfrLen;
  TBuf8<RX_BUFFER_LEN> iBuffer;
  CSocket* iSocket;
  TBool iAutoRestart;
  TBool iSendLastChar;
  TUint8 iLastChar;
};

////////////////////////////////////////////////////////////

CSocketSetup* CSocketSetup::NewL(CSocket* pOwner)
{
  CSocketSetup* self = new (ELeave) CSocketSetup(pOwner);
  CleanupStack::PushL(self);
  self->ConstructL();
  CleanupStack::Pop(); // self
  return self;
}

CSocketSetup::CSocketSetup(CSocket* pOwner) 
  : CActive(EPriorityStandard), iSocket(pOwner)
{
}

CSocketSetup::~CSocketSetup()
{
  Cancel();
  iResolver.Close();
}

void CSocketSetup::ConstructL()
{
  CActiveScheduler::Add(this);
}

// Starts name resolution which starts connection
// when it finishes.
TBool CSocketSetup::ResolveL(const TDesC& host, TInt port)
{
  CSOCKET_LOG(this, "CSocketSetup::ResolveL -- called");

  __ASSERT_ALWAYS(!IsActive(), CSocketPanic(CSocket::INVFAILED));
  __ASSERT_ALWAYS(iSocket->State() == CSocket::EClosed,
                  CSocketPanic(CSocket::INVFAILED));
  iAddressName = host;
  iPort = port;

  iSocket->SetState(CSocket::EResolving);

  if(iSocket->Notify(MSocketObserver::EResolving)) { return ETrue; }
  if (iSocket->State() != CSocket::EResolving) { return EFalse; }

  TInt result = iResolver.Open(*(iSocket->SocketServ()),
                               KAfInet, 
                               KProtocolInetTcp);
  if (result != KErrNone) {
    iSocket->HandleError(result);
  }

  User::LeaveIfError(result);
  iResolver.GetByName(iAddressName, iHostEntry, iStatus);
  
  SetActive();
  return EFalse;
}

// hmmm... doesn't leave. 
TBool CSocketSetup::ConnectL()
{
  CSOCKET_LOG(this, "CSocketSetup::ConnectL -- called");

  iSocket->SetState(CSocket::EConnecting);

  if (iSocket->Notify(MSocketObserver::EConnecting)) { return ETrue; };
  if (iSocket->State() != CSocket::EConnecting) { return EFalse; }

  // Force error on timeout. 
  // djk 20040212 this didn't make any difference
  //iSocket->Socket()->SetOpt(KSolInetTcp,KSoTcpKeepAlive, 1); 

  // Note: no return code.
  iSocket->Socket()->Connect(iAddr, iStatus);
  SetActive();

  return EFalse;
}

void CSocketSetup::DoCancel()
{
  if (iSocket->State() == CSocket::EResolving) {
    iResolver.Cancel();
    iResolver.Close();
  }
  else if (iSocket->State() == CSocket::EConnecting) {
    iSocket->Socket()->CancelConnect();
  }
}

void CSocketSetup::RunL()
{
  if (iStatus == KErrNone) {
    switch (iSocket->State()) {
    case CSocket::EResolving:
      // Stash address from name resolver.
      iAddr = iHostEntry().iAddr;
      // Resolver just gives us the name, we need to set
      // the port explicitly.
      iAddr.SetPort(iPort);
      iResolver.Close(); 
      if (ConnectL()) {
        return;
      }
      break;
    case CSocket::EConnecting:
      CSOCKET_LOG(this, "CSocketSetup::RunL -- Connected");
      iSocket->SetState(CSocket::EConnected);
      if (iSocket->Notify(MSocketObserver::EConnected)) { return;}
      if (iSocket->State() != CSocket::EConnected) { return; }
      break;
    case CSocket::EConnected:
    case CSocket::EClosed:
    case CSocket::EError:
      break;
    }
  }
  else {
    CSOCKET_LOG_ERR(this, "CSocketSetup::RunL -- iStatus != KErrNone, err: ", iStatus.Int());
    iSocket->HandleError(iStatus.Int());
  }
}

TInt CSocketSetup::RunError()
{
  CSOCKET_LOG(this, "CSocketSetup::RunError -- called");
  iSocket->HandleError(KErrCouldNotConnect);
  return KErrNone;
}

CSocketTx* CSocketTx::NewL(CSocket* pOwner)
{
  CSocketTx* self = new (ELeave) CSocketTx(pOwner);
  CleanupStack::PushL(self);
  self->ConstructL();
  CleanupStack::Pop(); // self
  return self;
}

CSocketTx::CSocketTx(CSocket* pOwner)
  : CActive(EPriorityStandard), iSocket(pOwner), iBytesSent(0)
{
}

CSocketTx::~CSocketTx()
{
  Cancel();
  delete iBuffer;
  iBuffer = NULL;
}

void CSocketTx::ConstructL()
{
  CActiveScheduler::Add(this);

  // hmmmm...Make this a parameter?
  // + 1 so we have space to null terminate.
  iBuffer = HBufC8::NewMaxL(TX_BUFFER_LEN + 1);
  // Set the default size to 0. 
  // This is not done autmatically.
  iBuffer->Des().Zero();
}


// It is legal to call this when the buffer is empty.
void CSocketTx::EnqueueWrite()
{
  __ASSERT_ALWAYS(!IsActive(),CSocketPanic(CSocket::INVFAILED));

  if (iCurrentWrite.Size() > 0) {
    // Release previous data.
    TPtr8 ptr(iBuffer->Des());
    ptr.Delete(0, iCurrentWrite.Size());
    __ASSERT_DEBUG( ptr.Size()  == iBuffer->Des().Size(),
                    CSocketPanic(CSocket::INVFAILED));
  }

  // I used to do this, but I would see rare silent write failures.
  //iCurrentWrite.Set(iBuffer->Des());

  // Bound size of writes.  Why 1024? magick number. HACK   
  TInt nBytes = iBuffer->Size() > 1024 ? 1024 : iBuffer->Size();
  iCurrentWrite.Set(iBuffer->Des().Ptr(), nBytes);

  if (iCurrentWrite.Size() > 0) {
    iSocket->Socket()->Write(iCurrentWrite, iStatus);
    SetActive();
  }
}

void CSocketTx::Write(const TDesC8& data)
{
  __ASSERT_ALWAYS(iSocket->State() == CSocket::EConnected,
                  CSocketPanic(CSocket::INVFAILED));

  // Hmmm.. can't just resize the buffer when we run out of space because
  // it might be in use.
  __ASSERT_ALWAYS(data.Length() + iBuffer->Des().Size() <= iBuffer->Des().MaxLength() - 1,
                  CSocketPanic(CSocket::INVFAILED));

  // Make a deep copy of the buffer.
  TPtr8 ptr(iBuffer->Des());
  ptr.Append(data);

  if (!IsActive()) {
    EnqueueWrite();
  }
  // Otherwise, RunL() will write buffered data when 
  // the current write finishes.
}

TInt CSocketTx::SendLen() const
{
  return iBytesSent;
}

TInt CSocketTx::BytesBuffered() const
{
  return iBuffer->Length();
}

void CSocketTx::DoCancel()
{
  iSocket->Socket()->CancelWrite();
}

void CSocketTx::RunL()
{
  if (iStatus == KErrNone) {
    // Set length before callback.
    iBytesSent = iCurrentWrite.Size();
    if (iSocket->State() == CSocket::EConnected) {
      if (iSocket->Notify(MSocketObserver::EWrite)) { return; }
      if (iSocket->State() != CSocket::EConnected) { return; }
      // Client code in the callback called CSocket::Write().
      if (IsActive()) { return; }
      // Kick off the next write if there's any buffered
      // data left.
      EnqueueWrite();
    }
    else {
      // Hmmm... assert here?
      CSOCKET_LOG_ERR(this, "CSocketTx::RunL -- write in unexpected state!, state", iSocket->State());
    }
  }
  else {
    CSOCKET_LOG_ERR(this, "CSocketTx::RunL -- iStatus != KErrNone, err: ", iStatus.Int());
    iSocket->HandleError(iStatus.Int());
  }
}

TInt CSocketTx::RunError()
{
  CSOCKET_LOG(this, "CSocketTx::RunError -- called");
  iSocket->HandleError(KErrUnknown);
  return KErrNone;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -