eva0.4.1源码看看5

/***************************************************************************
 *   Copyright (C) 2004 by yunfan                                          *
 *   [email protected]                                                     *
 *                                                                         *
 *   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.             *
 ***************************************************************************/
#ifndef EVASOCKET_H
#define EVASOCKET_H
#include <qhostaddress.h>
#include <qcstring.h>   //cstring,,这么多没用过的类
#include <qobject.h>
// Implementing UDP & TCP connections to Tencent Server
class QSocketDevice;
class QSocketNotifier;
                    
class EvaSocket : public QObject {//这个socket类,也包括http?
    Q_OBJECT
public:
    enum Type { TCP, UDP};
    enum Status { Init, Connecting, Ready, Failed, None, BytesReadWrong};
    EvaSocket(const QHostAddress &host, const short port, const Type type = UDP);
    ~EvaSocket();
                       
    const Type getConnectType() const { return connectionType; }
                           
    void setHost( const QHostAddress &address, const short port);
    const QHostAddress &getHostAddress() const { return server; }
    const short getHostPort() const { return serverPort; }
    const Status getStatus() const { return connectionStatus; }
                       
    void closeConnection();
    void startConnecting();
    bool write(const char *buf, const int len);
    bool read(char *buf, int len);
    const QHostAddress getSocketAddress();
    const unsigned short getSocketPort();
    void setWriteNotifierEnabled(bool enabled);
signals:
    void isReady(); // emit when socket is connected
    void receivedData(int);     // emit after receiving data from server
    void exceptionEvent(int);      // emit whenever exception happens
    void writeReady();
protected:
    QSocketDevice *connectSocket;
    QSocketNotifier *socketReadNotifier;
    QSocketNotifier *socketWriteNotifier;
                       
    int receivedLength;
    char *receivedBuffer;
private:
    Type connectionType;
    QHostAddress server;
    short serverPort;
                       
    Status connectionStatus;  //  connected or not
private slots:
    void slotWriteReady(int);
    void slotReceiveReady(int);
};
// call read after receiving proxyEvent(Proxy_Ready) SIGNAL
class EvaHttpProxy : public EvaSocket {//基于socket
    Q_OBJECT
public:
    enum ProxyStatus { Proxy_None, Proxy_TCP_Ready, Proxy_Connecting, Proxy_Ready,
                Proxy_Need_Auth, Proxy_Read_Error, Proxy_Error};
    EvaHttpProxy(const QHostAddress &proxyHost, const short proxyPort, const QString username = QString::null,
                                const QString password = QString::null);
    void setDestinationServer(const QString &server, const int port); // server could be IP or URL
    const QString &getDestinationServer() const { return destinationAddress; }
    void setAuthParameter(const QString &username, const QString &password);
    const QCString &getBase64AuthParam() const { return base64AuthParam;}//主要就是进行了一些认证
    void setBase64AuthParam(const QCString &param) { base64AuthParam = param;  status = Proxy_None; }
    bool doInitConnecting();
    bool doAuthConnecting();
                       
    const ProxyStatus getProxyStatus() const { return status; }
signals:
    void dataArrived(int);
    void proxyEvent( int );
    void socketException(int);
    void proxyWriteReady();
public slots:
    void tcpReady();
    void slotWriteReady();
private:
    ProxyStatus status;
    QString destinationAddress;
    QCString base64AuthParam;
    QCString sentBuffer;
    char *readBuffer;
    void received(int len);
private slots:
    void parseData(int len);
};
#endif



/***************************************************************************
 *   Copyright (C) 2004-2005 by yunfan                                     *
 *   [email protected]                                                     *
 *                                                                         *
 *   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 "evasocket.h"
#include "qmdcodec.h"    //待研究
#include <stdlib.h>
#include <qsocketdevice.h>
#include <qsocketnotifier.h>
#include <qapplication.h>
#include <qmutex.h>
#include <qtimer.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/mman.h>    //干嘛的
/*!
    \class EvaSocket evasocket.h
    \brief The EvaSocket class provides a UDP or TCP connection  看来不包含http
             
    It provides a very simple non-blocking socket connection.
    socketWriteNotifier is only used once to notify that the connection is ready
    to write, after isReady() emited, socketWriteNotifier is disabled unless
    setHost() is called.
 */
EvaSocket::EvaSocket(const  QHostAddress &host, const short port, const Type type)
    : socketReadNotifier(NULL), socketWriteNotifier(NULL)
{
    connectionStatus = None;
    receivedLength = 0;
    receivedBuffer = NULL;
    connectionType = type;
        server = host;
    serverPort = port;
    if(connectionType == UDP){
        connectSocket = new QSocketDevice(QSocketDevice::Datagram);  //udp被当成device,qt这么认为
    }else{
        connectSocket = new QSocketDevice(QSocketDevice::Stream);
        connectSocket->setBlocking(false);
            socketWriteNotifier =  new QSocketNotifier(connectSocket->socket(),
                            QSocketNotifier::Write,0,"writeNotifier");  //写通知,这个是基于epoll?select?poll?
        QObject::connect(socketWriteNotifier,SIGNAL(activated(int)),SLOT(slotWriteReady(int)));
        socketWriteNotifier->setEnabled(false);
    }
    socketReadNotifier = new QSocketNotifier(connectSocket->socket(),
                        QSocketNotifier::Read,0,"readNotifier");
    connectionStatus = Init;
    QObject::connect(socketReadNotifier,SIGNAL(activated(int)),SLOT(slotReceiveReady(int)));
    socketReadNotifier->setEnabled(false);
}
EvaSocket::~EvaSocket()
{
    delete connectSocket;
    if(socketReadNotifier) {
        socketReadNotifier->setEnabled(false);
        delete socketReadNotifier;
    }
    if(socketWriteNotifier) {
        socketWriteNotifier->setEnabled(false);
        delete socketWriteNotifier;
    }
}
const QHostAddress EvaSocket::getSocketAddress( )
{
    if(connectSocket) return connectSocket->address();
    return QHostAddress();
}
const unsigned short EvaSocket::getSocketPort( )
{
    if(connectSocket) return connectSocket->port();
    return 0;
}
void EvaSocket::setHost(const QHostAddress &address, const short port)
{
    server = address;
    serverPort = port; 
    connectionStatus = None;
    if(connectSocket->isValid()){
        delete connectSocket;
        if(socketReadNotifier) {
            socketReadNotifier->setEnabled(false);
            delete socketReadNotifier;
        }
        if(socketWriteNotifier) {
            socketWriteNotifier->setEnabled(false);
            delete socketWriteNotifier;
        }
        if(connectionType == UDP){
            connectSocket = new QSocketDevice(QSocketDevice::Datagram);
        }else{
            connectSocket = new QSocketDevice(QSocketDevice::Stream);
            connectSocket->setBlocking(false);
            socketWriteNotifier =  new QSocketNotifier(connectSocket->socket(),
                                QSocketNotifier::Write,0,"writeNotifier");
            QObject::connect(socketWriteNotifier,SIGNAL(activated(int)),SLOT(slotWriteReady(int)));
            socketWriteNotifier->setEnabled(false);
        }
        socketReadNotifier = new QSocketNotifier(connectSocket->socket(),
                            QSocketNotifier::Read,0,"SocketNotifier");
        QObject::connect(socketReadNotifier,SIGNAL(activated(int)),SLOT(slotReceiveReady(int)));
        if(connectionType == TCP)
            socketReadNotifier->setEnabled(false);
    }
    connectionStatus = Init;
}
void EvaSocket::closeConnection()
{
    if(connectSocket->isOpen()) connectSocket->close();
    connectionStatus = None;
    receivedLength = 0;
}
void EvaSocket::startConnecting()
{
    if(connectionStatus != Init) {
        emit exceptionEvent(connectionStatus);
        return;
    }
    connectionStatus = Connecting;
    if(connectionType == TCP){
        if(!connectSocket->connect(server, serverPort)){
            fprintf(stderr,"connecting server failed\nError type: ");
            connectionStatus = Failed;
            switch(connectSocket->error()){
                case QSocketDevice::NoError:
                    fprintf(stderr,"NoError\n");
                    break;
                case QSocketDevice::AlreadyBound:
                    fprintf(stderr,"AlreadyBound\n");
                    break;
                case QSocketDevice::Inaccessible:
                    fprintf(stderr,"Inaccessible\n");
                    break;
                case QSocketDevice::NoResources:
                    fprintf(stderr,"NoResources\n");
                    break;
                case QSocketDevice::InternalError:
                    fprintf(stderr,"InternalError\n");
                    break;
                case QSocketDevice::Impossible:
                    fprintf(stderr,"Impossible\n");
                    break;
                case QSocketDevice::NoFiles:
                    fprintf(stderr,"NoFiles\n");
                    break;
                case QSocketDevice::ConnectionRefused:
                    fprintf(stderr,"ConnectionRefused\n");
                    break;
                case QSocketDevice::NetworkFailure:
                    fprintf(stderr,"NetworkFailure\n");
                    break;
                case QSocketDevice::UnknownError:
                    fprintf(stderr,"UnknownError\n");
                    break;
                default:
                    printf("not listed error\n");
            }
            emit exceptionEvent(connectionStatus);
            return;
        }
    }
    if(socketReadNotifier) socketReadNotifier->setEnabled(true);
    if(connectionType == TCP && socketWriteNotifier) {
        socketWriteNotifier->setEnabled(true);
    }else{
        connectionStatus = Ready;
        emit isReady();
    }
}
bool EvaSocket::write(const char *buf, const int len)
{
    if(connectionStatus != Ready || !buf ) return false;
    if(!connectSocket->isValid()){
        if(connectionType == TCP && socketReadNotifier && socketWriteNotifier){
            socketReadNotifier->setEnabled(false);
            socketWriteNotifier->setEnabled(false);
        }
        emit exceptionEvent(Failed);
        return false;
    }
    QMutex mutex; //写之前,锁一下?锁什么?
    mutex.lock();
    int BytesSent = 0;
    if(socketWriteNotifier) socketWriteNotifier->setEnabled(false);
    if(connectionType == UDP){
        BytesSent =connectSocket->writeBlock(buf, len, server, serverPort);
    }else{
        int bytes = 0;
        int times = 0;
//      printf("---++++++++--   EvaSocket::write -- BytesSent:%d, len: %d\n", BytesSent, len);
        while(BytesSent < len){
            bytes =connectSocket->writeBlock(buf + BytesSent, len - BytesSent);
            if(bytes == -1) {
                printf("EvaSocket::write retry :%d\n", times);
                if(!connectSocket->error()){
                    if(times>20){
                        fprintf(stderr, "EvaSocket::write -- error : retried %d times\n", times);
                        mutex.unlock();
                        return false;
                    }
                    usleep(10000);
                    //qApp->processEvents();
                    times++;
                    continue;
                }else
                    break;
            }
            BytesSent += bytes;
//          while( connectionStatus != WriteReady && BytesSent < len ){
//              qApp->processEvents();
//              usleep(10 * 1000);
//              if(!connectSocket->isValid()){
//                  connectionStatus = oldStatus;
//                  mutex.unlock();
//                  return false;
//              }
//          }
//          printf("                --- EvaSocket::write -- bytes:%d, len: %d\n", bytes, len);
        }
//      printf("                EvaSocket::write -- BytesSent:%d, len: %d\n", BytesSent, len);
    }
    mutex.unlock();
    if(len != BytesSent){
        printf("EvaSocket::write -- error code: %d\n", connectSocket->error());
        return false;
    }
    return true;
}
bool EvaSocket::read(char *buf, int len)
{
    if(connectionStatus != Ready || receivedLength != len || !buf ){
        printf("EvaSocket::read -- receivedLength: %d, len: %d\n", receivedLength, len);
        return false;
    }
    memcpy(buf, receivedBuffer, receivedLength);
    if(socketReadNotifier) socketReadNotifier->setEnabled(true);
    return true;
}
void EvaSocket::setWriteNotifierEnabled( bool enabled )
{
    if(socketWriteNotifier) socketWriteNotifier->setEnabled(enabled);
}
void EvaSocket::slotWriteReady(int /*socket */)
{
    if(socketWriteNotifier) socketWriteNotifier->setEnabled(false);
    if(connectionStatus == Connecting){
        connectionStatus = Ready;
        emit isReady();
    } else{
        emit writeReady();
    }
}
void EvaSocket::slotReceiveReady(int /*socket*/)
{
    if( (socketReadNotifier->type() != QSocketNotifier::Read) || (!connectSocket->isValid()) ){
        socketReadNotifier->setEnabled(false);
        printf("EvaSocket::slotReceiveReady -- socket not valid or notifier not set to Read \n");
        emit exceptionEvent(Failed);
        return;
    }
                 
    int ByteCount = 0;
    ByteCount = connectSocket->bytesAvailable();
             
    if(receivedBuffer!=NULL) delete receivedBuffer;
    receivedBuffer = new char[ByteCount * 2]; 
    //read都不锁,write锁的什么
    receivedLength = connectSocket->readBlock(receivedBuffer,ByteCount*2);
    if(!receivedLength){
        printf("EvaSocket::slotReceiveReady -- connection closed due to ZERO byte\n");
        socketReadNotifier->setEnabled(false);//不停的开关这个通知
        emit exceptionEvent(Failed);
        return;
    }
             
    if(receivedLength == -1){
        printf("EvaSocket::slotReceiveReady -- readBlock return -1\n");
        emit exceptionEvent(Failed);
        return;
    }
    if(socketReadNotifier) socketReadNotifier->setEnabled(false);
    emit receivedData(receivedLength);
    if(receivedLength != ByteCount)
        printf("EvaSocket::slotReceiveReady -- bytesAvailable() might not be accurate.\n");
}
/* =========================================================== */
EvaHttpProxy::EvaHttpProxy(const QHostAddress &proxyHost, const short proxyPort, const QString username, const QString password)
    : EvaSocket(proxyHost, proxyPort, EvaSocket::TCP),
    status(Proxy_None),
    destinationAddress(""),
    base64AuthParam(""),
    readBuffer(NULL)
{
    if(username!=QString::null && password!= QString::null){
        setAuthParameter(username, password);
    }
    QObject::connect(this, SIGNAL(isReady()), SLOT(tcpReady()));
    QObject::connect(this, SIGNAL(writeReady()), SLOT(slotWriteReady()));
    QObject::connect(this, SIGNAL(receivedData(int)), SLOT(parseData(int)));
    QObject::connect(this, SIGNAL(exceptionEvent(int)), SIGNAL(socketException(int)));
}
void EvaHttpProxy::setDestinationServer(const QString &server, const int port) // server could be IP or URL
{
    destinationAddress = server + ':' + QString::number(port);// qq http proxy server port: 443,改成规定的格式
    status = Proxy_None;
}
void EvaHttpProxy::setAuthParameter(const QString &username, const QString &password)
{
    QCString para = (username + ':' + password).local8Bit(); //规定的格式,QString?qt帮助里看不到这个类
    base64AuthParam = QCodecs::base64Encode(para);//这是个什么code?QTextCodec?
    status = Proxy_None;
}
bool EvaHttpProxy::doInitConnecting()
{
    if(getStatus() != EvaSocket::Ready) return false;
    if(destinationAddress == "") return false;
        //这个是关键的格式,哪里知道的
    sentBuffer = "CONNECT " + destinationAddress.local8Bit() + " HTTP/1.1\r\n" +
        "Accept: */*\r\n" + "Content-Type: text/html\r\nProxy-Connection: Keep-Alive\r\n" +
        "Content-length: 0\r\n\r\n";
    status = Proxy_Connecting;
    return write(sentBuffer.data(), sentBuffer.length());
}
bool EvaHttpProxy::doAuthConnecting()
{
    if(getStatus() != EvaSocket::Ready) return false;
    if(destinationAddress == "") return false;
    if(base64AuthParam == "") return false;
             
    sentBuffer = "CONNECT " + destinationAddress.local8Bit() + " HTTP/1.1\r\n" +
        "Proxy-Authorization: Basic " + base64AuthParam + "\r\n" +
        "Accept: */*\r\nContent-Type: text/html\r\nProxy-Connection: Keep-Alive\r\n" +
        "Content-length: 0\r\n\r\n";
    status = Proxy_Connecting;
    return write(sentBuffer.data(), sentBuffer.length());
}
void EvaHttpProxy::tcpReady()
{
    printf("EvaHttpProxy::tcpReady -- TCP connection ready\n");
    if(destinationAddress == "") {
        emit proxyEvent(Proxy_TCP_Ready);
        return;
    }
             
    if(base64AuthParam != "")
        doAuthConnecting();
    else
        doInitConnecting();
}
void EvaHttpProxy::slotWriteReady()
{
    if ( status == Proxy_Ready )
        emit proxyWriteReady();
}
void EvaHttpProxy::parseData(int len)
{  
    if(readBuffer!=NULL) free(readBuffer);
    readBuffer = (char *)malloc((len+1) * sizeof(char));
    if(!read(readBuffer, len)){
        emit proxyEvent(Proxy_Read_Error);
        return;
    }
    readBuffer[len]=0x00;
    QString replyBuffer(readBuffer);
    if(replyBuffer.startsWith("HTTP/1.")){ // this is for RedHat 9, the old Qt dosen't support QString::startsWith(const QString &str, bool cs) const
        int replyCode = replyBuffer.mid(9, 3).toInt();
        fprintf(stderr, "Proxy Server Reply Code: %d\n",replyCode);
        switch(replyCode){
        case 200:
            status = Proxy_Ready;
            emit proxyEvent(Proxy_Ready);
            break;
        case 407:
            status = Proxy_Need_Auth;
            emit proxyEvent(Proxy_Need_Auth);
            break;
        case 501:  // "Not Support"
        case 502:  // "Proxy Error"
        default:
            status = Proxy_Error;
            emit proxyEvent(Proxy_Error);
            break;
        }
        return;
    }
    if(status == Proxy_Ready)
        dataArrived(len);
}


越看问题越多啊,难道这些用的是qt很早之前的版本,很多类,根本找不到。应该是。


你可能感兴趣的:(eva,源码看看)