📄 evasocket.cpp
字号:
/*************************************************************************** * Copyright (C) 2004-2005 by yunfan * * yunfan_zg@163.com * * * * 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 <unistd.h>#include <stdio.h>#include <string.h>#include <arpa/inet.h>#include <sys/mman.h>#include <stdlib.h>#include <qsocketdevice.h> #include <qsocketnotifier.h>#include <qapplication.h>#include <qmutex.h>#include <qtimer.h>#include <qstringlist.h>#include <qurl.h>#include <qiodevice.h>#include <qtextstream.h>#include <qdns.h>#include <qcstring.h>#include <kdebug.h>/*! \class EvaSocket evasocket.h \brief The EvaSocket class provides a UDP or TCP connection 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); }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,"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; 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; } } 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]; 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(); base64AuthParam = QCodecs::base64Encode(para); 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.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: //Proxy Authentication Required 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);}/** ============================================================== **/HttpHeader::HttpHeader() : m_HeaderLen(0), m_ContentLen(0), m_Username(""), m_Password(""), m_Base64AuthParam(""){}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -