📄 qt-ikstransport.cpp
字号:
/* ikstransport implementation using QT** 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 the GNU Public Licence (GPL) version 2** See http://www.gnu.org/ for further details of the GPL.*/#include <iksemel.h>#include "qt-ikstransport-private.h"#include <sys/types.h>#include <stdio.h>#include <string.h>#include <qsocket.h>#include <qstring.h>// force C linkage#include "qt-ikstransport.h"/////////////////////////////////////////////////////////////* Helper classes to keep track of when the instance gets deleted out from under the notify function. The class that might go away either isa or hasa NotifyOnDelete instance. Functions which need to know when the NotifyOnDelete subclass has been deleted create a DeletionMonitor at the top of their scope and check it after calling any functions that might cause the NotifyOnDelete subclass instance to be deleted. These classes work even for rentrant functions because the flag value is propagated up the stack as each DeletionMonitor is destroyed.*/class NotifyOnDelete {public: NotifyOnDelete() : mpDeleted( NULL ) {} void markDeleted() { if (mpDeleted) { //qDebug("NotifyOnDelete -- claiming to be deleted!.\n"); *mpDeleted = true; mpDeleted = NULL; } } virtual ~NotifyOnDelete() { if (mpDeleted) { //qDebug("NotifyOnDelete -- setting flag.\n"); *mpDeleted = true; //qDebug("NotifyOnDelete -- set flag!\n"); } } protected: bool* setObserver(bool* flagToSet) { bool* old = mpDeleted; mpDeleted = flagToSet; return old; }private: bool* mpDeleted; friend class DeletionMonitor;};class DeletionMonitor{public: DeletionMonitor(NotifyOnDelete* pNotifier) : mpNotifier( pNotifier), mWasDeleted(false) { //qDebug("[%p]:DeletionMonitor -- create.\n", this); mpOldFlag = pNotifier->setObserver(&mWasDeleted); } ~DeletionMonitor() { //qDebug("[%p]:DeletionMonitor -- destroy.\n", this); if (mpOldFlag) { // i.e. Propagate the flag value up the stack as the stack unwinds. // Cool huh. *mpOldFlag = mWasDeleted; } //qDebug("[%p]:DeletionMonitor -- %p %i.\n", this, mpOldFlag, mWasDeleted); if (!mWasDeleted) { // Restore the flag hook for the stack frame above us. mpNotifier->setObserver(mpOldFlag); } } bool wasDeleted() const { return mWasDeleted; }private: NotifyOnDelete* mpNotifier; bool* mpOldFlag; bool mWasDeleted;};////////////////////////////////////////////////////////////int QTIkstransportInstance::IksTConnectAsync(iksparser *prs, void **socket, const char *server, const char *server_name, int port, void *notify_data, iksAsyncNotify *notify_func){ if (!server_name) { server_name = server; } QTIkstransportInstance* instance = new QTIkstransportInstance(prs, server, server_name, port, notify_data, notify_func); if (!instance) { return IKS_NOMEM; } int ret = instance->iksTConnectAsync(socket); if (ret != IKS_OK) { delete instance; *socket = NULL; } return ret;}#define IMPL_INST( socket_ptr) ( (QTIkstransportInstance*) socket_ptr )void QTIkstransportInstance::IksTClose(void *socket) { IMPL_INST( socket )->startDeferredDelete();}int QTIkstransportInstance::IksTSend(void *socket, const char *data, size_t len){ return IMPL_INST( socket )->iksTSend(data, len);}int QTIkstransportInstance::IksTRecv(void *socket, char *buffer, size_t buf_len, int timeout){ return IMPL_INST( socket )->iksTRecv(buffer, buf_len, timeout);}////////////////////////////////////////////////////////////// QSocket slots////////////////////////////////////////////////////////////void QTIkstransportInstance::hostFound(){ if (mIgnoreNotifications) { return; } notify(IKS_ASYNC_RESOLVED);}void QTIkstransportInstance::connected(){ if (mIgnoreNotifications) { return; } DeletionMonitor monitor(mpDeletionNotifier); // Send the opening header. int ret = iks_send_header (mpParser, mServerName); if (monitor.wasDeleted()) { return; // Bail out. } if (ret != IKS_OK) { notify(IKS_ASYNC_ERROR, IKS_NET_RWERR); return; } notify(IKS_ASYNC_CONNECTED);}void QTIkstransportInstance::connectionClosed(){ if (mIgnoreNotifications) { return; } mIgnoreNotifications = true; notify(IKS_ASYNC_ERROR, IKS_NET_DROPPED);}void QTIkstransportInstance::delayedCloseFinished(){ // hmmm... is there anything to do here.}void QTIkstransportInstance::readyRead(){ if (mIgnoreNotifications ) { return; } // We just notify. The client code must explictly // call iks_recv() if (mpSocket->bytesAvailable() > 0) { notify(IKS_ASYNC_READ, mpSocket->bytesAvailable()); }}void QTIkstransportInstance::bytesWritten( int nbytes ){ if (mIgnoreNotifications) { return; } notify(IKS_ASYNC_WRITTEN, (int)nbytes);}void QTIkstransportInstance::error ( int code ){ if (mIgnoreNotifications) { return; } int value; switch (code) { case QSocket::ErrConnectionRefused: value = IKS_NET_NOCONN; case QSocket::ErrHostNotFound: value = IKS_NET_NODNS; case QSocket::ErrSocketRead: value = IKS_NET_RWERR; default: value = IKS_NET_UNKNOWN; } notify(IKS_ASYNC_ERROR, value);}////////////////////////////////////////////////////////////QTIkstransportInstance::QTIkstransportInstance(iksparser *prs, const char *server, const char *server_name, int port, void *notify_data, iksAsyncNotify *notify_func) : mpParser(prs), mpSocket (NULL), mIgnoreNotifications(false), mServer(server), mServerName(server_name), mPort(port), mNotifyData(notify_data), mpfNotifyFunc(notify_func), mpDeletionNotifier(NULL){ mpDeletionNotifier = new NotifyOnDelete();}int QTIkstransportInstance::iksTConnectAsync(void **socketptr){ mpSocket = new QSocket(); if (!mpSocket) { return IKS_NOMEM; } mIgnoreNotifications = false; QObject::connect(mpSocket, SIGNAL(hostFound(void)), this, SLOT(hostFound(void))); QObject::connect(mpSocket, SIGNAL(connected(void)), this, SLOT(connected(void))); QObject::connect(mpSocket, SIGNAL(connectionClosed(void)), this, SLOT(connectionClosed(void))); QObject::connect(mpSocket, SIGNAL(delayedCloseFinished(void)), this, SLOT(delayedCloseFinished(void))); QObject::connect(mpSocket, SIGNAL(readyRead(void)), this, SLOT(readyRead(void))); QObject::connect(mpSocket, SIGNAL(bytesWritten(int)), this, SLOT(bytesWritten(int))); QObject::connect(mpSocket, SIGNAL(error(int)), this, SLOT(error(int))); *socketptr = this; DeletionMonitor monitor(mpDeletionNotifier); mpSocket->connectToHost(mServer, mPort); if (monitor.wasDeleted()) { // hmmmm... not sure if this can happen. // Bail out if a signal emmitted from connectToHost called into the iksSocketHook // and called iks_disconnect(). return IKS_NET_NOCONN; } return IKS_OK;}void QTIkstransportInstance::startDeferredDelete(){ qDebug("QTIkstransportInstance::startDeferredDelete -- called."); mIgnoreNotifications = true; if (mpSocket) { // Disconnect all signals. mpSocket->disconnect(); mpSocket->close(); } // Tell observers that this object is going away. mpDeletionNotifier->markDeleted(); // Ask the QT event loop to delete us. // i.e. don't delete the QSocket instance from inside it's // own signal. deleteLater(); // Tell the client code that the socket is closed. // We don't wait to do this ~QTIkstransportInstance because // then you could get out of order events if the client // code connects again before the destructor runs. if (notify(IKS_ASYNC_CLOSED)) { return; // already deleted! }}QTIkstransportInstance::~QTIkstransportInstance(){ qDebug("QTIkstransportInstance::~QTIkstransportInstance -- called.\n"); if (mpSocket) { qDebug("QTIkstransportInstance::~QTIkstransportInstance -- deleting socket.\n"); mIgnoreNotifications = true; delete mpSocket; mpSocket = NULL; } delete mpDeletionNotifier;}int QTIkstransportInstance::iksTSend(const char *data, size_t len){ if (!mpSocket) { return IKS_NET_RWERR; } if (mpSocket->state() != QSocket::Connected) { // The QSocket isn't ready yet. return IKS_NET_NOCONN; } Q_LONG written = mpSocket->writeBlock(data, len); if (written == (Q_LONG)len) { if (notify(IKS_ASYNC_WRITE, len)) { return IKS_NET_NOCONN; } return IKS_OK; } return IKS_NET_RWERR;}int QTIkstransportInstance::iksTRecv(char *buffer, size_t buf_len, int timeout){ if (!mpSocket) { return -1; } if (timeout != 0) { // We don't support waiting. return -1; } if (mpSocket->state() != QSocket::Connected) { // The QSocket isn't ready yet. return 0; } int bytesToRead = mpSocket->bytesAvailable() < buf_len - 1 ? mpSocket->bytesAvailable() : buf_len - 1; if (bytesToRead < 1) { return 0; } Q_LONG read = mpSocket->readBlock(buffer, bytesToRead); if (read == - 1) { if (notify(IKS_ASYNC_ERROR, IKS_NET_RWERR)) { return -1; } } return read;}bool QTIkstransportInstance::notify(int reason, int data0, int data1){ // Note: Client code in the mpNotifyFunc might do something which // causes a call back into this function, so it must be reentrant. DeletionMonitor monitor(mpDeletionNotifier); iksasyncevent eventInst; eventInst.event = reason; eventInst.data0 = data0; eventInst.data1 = data1; if (mpfNotifyFunc) { mpfNotifyFunc(mNotifyData, &eventInst); } return monitor.wasDeleted();}ikstransport qt_ikstransport = { IKS_TRANSPORT_V1, NULL /* Synchronous connect not supported. */, &QTIkstransportInstance::IksTSend, &QTIkstransportInstance::IksTRecv, &QTIkstransportInstance::IksTClose, &QTIkstransportInstance::IksTConnectAsync,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -