From 323d0d5ba0f8adff838a3a09d617a40de0cee1f0 Mon Sep 17 00:00:00 2001 From: James Turner Date: Sun, 9 Jun 2013 19:16:46 +0100 Subject: [PATCH] HTTP engine tweaks for SVN support. --- simgear/io/HTTPClient.cxx | 43 +++++-- simgear/io/HTTPClient.hxx | 2 + simgear/io/HTTPRequest.cxx | 10 +- simgear/io/HTTPRequest.hxx | 5 +- simgear/io/sg_netChannel.cxx | 216 ++++++++++++++++++----------------- simgear/io/sg_netChannel.hxx | 25 +++- 6 files changed, 174 insertions(+), 127 deletions(-) diff --git a/simgear/io/HTTPClient.cxx b/simgear/io/HTTPClient.cxx index 5e32d2cb..ba68a94a 100644 --- a/simgear/io/HTTPClient.cxx +++ b/simgear/io/HTTPClient.cxx @@ -53,6 +53,8 @@ const int GZIP_HEADER_FNAME = 1 << 3; const int GZIP_HEADER_COMMENT = 1 << 4; const int GZIP_HEADER_CRC = 1 << 1; +typedef std::list RequestList; + class Connection : public NetChat { public: @@ -117,13 +119,27 @@ public: virtual void handleClose() { NetChat::handleClose(); - - if ((state == STATE_GETTING_BODY) && activeRequest) { + + // closing of the connection from the server side when getting the body, + bool canCloseState = (state == STATE_GETTING_BODY); + if (canCloseState && activeRequest) { // force state here, so responseComplete can avoid closing the // socket again state = STATE_CLOSED; responseComplete(); } else { + if (activeRequest) { + activeRequest->setFailure(500, "server closed connection"); + // remove the failed request from sentRequests, so it does + // not get restored + RequestList::iterator it = std::find(sentRequests.begin(), + sentRequests.end(), activeRequest); + if (it != sentRequests.end()) { + sentRequests.erase(it); + } + activeRequest = NULL; + } + state = STATE_CLOSED; } @@ -186,6 +202,7 @@ public: } Request_ptr r = queuedRequests.front(); + r->requestStart(); requestBodyBytesToSend = r->requestBodyLength(); stringstream headerData; @@ -229,6 +246,7 @@ public: bool ok = push(headerData.str().c_str()); if (!ok) { + SG_LOG(SG_IO, SG_WARN, "HTTPClient: over-stuffed the socket"); // we've over-stuffed the socket, give up for now, let things // drain down before trying to start any more requests. return; @@ -236,8 +254,7 @@ public: while (requestBodyBytesToSend > 0) { char buf[4096]; - int len = 4096; - r->getBodyData(buf, len); + int len = r->getBodyData(buf, 4096); if (len > 0) { requestBodyBytesToSend -= len; if (!bufferSend(buf, len)) { @@ -245,13 +262,16 @@ public: state = STATE_SOCKET_ERROR; return; } + // SG_LOG(SG_IO, SG_INFO, "sent body:\n" << string(buf, len) << "\n%%%%%%%%%"); } else { - SG_LOG(SG_IO, SG_WARN, "asynchronous request body generation is unsupported"); + SG_LOG(SG_IO, SG_WARN, "HTTP asynchronous request body generation is unsupported"); break; } } - //std::cout << "did send request:" << r->url() << std::endl; + SG_LOG(SG_IO, SG_DEBUG, "did start request:" << r->url() << + "\n\t @ " << reinterpret_cast(r.ptr()) << + "\n\t on connection " << this); // successfully sent, remove from queue, and maybe send the next queuedRequests.pop_front(); sentRequests.push_back(r); @@ -308,7 +328,7 @@ public: if (result == Z_OK || result == Z_STREAM_END) { // nothing to do } else { - SG_LOG(SG_IO, SG_WARN, "got Zlib error:" << result); + SG_LOG(SG_IO, SG_WARN, "HTTP: got Zlib error:" << result); return; } @@ -607,7 +627,7 @@ private: void responseComplete() { - //std::cout << "responseComplete:" << activeRequest->url() << std::endl; + // SG_LOG(SG_IO, SG_INFO, "*** responseComplete:" << activeRequest->url()); activeRequest->responseComplete(); client->requestFinished(this); @@ -666,8 +686,8 @@ private: unsigned char* zlibOutputBuffer; bool contentGZip, contentDeflate; - std::list queuedRequests; - std::list sentRequests; + RequestList queuedRequests; + RequestList sentRequests; }; Client::Client() @@ -677,7 +697,7 @@ Client::Client() void Client::update(int waitTimeout) { - NetChannel::poll(waitTimeout); + _poller.poll(waitTimeout); ConnectionDict::iterator it = _connections.begin(); for (; it != _connections.end(); ) { @@ -715,6 +735,7 @@ void Client::makeRequest(const Request_ptr& r) if (_connections.find(connectionId) == _connections.end()) { Connection* con = new Connection(this); con->setServer(host, port); + _poller.addChannel(con); _connections[connectionId] = con; } diff --git a/simgear/io/HTTPClient.hxx b/simgear/io/HTTPClient.hxx index f200b9f4..f1bdf0d6 100644 --- a/simgear/io/HTTPClient.hxx +++ b/simgear/io/HTTPClient.hxx @@ -4,6 +4,7 @@ #include #include +#include namespace simgear { @@ -49,6 +50,7 @@ private: std::string _proxy; int _proxyPort; std::string _proxyAuth; + NetChannelPoller _poller; // connections by host typedef std::map ConnectionDict; diff --git a/simgear/io/HTTPRequest.cxx b/simgear/io/HTTPRequest.cxx index ce706957..23018d9c 100644 --- a/simgear/io/HTTPRequest.cxx +++ b/simgear/io/HTTPRequest.cxx @@ -48,6 +48,11 @@ string Request::header(const std::string& name) const return string(); } +void Request::requestStart() +{ + +} + void Request::responseStart(const string& r) { const int maxSplit = 2; // HTTP/1.1 nnn reason-string @@ -232,10 +237,9 @@ std::string Request::requestBodyType() const return "text/plain"; } -void Request::getBodyData(char*, int& count) const +int Request::getBodyData(char*, int maxCount) const { - count = 0; - return; + return 0; } } // of namespace HTTP diff --git a/simgear/io/HTTPRequest.hxx b/simgear/io/HTTPRequest.hxx index 0c6e2685..c3fe525b 100644 --- a/simgear/io/HTTPRequest.hxx +++ b/simgear/io/HTTPRequest.hxx @@ -52,10 +52,10 @@ public: /** * Retrieve the body data bytes. Will be passed the maximum body bytes - * to return in the buffer, and should update count with the actual number + * to return in the buffer, and must return the actual number * of bytes written. */ - virtual void getBodyData(char* s, int& count) const; + virtual int getBodyData(char* s, int count) const; /** * retrieve the request body content type. Default is text/plain @@ -86,6 +86,7 @@ public: protected: Request(const std::string& url, const std::string method = "GET"); + virtual void requestStart(); virtual void responseStart(const std::string& r); virtual void responseHeader(const std::string& key, const std::string& value); virtual void responseHeadersComplete(); diff --git a/simgear/io/sg_netChannel.cxx b/simgear/io/sg_netChannel.cxx index 817650ac..be8299f7 100644 --- a/simgear/io/sg_netChannel.cxx +++ b/simgear/io/sg_netChannel.cxx @@ -41,8 +41,6 @@ namespace simgear { -static NetChannel* channels = 0 ; - NetChannel::NetChannel () { closed = true ; @@ -51,31 +49,14 @@ NetChannel::NetChannel () accepting = false ; write_blocked = false ; should_delete = false ; - - next_channel = channels ; - channels = this ; + poller = NULL; } NetChannel::~NetChannel () { close(); - - NetChannel* prev = NULL ; - - for ( NetChannel* ch = channels; ch != NULL; - ch = ch -> next_channel ) - { - if (ch == this) - { - ch = ch -> next_channel ; - if ( prev != NULL ) - prev -> next_channel = ch ; - else - channels = ch ; - next_channel = 0 ; - break; - } - prev = ch ; + if (poller) { + poller->removeChannel(this); } } @@ -232,89 +213,6 @@ NetChannel::handleResolve() } } -bool -NetChannel::poll (unsigned int timeout) -{ - if (!channels) - return false ; - - enum { MAX_SOCKETS = 256 } ; - Socket* reads [ MAX_SOCKETS+1 ] ; - Socket* writes [ MAX_SOCKETS+1 ] ; - Socket* deletes [ MAX_SOCKETS+1 ] ; - int nreads = 0 ; - int nwrites = 0 ; - int ndeletes = 0 ; - int nopen = 0 ; - NetChannel* ch; - for ( ch = channels; ch != NULL; ch = ch -> next_channel ) - { - if ( ch -> should_delete ) - { - assert(ndeletes closed ) - { - if (ch -> resolving_host ) - { - ch -> handleResolve(); - continue; - } - - nopen++ ; - if (ch -> readable()) { - assert(nreads writable()) { - assert(nwrites closed ) - ch -> handleReadEvent(); - } - - for ( i=0; writes[i]; i++ ) - { - ch = (NetChannel*)writes[i]; - if ( ! ch -> closed ) - ch -> handleWriteEvent(); - } - - return true ; -} - -void -NetChannel::loop (unsigned int timeout) -{ - while ( poll (timeout) ) ; -} - - void NetChannel::handleRead (void) { SG_LOG(SG_IO, SG_WARN, "Network:" << getHandle() << ": unhandled read"); } @@ -336,4 +234,112 @@ void NetChannel::handleError (int error) } } +void +NetChannelPoller::addChannel(NetChannel* channel) +{ + assert(channel); + assert(channel->poller == NULL); + + channel->poller = this; + channels.push_back(channel); +} + +void +NetChannelPoller::removeChannel(NetChannel* channel) +{ + assert(channel); + assert(channel->poller == this); + channel->poller = NULL; + + ChannelList::iterator it = channels.begin(); + for (; it != channels.end(); ++it) { + if (*it == channel) { + channels.erase(it); + return; + } + } +} + +bool +NetChannelPoller::poll(unsigned int timeout) +{ + if (channels.empty()) { + return false; + } + + enum { MAX_SOCKETS = 256 } ; + Socket* reads [ MAX_SOCKETS+1 ] ; + Socket* writes [ MAX_SOCKETS+1 ] ; + int nreads = 0 ; + int nwrites = 0 ; + int nopen = 0 ; + NetChannel* ch; + + ChannelList::iterator it = channels.begin(); + while( it != channels.end() ) + { + NetChannel* ch = *it; + if ( ch -> should_delete ) + { + delete ch; + it = channels.erase(it); + continue; + } + + ++it; // we've copied the pointer into ch + if ( ch->closed ) { + continue; + } + + if (ch -> resolving_host ) + { + ch -> handleResolve(); + continue; + } + + nopen++ ; + if (ch -> readable()) { + assert(nreads writable()) { + assert(nwrites closed ) + ch -> handleReadEvent(); + } + + for ( int i=0; writes[i]; i++ ) + { + ch = (NetChannel*)writes[i]; + if ( ! ch -> closed ) + ch -> handleWriteEvent(); + } + + return true ; +} + +void +NetChannelPoller::loop (unsigned int timeout) +{ + while ( poll (timeout) ) ; +} + + } // of namespace simgear diff --git a/simgear/io/sg_netChannel.hxx b/simgear/io/sg_netChannel.hxx index 6cadc1f3..bf28a730 100644 --- a/simgear/io/sg_netChannel.hxx +++ b/simgear/io/sg_netChannel.hxx @@ -54,20 +54,23 @@ #define SG_NET_CHANNEL_H #include + #include +#include namespace simgear { +class NetChannelPoller; + class NetChannel : public Socket { bool closed, connected, accepting, write_blocked, should_delete, resolving_host ; - NetChannel* next_channel ; std::string host; int port; - friend bool netPoll (unsigned int timeout); - + friend class NetChannelPoller; + NetChannelPoller* poller; public: NetChannel () ; @@ -109,9 +112,19 @@ public: virtual void handleWrite (void); virtual void handleAccept (void); virtual void handleError (int error); - - static bool poll (unsigned int timeout = 0 ) ; - static void loop (unsigned int timeout = 0 ) ; + +}; + +class NetChannelPoller +{ + typedef std::vector ChannelList; + ChannelList channels; +public: + void addChannel(NetChannel* channel); + void removeChannel(NetChannel* channel); + + bool poll(unsigned int timeout = 0); + void loop(unsigned int timeout = 0); }; } // of namespace simgear -- 2.39.5