📄 symbian-ikstransport.cpp
字号:
/* ikstransport implementation using Symbian 7.0 Socket APIs** 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 "iksemel.h" // hmmmm <> ?#include "symbian-ikstransport.h"#include "CSocket.h"#include "delmon.h"#include <string.h> #include <utf.h>class CNotifyOnDelete;class CSymbianTransportInstance : public CBase, public MSocketObserver {public: // Static hook functions used to fill in the ikstransport struct. static TInt IksTConnectAsync(iksparser *prs, void **socketptr, const char *server, const char *server_name, TInt port, void *notify_data, iksAsyncNotify *notify_func); static void IksTClose(void *socket); static TInt IksTSend(void *socket, const char *data, size_t len); static TInt IksTRecv(void *socket, char *buffer, size_t buf_len, TInt timeout);protected: CSymbianTransportInstance(iksparser *prs, const char *server, const char *server_name, TInt port, void *notify_data, iksAsyncNotify *notify_func); // Finishes constructing the instance. TInt IksConnectAsync(void **socketptr); ~CSymbianTransportInstance(); TInt IksSend(const char *data, size_t len); TInt IksRecv(char *buffer, size_t buf_len, TInt timeout); // Returns true if the instance was deleted during the call. TBool Notify(TInt reason, TInt data0 = 0, TInt data1 = 0); // MSocketObserver implementation. virtual void SocketNotify(CSocket* pSocket, const TSocketReason& reason);private: iksparser* iParser; TBool iIgnoreNotifications; TInt iAlreadyRead; TBuf8<128> iServer; TBuf8<128> iServerName; TInt iPort; void* iNotifyData; iksAsyncNotify* iNotifyFunc; // Used by Notify() to figure out when the instance has // been deleted out from under it. CNotifyOnDelete* iDeletionNotifier; TBool iIsDeleting; CSocket* iSocket;};EXPORT_C TInt CSymbianTransportInstance::IksTConnectAsync(iksparser *prs, void **socket, const char *server, const char *server_name, TInt port, void *notify_data, iksAsyncNotify *notify_func){ if (!server_name) { server_name = server; } CSymbianTransportInstance* instance = new CSymbianTransportInstance(prs, server, server_name, port, notify_data, notify_func); if (!instance) { return IKS_NOMEM; } TInt ret = instance->IksConnectAsync(socket); if (ret != IKS_OK) { delete instance; *socket = NULL; } return ret;}#define IMPL_INST( socket_ptr) ( (CSymbianTransportInstance*) socket_ptr )EXPORT_C void CSymbianTransportInstance::IksTClose(void *socket) { delete IMPL_INST( socket );}EXPORT_C TInt CSymbianTransportInstance::IksTSend(void *socket, const char *data, size_t len){ return IMPL_INST( socket )->IksSend(data, len);}EXPORT_C TInt CSymbianTransportInstance::IksTRecv(void *socket, char *buffer, size_t buf_len, TInt timeout){ return IMPL_INST( socket )->IksRecv(buffer, buf_len, timeout);}CSymbianTransportInstance::CSymbianTransportInstance(iksparser *prs, const char *server, const char *server_name, TInt port, void *notify_data, iksAsyncNotify *notify_func) : iParser(prs), iIgnoreNotifications(EFalse), iAlreadyRead(0), iPort(port), iNotifyData(notify_data), iNotifyFunc(notify_func), iDeletionNotifier(NULL), iIsDeleting(EFalse), iSocket(NULL){ iServer.Append((const TUint8*)server, strlen(server)); iServer.ZeroTerminate(); iServerName.Append((const TUint8*)server_name, strlen(server_name)); iServerName.ZeroTerminate();}TInt CSymbianTransportInstance::IksConnectAsync(void **socketptr){ TBuf<128> fatName; TInt ret = CnvUtfConverter::ConvertToUnicodeFromUtf8(fatName, iServer); if (ret < 0) { return IKS_NET_UNKNOWN; } iDeletionNotifier = new CNotifyOnDelete(); if (!iDeletionNotifier) { return IKS_NOMEM; } TRAPD(err, iSocket = CSocket::NewL()); if (err != KErrNone) { return IKS_NET_UNKNOWN; // hmmm.... } iIgnoreNotifications = EFalse; *socketptr = this; TDeletionMonitor monitor(iDeletionNotifier); iSocket->SetObserver(this); TBool deleted = EFalse; TRAP(err, deleted = iSocket->ConnectL(fatName, iPort, EFalse)); if (monitor.WasDeleted()) { // Client code called iks_disconnect from // the socket hook. *socketptr = NULL; return IKS_NET_NOCONN; } if (err != KErrNone || deleted) { return IKS_NET_NOCONN; } return IKS_OK;}CSymbianTransportInstance::~CSymbianTransportInstance(){ iIsDeleting = ETrue; if (iSocket) { iIgnoreNotifications = ETrue; delete iSocket; iSocket = NULL; Notify(IKS_ASYNC_CLOSED); } delete iDeletionNotifier;}TInt CSymbianTransportInstance::IksSend(const char *data, size_t len){ if (!iSocket) { return IKS_NET_NOCONN; } if (iSocket->State() != CSocket::EConnected) { // The socket isn't ready yet. return IKS_NET_NOCONN; } if (((TInt)len) > iSocket->BytesWriteable()) { // The write buffer overflowed! // Hmmm this is a recoverable error, but the client code // has no way of knowing that. return IKS_NET_RWERR; } if (Notify(IKS_ASYNC_WRITE, len)) { return IKS_NET_NOCONN; // already deleted! } TPtrC8 ptr((const TUint8*)data, len); iSocket->Write(ptr); return IKS_OK;}TInt CSymbianTransportInstance::IksRecv(char *buffer, size_t buf_len, TInt timeout){ if (!iSocket) { return -1; } if (timeout != 0) { // We don't support waiting. return -1; } if (iSocket->State() == CSocket::EClosed || iSocket->State() == CSocket::EError) { return -1; // Illegal state, won't recover. } if (iSocket->State() == CSocket::EResolving || iSocket->State() == CSocket::EConnecting) { return 0; // Not fully connected yet. } // Important: Don't feed \0's into the parser. TInt len = iSocket->RecvdData().Length() - 1; if (len < 1) { // REDFLAG: required. I don't think so, but this should be harmless. // Refill the read buffer. iSocket->EnableRead(ETrue); return 0; } TInt bytesToRead = len - iAlreadyRead; if (((size_t)bytesToRead) > buf_len) { bytesToRead = buf_len; } if (bytesToRead < 1) { // Refill the read buffer. iSocket->EnableRead(ETrue); return 0; } strncpy(buffer, (const char*)iSocket->RecvdData().Ptr() + iAlreadyRead, bytesToRead); iAlreadyRead += bytesToRead; if (iAlreadyRead >= iSocket->RecvdData().Length() - 1) { // Refill the read buffer. iSocket->EnableRead(ETrue); } return bytesToRead;}TBool CSymbianTransportInstance::Notify(TInt reason, TInt data0, TInt data1){ if (!iNotifyFunc) { return EFalse; } iksasyncevent eventInst; eventInst.event = reason; eventInst.data0 = data0; eventInst.data1 = data1; if (iIsDeleting) { iNotifyFunc(iNotifyData, &eventInst); return EFalse; // Not deleted yet. hmmmm. } // Note: Client code in the iNotifyFunc might do something which // causes a call back into this function, so it must be reentrant. TDeletionMonitor monitor(iDeletionNotifier); iNotifyFunc(iNotifyData, &eventInst); return monitor.WasDeleted();}void CSymbianTransportInstance::SocketNotify(CSocket* pSocket, const TSocketReason& reason){ if ((!pSocket) && (reason == EClosed)) { // The socket instance is being deleted. iSocket = NULL; // The destructor will post an event. return; } if (iIgnoreNotifications) { return; } switch (reason) { case EResolving: break; case EConnecting: if (Notify(IKS_ASYNC_RESOLVED)) { return; } break; case EConnected: { // Send the opening header. TDeletionMonitor monitor(iDeletionNotifier); TInt ret = iks_send_header (iParser, (const char*)iServerName.PtrZ()); if (monitor.WasDeleted()) { return; // Bail out. } if (ret != IKS_OK) { Notify(IKS_ASYNC_ERROR, IKS_NET_RWERR); return; } if(Notify(IKS_ASYNC_CONNECTED)) { return; // Already deleted. } // Turn on ERead callbacks. iSocket->EnableRead(ETrue); } break; case ERead: iAlreadyRead = 0; if (Notify(IKS_ASYNC_READ, iSocket->RecvdData().Length())) { return; } break; case EWrite: if (Notify(IKS_ASYNC_WRITTEN, (TInt)iSocket->SendLen())) { return; } break; case EError: { // Ignore all other notifications. iIgnoreNotifications = ETrue; TInt errCode = IKS_NET_UNKNOWN; switch (iSocket->LastError()) { case KErrEof: errCode = IKS_NET_DROPPED; break; case KErrNotFound: errCode = IKS_NET_NODNS; break; case KErrWrite: errCode = IKS_NET_RWERR; break; case KErrTimedOut: // drop through on purpose. case KErrCouldNotConnect: errCode = IKS_NET_NOCONN; break; default: errCode = IKS_NET_UNKNOWN; } if (Notify(IKS_ASYNC_ERROR, errCode, iSocket->LastError())) { return; } } break; case EClosed: // iIgnoreNotifications keeps us from // getting here during a normal iks_disconnect // so if we are seeing this, then the other end // must have dropped the connection. if (Notify(IKS_ASYNC_ERROR, IKS_NET_DROPPED)) { return; } break; }}ikstransport symbian_ikstransport = { IKS_TRANSPORT_V1, /* ABI version */ NULL /* Synchronous connect not supported. */, &CSymbianTransportInstance::IksTSend, &CSymbianTransportInstance::IksTRecv, &CSymbianTransportInstance::IksTClose, &CSymbianTransportInstance::IksTConnectAsync,};EXPORT_C ikstransport* iks_symbian_ikstransport(){ return &symbian_ikstransport;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -