📄 ioqueue_symbian.cpp
字号:
/* $Id: ioqueue_symbian.cpp 1248 2007-05-03 19:56:21Z bennylp $ */
/*
* Copyright (C)2003-2006 Benny Prijono <benny@prijono.org>
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <pj/ioqueue.h>
#include <pj/assert.h>
#include <pj/errno.h>
#include <pj/list.h>
#include <pj/lock.h>
#include <pj/pool.h>
#include <pj/string.h>
#include "os_symbian.h"
class CIoqueueCallback;
/*
* IO Queue structure.
*/
struct pj_ioqueue_t
{
int eventCount;
};
/////////////////////////////////////////////////////////////////////////////
// Class to encapsulate asynchronous socket operation.
//
class CIoqueueCallback : public CActive
{
public:
static CIoqueueCallback* NewL(pj_ioqueue_t *ioqueue,
pj_ioqueue_key_t *key,
pj_sock_t sock,
const pj_ioqueue_callback *cb,
void *user_data);
//
// Start asynchronous recv() operation
//
pj_status_t StartRead(pj_ioqueue_op_key_t *op_key,
void *buf, pj_ssize_t *size, unsigned flags,
pj_sockaddr_t *addr, int *addrlen);
//
// Start asynchronous accept() operation.
//
pj_status_t StartAccept(pj_ioqueue_op_key_t *op_key,
pj_sock_t *new_sock,
pj_sockaddr_t *local,
pj_sockaddr_t *remote,
int *addrlen );
//
// Completion callback.
//
void RunL();
//
// CActive's DoCancel()
//
void DoCancel();
//
// Cancel operation and call callback.
//
void CancelOperation(pj_ioqueue_op_key_t *op_key,
pj_ssize_t bytes_status);
//
// Accessors
//
void* get_user_data() const
{
return user_data_;
}
void set_user_data(void *user_data)
{
user_data_ = user_data;
}
pj_ioqueue_op_key_t *get_op_key() const
{
return pending_data_.common_.op_key_;
}
CPjSocket* get_pj_socket()
{
return sock_;
}
private:
// Type of pending operation.
enum Type {
TYPE_NONE,
TYPE_READ,
TYPE_ACCEPT,
};
// Static data.
pj_ioqueue_t *ioqueue_;
pj_ioqueue_key_t *key_;
CPjSocket *sock_;
pj_ioqueue_callback cb_;
void *user_data_;
// Symbian data.
TPtr8 aBufferPtr_;
TInetAddr aAddress_;
// Application data.
Type type_;
union Pending_Data
{
struct Common
{
pj_ioqueue_op_key_t *op_key_;
} common_;
struct Pending_Read
{
pj_ioqueue_op_key_t *op_key_;
pj_sockaddr_t *addr_;
int *addrlen_;
} read_;
struct Pending_Accept
{
pj_ioqueue_op_key_t *op_key_;
pj_sock_t *new_sock_;
pj_sockaddr_t *local_;
pj_sockaddr_t *remote_;
int *addrlen_;
} accept_;
};
union Pending_Data pending_data_;
RSocket blank_sock_;
CIoqueueCallback(pj_ioqueue_t *ioqueue,
pj_ioqueue_key_t *key, pj_sock_t sock,
const pj_ioqueue_callback *cb, void *user_data)
: CActive(CActive::EPriorityStandard),
ioqueue_(ioqueue), key_(key), sock_((CPjSocket*)sock),
user_data_(user_data), aBufferPtr_(NULL, 0), type_(TYPE_NONE)
{
pj_memcpy(&cb_, cb, sizeof(*cb));
}
void ConstructL()
{
CActiveScheduler::Add(this);
}
void HandleReadCompletion();
CPjSocket *HandleAcceptCompletion();
};
CIoqueueCallback* CIoqueueCallback::NewL(pj_ioqueue_t *ioqueue,
pj_ioqueue_key_t *key,
pj_sock_t sock,
const pj_ioqueue_callback *cb,
void *user_data)
{
CIoqueueCallback *self = new CIoqueueCallback(ioqueue, key, sock,
cb, user_data);
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
//
// Start asynchronous recv() operation
//
pj_status_t CIoqueueCallback::StartRead(pj_ioqueue_op_key_t *op_key,
void *buf, pj_ssize_t *size,
unsigned flags,
pj_sockaddr_t *addr, int *addrlen)
{
PJ_ASSERT_RETURN(IsActive()==false, PJ_EBUSY);
PJ_ASSERT_RETURN(pending_data_.common_.op_key_==NULL, PJ_EBUSY);
flags &= ~PJ_IOQUEUE_ALWAYS_ASYNC;
pending_data_.read_.op_key_ = op_key;
pending_data_.read_.addr_ = addr;
pending_data_.read_.addrlen_ = addrlen;
aBufferPtr_.Set((TUint8*)buf, 0, (TInt)*size);
type_ = TYPE_READ;
if (addr && addrlen) {
sock_->Socket().RecvFrom(aBufferPtr_, aAddress_, flags, iStatus);
} else {
aAddress_.SetAddress(0);
aAddress_.SetPort(0);
sock_->Socket().Recv(aBufferPtr_, flags, iStatus);
}
SetActive();
return PJ_EPENDING;
}
//
// Start asynchronous accept() operation.
//
pj_status_t CIoqueueCallback::StartAccept(pj_ioqueue_op_key_t *op_key,
pj_sock_t *new_sock,
pj_sockaddr_t *local,
pj_sockaddr_t *remote,
int *addrlen )
{
PJ_ASSERT_RETURN(IsActive()==false, PJ_EBUSY);
PJ_ASSERT_RETURN(pending_data_.common_.op_key_==NULL, PJ_EBUSY);
pending_data_.accept_.op_key_ = op_key;
pending_data_.accept_.new_sock_ = new_sock;
pending_data_.accept_.local_ = local;
pending_data_.accept_.remote_ = remote;
pending_data_.accept_.addrlen_ = addrlen;
// Create blank socket
blank_sock_.Open(PjSymbianOS::Instance()->SocketServ());
type_ = TYPE_ACCEPT;
sock_->Socket().Accept(blank_sock_, iStatus);
SetActive();
return PJ_EPENDING;
}
//
// Handle asynchronous RecvFrom() completion
//
void CIoqueueCallback::HandleReadCompletion()
{
if (pending_data_.read_.addr_) {
PjSymbianOS::Addr2pj(aAddress_,
*(pj_sockaddr_in*)pending_data_.read_.addr_);
pending_data_.read_.addr_ = NULL;
}
if (pending_data_.read_.addrlen_) {
*pending_data_.read_.addrlen_ = sizeof(pj_sockaddr_in);
pending_data_.read_.addrlen_ = NULL;
}
pending_data_.read_.op_key_ = NULL;
}
//
// Handle asynchronous Accept() completion.
//
CPjSocket *CIoqueueCallback::HandleAcceptCompletion()
{
CPjSocket *pjNewSock = new CPjSocket(blank_sock_);
if (pending_data_.accept_.new_sock_) {
*pending_data_.accept_.new_sock_ = (pj_sock_t)pjNewSock;
pending_data_.accept_.new_sock_ = NULL;
}
if (pending_data_.accept_.local_) {
TInetAddr aAddr;
pj_sockaddr_in *ptr_sockaddr;
blank_sock_.LocalName(aAddr);
ptr_sockaddr = (pj_sockaddr_in*)pending_data_.accept_.local_;
PjSymbianOS::Addr2pj(aAddr, *ptr_sockaddr);
pending_data_.accept_.local_ = NULL;
}
if (pending_data_.accept_.remote_) {
TInetAddr aAddr;
pj_sockaddr_in *ptr_sockaddr;
blank_sock_.RemoteName(aAddr);
ptr_sockaddr = (pj_sockaddr_in*)pending_data_.accept_.remote_;
PjSymbianOS::Addr2pj(aAddr, *ptr_sockaddr);
pending_data_.accept_.remote_ = NULL;
}
if (pending_data_.accept_.addrlen_) {
*pending_data_.accept_.addrlen_ = sizeof(pj_sockaddr_in);
pending_data_.accept_.addrlen_ = NULL;
}
return pjNewSock;
}
//
// Completion callback.
//
void CIoqueueCallback::RunL()
{
Type cur_type = type_;
type_ = TYPE_NONE;
if (cur_type == TYPE_READ) {
//
// Completion of asynchronous RecvFrom()
//
/* Clear op_key (save it to temp variable first!) */
pj_ioqueue_op_key_t *op_key = pending_data_.read_.op_key_;
pending_data_.read_.op_key_ = NULL;
// Handle failure condition
if (iStatus != KErrNone) {
if (cb_.on_read_complete) {
cb_.on_read_complete( key_, op_key,
-PJ_RETURN_OS_ERROR(iStatus.Int()));
}
return;
}
HandleReadCompletion();
/* Call callback */
if (cb_.on_read_complete) {
cb_.on_read_complete(key_, op_key, aBufferPtr_.Length());
}
} else if (cur_type == TYPE_ACCEPT) {
//
// Completion of asynchronous Accept()
//
/* Clear op_key (save it to temp variable first!) */
pj_ioqueue_op_key_t *op_key = pending_data_.read_.op_key_;
pending_data_.read_.op_key_ = NULL;
// Handle failure condition
if (iStatus != KErrNone) {
if (pending_data_.accept_.new_sock_)
*pending_data_.accept_.new_sock_ = PJ_INVALID_SOCKET;
if (cb_.on_accept_complete) {
cb_.on_accept_complete( key_, op_key, PJ_INVALID_SOCKET,
-PJ_RETURN_OS_ERROR(iStatus.Int()));
}
return;
}
CPjSocket *pjNewSock = HandleAcceptCompletion();
// Call callback.
if (cb_.on_accept_complete) {
cb_.on_accept_complete( key_, op_key, (pj_sock_t)pjNewSock,
PJ_SUCCESS);
}
}
ioqueue_->eventCount++;
}
//
// CActive's DoCancel()
//
void CIoqueueCallback::DoCancel()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -