Vegastrike 0.5.1 rc1  1.0
Original sources for Vegastrike Evolved
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
VsnetHTTPSocket Class Reference

#include <vsnet_sockethttp.h>

Inheritance diagram for VsnetHTTPSocket:
VsnetSocketBase

Public Member Functions

 VsnetHTTPSocket (const AddressIP &remote_ip, const std::string &host, const std::string &path, SocketSet &set)
 
 VsnetHTTPSocket (const std::string &url, SocketSet &set)
 
virtual bool lower_selected (int datalen=-1)
 
virtual int lower_sendbuf ()
 
virtual void lower_clean_sendbuf ()
 
bool sendstr (const std::string &data)
 
bool recvstr (std::string &data)
 
virtual bool need_test_writable ()
 
virtual bool write_on_negative ()
 
virtual int optPayloadSize () const
 
virtual bool isActive ()
 
void resendData ()
 
void reopenConnection ()
 
virtual bool isReadyToSend (fd_set *)
 
virtual void dump (std::ostream &ostr) const
 
- Public Member Functions inherited from VsnetSocketBase
 VsnetSocketBase (int fd, const char *socktype, SocketSet &set)
 
virtual ~VsnetSocketBase ()
 
bool valid () const
 
int get_fd () const
 
int close_fd ()
 
const char * get_socktype () const
 
bool set_block ()
 
bool set_nonblock ()
 
bool get_nonblock () const
 
void disconnect (const char *s)
 
virtual int get_write_fd () const
 
void setSet (SocketSet *set)
 

Friends

std::ostream & operator<< (std::ostream &ostr, const VsnetHTTPSocket &s)
 

Additional Inherited Members

- Protected Member Functions inherited from VsnetSocketBase
virtual void child_disconnect (const char *s)
 
- Protected Attributes inherited from VsnetSocketBase
int _fd
 
SocketSet_set
 

Detailed Description

Definition at line 18 of file vsnet_sockethttp.h.

Constructor & Destructor Documentation

VsnetHTTPSocket::VsnetHTTPSocket ( const AddressIP remote_ip,
const std::string &  host,
const std::string &  path,
SocketSet set 
)

Definition at line 11 of file vsnet_sockethttp.cpp.

12  :
13  VsnetSocketBase( -1, "http", set )
14  , _path( path )
15  , _hostheader( host )
16  , _incompleteheadersection( 0 )
17  , _content_length( 0 )
18  , _send_more_data( false )
19  , sendDataPos( 0 )
20 {
21  numRetries = 0;
22  timeToNextRequest = 0;
23  readHeader = false;
24  ischunked = false;
25  this->_remote_ip = remote_ip;
26  ischunked = false;
27  chunkedlen = 0;
28  chunkedchar = '\0';
29  readingchunked = false;
30 }
VsnetHTTPSocket::VsnetHTTPSocket ( const std::string &  url,
SocketSet set 
)

Definition at line 97 of file vsnet_sockethttp.cpp.

References hostFromURI(), and remoteIPFromURI().

97  :
98  VsnetSocketBase( -1, "http", set )
99  , _incompleteheadersection( 0 )
100  , _content_length( 0 )
101  , _send_more_data( false )
102  , sendDataPos( 0 )
103 {
104  numRetries = 0;
105  timeToNextRequest = 0;
106  readHeader = false;
107  std::string dummy;
108  unsigned short port;
109  this->_remote_ip = remoteIPFromURI( uri );
110  hostFromURI( uri, dummy, this->_hostheader, this->_path, port );
111  ischunked = false;
112  readingchunked = false;
113  chunkedlen = 0;
114  chunkedchar = '\0';
115 }

Member Function Documentation

void VsnetHTTPSocket::dump ( std::ostream &  ostr) const
virtual

Definition at line 139 of file vsnet_sockethttp.cpp.

Referenced by operator<<().

140 {
141  //VsnetSocketBase::dump( ostr );
142  ostr<<"URI: http://"<<_remote_ip<<_path;
143 }
bool VsnetHTTPSocket::isActive ( )
virtual

Implements VsnetSocketBase.

Definition at line 92 of file vsnet_sockethttp.cpp.

93 {
94  return _content_length == 0 && !dataToReceive.empty();
95  //return waitingToReceive!=false;
96 }
bool VsnetHTTPSocket::isReadyToSend ( fd_set *  write_set_select)
virtual

Reimplemented from VsnetSocketBase.

Definition at line 133 of file vsnet_sockethttp.cpp.

References VsnetSocketBase::get_write_fd(), and need_test_writable().

134 {
135  if ( get_write_fd() < 0 || FD_ISSET( get_write_fd(), write_set_select ) )
136  return need_test_writable();
137  return false;
138 }
void VsnetHTTPSocket::lower_clean_sendbuf ( )
virtual

Called when we noticed that the primary file descriptor is closed but data remains in the send queue.

Reimplemented from VsnetSocketBase.

Definition at line 171 of file vsnet_sockethttp.cpp.

References VsnetSocketBase::_fd, and reopenConnection().

172 {
173  if (waitingToReceive.empty() && this->_fd == -1)
175 }
bool VsnetHTTPSocket::lower_selected ( int  datalen = -1)
virtual

Implements VsnetSocketBase.

Definition at line 330 of file vsnet_sockethttp.cpp.

References VsnetSocketBase::_fd, VsnetSocketBase::close_fd(), COUT, VsnetSocketBase::get_fd(), hostFromURI(), ishex(), VsnetOSS::recv(), remoteIPFromURI(), resendData(), and vsnetEWouldBlock().

331 {
332  if ( waitingToReceive.empty() ) {
333  if (this->_fd >= 0) {
334  //dataToSend.size()==0&&
335  this->close_fd();
336  this->_fd = -1; //don't bother keepalive
337  }
338  return false;
339  }
340  if (this->_fd == -1) {
341  resendData();
342  return false;
343  }
344  char rcvbuf[1440];
345  int ret = 0;
346  int bufpos = 0;
347  while (datalen != 0) {
348  int dataToRead;
349  int dataIWantToRead = 1400;
350  if (_content_length > 0)
351  dataIWantToRead = _content_length;
352  dataToRead = dataIWantToRead;
353  if (datalen > 0)
354  dataToRead = datalen < dataIWantToRead ? datalen : dataIWantToRead;
355  //cout<<" Reading "<<dataToRead<<" characters...";
356  int ret = VsnetOSS::recv( get_fd(), &rcvbuf, dataToRead, 0 );
357  if (ret > 0) cout<<"READ DATA: "<<std::string( rcvbuf, ret )<<endl; //DELETEME!
358  if (ret <= 0) cout<<"recv returned "<<ret<<endl;
359  if (ret == 0) {
360  //It is not an error if closed without a Content-Length header.
361  if ( _content_length >= 0
362  && ( (readHeader == false /*set to false on success return*/ && dataToReceive.length()
363  == 0) || readHeader == true ) ) {
364  //incomplete transfer...
365  printf( "Server closed in reading...resending\n" );
366  resendData();
367  return false;
368  }
369  datalen = 0;
370  _content_length = 0;
371  break; //Done reading!
372  } else if (ret < 0) {
373  if ( vsnetEWouldBlock() ) {
374  datalen = 0;
375  return false;
376  }
377  //errored
378  perror( "Error in reading HTTP socket" );
379  resendData();
380  return false;
381  }
382  //Let ret==0 but transfer complete fall through.
383  if (datalen > 0 || datalen < 0) {
384  if (datalen != -1) datalen -= ret;
385  bufpos = 0;
386  if (_content_length == 0) {
387  for (bufpos = 0; bufpos < ret; bufpos++) {
388  char rcvchr = rcvbuf[bufpos];
389  if ( parseHeaderByte( rcvchr ) ) {
390  std::map< std::string, std::string >::const_iterator iter;
391 
392  _content_length = -1;
393  ischunked = false;
394  _send_more_data = true;
395 
396  iter = _header.find( "Status" );
397  if ( iter == _header.end() ) {
398  COUT<<"Missing status, resending\n";
399  resendData();
400  return false;
401  }
402  if ( (*iter).second.find( "100" ) != std::string::npos ) {
403  _content_length = 0;
404  _header.clear();
405  printf( "100 found in header at marker %d... rest of string looks like:%s\n", bufpos, rcvbuf+bufpos );
406  continue;
407  } else if ( (*iter).second.find( "200" ) == std::string::npos ) {
408  if ( (*iter).second.find( "301" ) != std::string::npos
409  || (*iter).second.find( "302" ) != std::string::npos
410  || (*iter).second.find( "303" ) != std::string::npos
411  || (*iter).second.find( "307" ) != std::string::npos ) {
412  //Redirect (permanent == 301, temporary == 302,303,307).
413  iter = _header.find( "Location" );
414  if ( iter == _header.end() ) {
415  COUT<<"Failed to find a Location header after a 3xx message";
416  } else {
417  std::string dummy;
418  unsigned short port;
419  this->_remote_ip = remoteIPFromURI( (*iter).second );
420  hostFromURI( (*iter).second, dummy, this->_hostheader, this->_path, port );
421  resendData();
422  return false;
423  }
424  } else {
425  COUT<<"Received HTTP error: status is "+(*iter).second<<std::endl;
426  resendData();
427  return false;
428  }
429  }
430  iter = _header.find( "Content-Length" );
431  if ( iter != _header.end() ) {
432  _content_length = atoi( (*iter).second.c_str() );
433  if (_content_length == 0)
434  _content_length = -1;
435  }
436  //Don't need to check content-type any more.
437  iter = _header.find( "Content-Type" );
438  if ( iter != _header.end() )
439  if ( (*iter).second != "message/x-vsnet-packet" && (*iter).second != "text/html" )
440  COUT<<"content type "<<(*iter).second<<std::endl;
441  iter = _header.find( "Connection" );
442  if ( iter != _header.end() ) {
443  if ( (*iter).second == "close" )
444  _send_more_data = false;
445  } else {
446  //assume no more data allowed.
447  _send_more_data = false;
448  }
449  iter = _header.find( "Transfer-Encoding" );
450  if ( iter != _header.end() ) {
451  if ( (*iter).second == "chunked" )
452  ischunked = true;
453  } else {
454  //assume no more data allowed.
455  ischunked = false;
456  }
457  readHeader = true;
458  bufpos++;
459  if (ischunked)
460  readingchunked = true;
461  chunkedlen = 0;
462  chunkedchar = '\0';
463  break;
464  }
465  }
466  }
467  while (bufpos < ret) {
468  for (; bufpos < ret && readingchunked; bufpos++) {
469  char rcvchr = rcvbuf[bufpos];
470  if (rcvchr == '\n' && chunkedchar != '\0' /*make sure that it had read something of interest*/) {
471  readingchunked = false;
472  if (chunkedlen == 0)
473  goto donewiththis; //break(3);
474  }
475  if ( ishex( rcvchr ) && (ishex( chunkedchar ) || chunkedchar == '\0') ) {
476  if (rcvchr >= '0' && rcvchr <= '9') {
477  chunkedlen *= 16;
478  chunkedlen += rcvchr-'0';
479  chunkedchar = rcvchr;
480  } else if (rcvchr >= 'A' && rcvchr <= 'F') {
481  chunkedlen *= 16;
482  chunkedlen += rcvchr-'A'+10;
483  chunkedchar = rcvchr;
484  } else if (rcvchr >= 'a' && rcvchr <= 'f') {
485  chunkedlen *= 16;
486  chunkedlen += rcvchr-'a'+10;
487  chunkedchar = rcvchr;
488  }
489  chunkedchar = rcvchr;
490  }
491  if (rcvchr == ';') chunkedchar = ';'; //this means extension follow and we shouldn't add numbers
492  }
493  if (readingchunked == false && _content_length != 0 && bufpos < ret) {
494  //Now, the socket *should* contain message/x-vsnet-packet data.
495  int delta = ret-bufpos;
496  if (delta > chunkedlen && ischunked)
497  delta = chunkedlen;
498  dataToReceive += std::string( rcvbuf+bufpos, (std::string::size_type) delta );
499  if (ischunked) {
500  chunkedlen -= delta;
501  if (chunkedlen == 0) {
502  chunkedchar = '\0';
503  readingchunked = true;
504  }
505  }
506  bufpos += delta;
507  if (_content_length > 0) {
508  _content_length -= ret;
509  if (_content_length <= 0) {
510  _content_length = 0;
511  break;
512  }
513  }
514  }
515  }
516  }
517  if (datalen != -1 && datalen <= 0)
518  return false;
519  }
520 donewiththis:
521  /*
522  * // What the heck?
523  * if (datalen == -1) {
524  * resendData();
525  * datalen = 0;
526  * return false;
527  * }
528  */
529  if (_content_length == 0 && !_send_more_data && _fd != -1) {
530  this->close_fd();
531  this->_fd = -1;
532  //reopenConnection();
533  if ( dataToReceive.length() == 0 || (dataToReceive[0] == '!' && dataToReceive.length() < 4) ) {
534  //don't bother with the bangs
535  dataToReceive = std::string();
536  waitingToReceive = std::string(); //can't receive a null info
537  }
538  }
539  //_connection_closed = false;
540  readHeader = false;
541  return true;
542 }
int VsnetHTTPSocket::lower_sendbuf ( )
virtual

Reimplemented from VsnetSocketBase.

Definition at line 177 of file vsnet_sockethttp.cpp.

References VsnetSocketBase::_fd, VsnetSocketBase::close_fd(), COUT, NONBLOCKING_CONNECT, reopenConnection(), and vsnetEWouldBlock().

178 {
179  if ( !waitingToReceive.empty() )
180  return 0;
181  if (this->_fd == -1) {
182  printf( "reopening from lower_sendbuf...\n" );
185  return 0;
186  }
187  if ( !( _send_more_data || _content_length
188  || _incompleteheader.length() || _header.size() ) ) {
189  COUT<<"Error: HTTP data being sent while incomplete header exists";
190  this->close_fd();
191  this->_fd = -1;
192  }
193  std::string data = dataToSend.front();
194  char endHeaderLen[50];
195  std::string httpData;
196 
197  //Have to regenerate this in case the request was forwarded (301).
198  sprintf( endHeaderLen, "Content-Length: %u\r\n\r\n", (unsigned int) data.length() );
199  httpData = "POST "+this->_path+" HTTP/1.1\r\n"
200  "Host: "+this->_hostheader+"\r\n"
201  "User-Agent: Vsnet/1.0\r\n"
202  "Connection: keep-alive\r\n"
203  "Accept: message/x-vsnet-packet\r\n"
204  "Keep-Alive: 300\r\n"
205  "Content-Type: message/x-vsnet-packet\r\n"
206  +endHeaderLen+data;
207 
208  const char *httpDataStr = httpData.data();
209  unsigned int pos = sendDataPos;
210  int retrycnt = 10;
211  int blockcnt = 10;
212  while (true) {
213  int len = httpData.length()-pos;
214  int netsent;
215  netsent = ::send( _fd, &httpDataStr[pos], len, 0 );
216  if (netsent <= 0) {
217  if ( vsnetEWouldBlock() ) {
218  if (blockcnt > 0) {
219  blockcnt--;
220  continue;
221  } else {
222  //Can't hold up anything trying to wait to send data.
223  sendDataPos = pos;
224  return 0;
225  }
226  }
227  if (retrycnt) {
228 //printf("Server closed in writing... reopening\n");
229  //What!?! A HTTP server decided to close the connection? The horror...
231  if (NONBLOCKING_CONNECT) {
232  sendDataPos = 0;
233 
234  return 0;
235  }
236  } else {
237  sendDataPos = 0;
238  return 0;
239  }
240  retrycnt--;
241  continue;
242  }
243  pos += netsent;
244  if ( pos >= httpData.length() )
245  break;
246  }
247  waitingToReceive = dataToSend.front();
248  dataToSend.pop_front();
249  sendDataPos = 0;
250  return 1;
251 }
bool VsnetHTTPSocket::need_test_writable ( )
virtual

Reimplemented from VsnetSocketBase.

Definition at line 35 of file vsnet_sockethttp.cpp.

References VsnetSocketBase::_fd, and queryTime().

Referenced by isReadyToSend(), and write_on_negative().

36 {
37  if (_fd <= 0)
38  if ( (int) (queryTime()-1) < timeToNextRequest )
39  return false;
40  //std::cout << "retry: " << (int)(queryTime()-1) << " < " << timeToNextRequest << std::endl;
41  return !dataToSend.empty();
42 }
virtual int VsnetHTTPSocket::optPayloadSize ( ) const
inlinevirtual

Definition at line 54 of file vsnet_sockethttp.h.

55  {
56  return 500;
57  }
bool VsnetHTTPSocket::recvstr ( std::string &  data)

Definition at line 151 of file vsnet_sockethttp.cpp.

152 {
153  if ( !waitingToReceive.empty() ) {
154  if ( _content_length == 0 && !dataToReceive.empty() ) {
155  waitingToReceive = std::string();
156  data = dataToReceive;
157  dataToReceive = std::string();
158  _incompleteheader = std::string();
159  _header.clear();
160  return true;
161  }
162  }
163  return false;
164 }
void VsnetHTTPSocket::reopenConnection ( )

Definition at line 117 of file vsnet_sockethttp.cpp.

References VsnetSocketBase::_fd, VsnetSocketBase::close_fd(), NetUIBase::createClientSocket(), int, and queryTime().

Referenced by lower_clean_sendbuf(), and lower_sendbuf().

118 {
119  if (dataToReceive.length() == 0)
120  waitingToReceive = std::string();
121  _send_more_data = true;
122  timeToNextRequest = (int) queryTime()+2;
123  if (this->_fd >= 0) {
124  this->close_fd();
125  this->_fd = -1;
126  }
127  _incompleteheadersection = 0;
128  _incompleteheader = std::string();
129  _header.clear();
130  this->_fd = NetUIBase::createClientSocket( _remote_ip, true, true );
131 }
void VsnetHTTPSocket::resendData ( )

Definition at line 303 of file vsnet_sockethttp.cpp.

References VsnetSocketBase::_fd, VsnetSocketBase::close_fd(), int, and queryTime().

Referenced by lower_selected().

304 {
305  if (this->_fd >= 0)
306  this->close_fd();
307  this->_fd = -1;
308  if ( waitingToReceive.empty() )
309  return;
310  if (numRetries >= 10) {
311  waitingToReceive = std::string();
312  dataToReceive = "e";
313  return;
314  }
315  numRetries++;
316  timeToNextRequest = (int) queryTime()+2;
317  dataToSend.push_front( waitingToReceive );
318  sendDataPos = 0;
319  waitingToReceive = std::string();
320  _header.clear();
321  readHeader = false;
322  _content_length = 0;
323  readingchunked = false;
324  ischunked = false;
325  _send_more_data = false;
326  chunkedlen = 0;
327  _incompleteheadersection = 0;
328  chunkedchar = '\0';
329 }
bool VsnetHTTPSocket::sendstr ( const std::string &  data)

Definition at line 145 of file vsnet_sockethttp.cpp.

Referenced by AcctLogout(), NetClient::loginAcctLoop(), NetServer::saveAccount(), and NetServer::sendJump().

146 {
147  dataToSend.push_back( data );
148  return true;
149 }
bool VsnetHTTPSocket::write_on_negative ( )
virtual

Reimplemented from VsnetSocketBase.

Definition at line 31 of file vsnet_sockethttp.cpp.

References need_test_writable().

32 {
33  return need_test_writable();
34 }

Friends And Related Function Documentation

std::ostream& operator<< ( std::ostream &  ostr,
const VsnetHTTPSocket s 
)
friend

Definition at line 166 of file vsnet_sockethttp.cpp.

167 {
168  s.dump( ostr );
169  return ostr;
170 }

The documentation for this class was generated from the following files: