Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

237 lines
5.7 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. //#include "stdafx.h"
  7. #ifdef _WIN32
  8. #include "winlite.h"
  9. #include "winsock.h"
  10. #elif POSIX
  11. #define INVALID_SOCKET -1
  12. #define SOCKET_ERROR -1
  13. #define SOCKET int
  14. #define LPSOCKADDR struct sockaddr *
  15. #define SOCKADDR_IN struct sockaddr_in
  16. #include <netdb.h>
  17. #include <sys/types.h>
  18. #include <sys/socket.h>
  19. #include <netinet/in.h>
  20. #include <arpa/inet.h>
  21. #define closesocket close
  22. #endif
  23. #include "tier1/strtools.h"
  24. #include "KeyValues.h"
  25. #include "utlbuffer.h"
  26. #include "tier1/checksum_crc.h"
  27. #include "tier1/convar.h"
  28. #include "cbase.h"
  29. #include "cs_gamestats.h"
  30. #include "cs_gamerules.h"
  31. #include "cs_urlretrieveprices.h"
  32. #if _DEBUG
  33. #define WEEKLY_PRICE_URL "http://gamestats/weeklyprices.dat"
  34. #else
  35. #define WEEKLY_PRICE_URL "http://www.steampowered.com/stats/csmarket/weeklyprices.dat"
  36. #endif
  37. //-----------------------------------------------------------------------------
  38. // Purpose: request a URL from connection
  39. //-----------------------------------------------------------------------------
  40. bool SendHTTPRequest( const char *pchRequestURL, SOCKET socketHTML )
  41. {
  42. char szHeader[ MED_BUFFER_SIZE ];
  43. char szHostName[ SMALL_BUFFER_SIZE ];
  44. ::gethostname( szHostName, sizeof(szHostName) );
  45. Q_snprintf( szHeader, sizeof(szHeader), "GET %s HTTP/1.0\r\n" \
  46. "Accept: */*\r\n" \
  47. "Accept-Language: en-us\r\n" \
  48. "User-Agent: Steam/3.0\r\n" \
  49. "Host: %s\r\n" \
  50. "\r\n",
  51. pchRequestURL, szHostName );
  52. return ::send( socketHTML, szHeader, Q_strlen(szHeader) + 1, 0 ) != SOCKET_ERROR ;
  53. }
  54. //-----------------------------------------------------------------------------
  55. // Purpose: Given a previous HTTP request parse the response into a key values buffer
  56. //-----------------------------------------------------------------------------
  57. bool ParseHTTPResponse( SOCKET socketHTML, uint32 *unPageHash = NULL )
  58. {
  59. char szHeaderBuf[ MED_BUFFER_SIZE ];
  60. char szBodyBuf[ MED_BUFFER_SIZE ];
  61. int dwRet = 0;
  62. bool bFinishedHeaderRead = false;
  63. int iRecvPosition = 0;
  64. int cCharsInLine = 0;
  65. // scan for the end of the header
  66. while ( !bFinishedHeaderRead && iRecvPosition < sizeof(szHeaderBuf) )
  67. {
  68. dwRet = ::recv( socketHTML, &szHeaderBuf[ iRecvPosition ] , 1, 0);
  69. if ( dwRet < 0 )
  70. {
  71. bFinishedHeaderRead = true;
  72. }
  73. switch( szHeaderBuf[ iRecvPosition ] )
  74. {
  75. case '\r':
  76. break;
  77. case '\n':
  78. if ( cCharsInLine == 0 )
  79. bFinishedHeaderRead = true;
  80. cCharsInLine = 0;
  81. break;
  82. default:
  83. cCharsInLine++;
  84. break;
  85. }
  86. iRecvPosition++;
  87. }
  88. CUtlBuffer buf;
  89. buf.SetBufferType( false, false );
  90. while( 1 )
  91. {
  92. dwRet = ::recv( socketHTML, szBodyBuf, sizeof(szBodyBuf)-1, 0);
  93. if ( dwRet <= 0 )
  94. break;
  95. buf.Put( szBodyBuf, sizeof(szBodyBuf)-1 );
  96. }
  97. weeklyprice_t weeklyprice;
  98. Q_memset( &weeklyprice, 0, sizeof( weeklyprice_t) );
  99. buf.Get( &weeklyprice, sizeof( weeklyprice_t ) );
  100. if ( weeklyprice.iVersion != PRICE_BLOB_VERSION )
  101. {
  102. Msg( "Incorrect price blob version! Update your server!\n" );
  103. return false;
  104. }
  105. CSGameRules()->AddPricesToTable( weeklyprice );
  106. return true;
  107. }
  108. //-----------------------------------------------------------------------------
  109. // Purpose: Given http url crack it into an address and the request part
  110. //-----------------------------------------------------------------------------
  111. bool ProcessURL( const char *pchURL, void *pSockAddrIn, char *pchRequest, int cchRequest )
  112. {
  113. char rgchHost[ MAX_DNS_NAME ];
  114. char rgchRequest[ MED_BUFFER_SIZE ];
  115. uint16 iPort;
  116. if ( Q_strnicmp( pchURL, "http://", 7 ) != 0 )
  117. {
  118. Assert( !"http protocol only supported" );
  119. return false;
  120. }
  121. const char *pchColon = strchr( pchURL + 7, ':' );
  122. if ( pchColon )
  123. {
  124. Q_strncpy( rgchHost, pchURL + 7, pchColon - ( pchURL + 7 ) + 1 );
  125. const char *pchForwardSlash = strchr( pchColon + 1, '/' );
  126. if ( !pchForwardSlash )
  127. return false;
  128. Q_strncpy( rgchRequest, pchColon + 1, pchForwardSlash - ( pchColon + 1 ) + 1 );
  129. iPort = atoi( rgchRequest );
  130. Q_strncpy( rgchRequest, pchForwardSlash, ( pchURL + Q_strlen(pchURL) ) - pchForwardSlash + 1 );
  131. }
  132. else
  133. {
  134. const char *pchForwardSlash = strchr( pchURL + 7, '/' );
  135. if ( !pchForwardSlash )
  136. return false;
  137. Q_strncpy( rgchHost, pchURL + 7, pchForwardSlash - ( pchURL + 7 ) + 1 );
  138. iPort = 80;
  139. Q_strncpy( rgchRequest, pchForwardSlash, ( pchURL + Q_strlen(pchURL) ) - pchForwardSlash + 1 );
  140. }
  141. struct hostent *hp = NULL;
  142. if ( inet_addr( rgchHost ) == INADDR_NONE )
  143. {
  144. hp = gethostbyname( rgchHost );
  145. }
  146. else
  147. {
  148. uint32 addr = inet_addr( rgchHost );
  149. hp = gethostbyaddr( ( char* )&addr, sizeof( addr ), AF_INET );
  150. }
  151. if( hp == NULL )
  152. {
  153. return false;
  154. }
  155. sockaddr_in &sockAddrIn = *((sockaddr_in *)pSockAddrIn);
  156. sockAddrIn.sin_addr.s_addr = *( ( unsigned long* )hp->h_addr );
  157. sockAddrIn.sin_family = AF_INET;
  158. sockAddrIn.sin_port = htons( iPort );
  159. Q_strncpy( pchRequest, rgchRequest, cchRequest );
  160. return true;
  161. }
  162. //networkstringtable
  163. bool BlackMarket_DownloadPrices( void )
  164. {
  165. char szRequest[ MED_BUFFER_SIZE ];
  166. sockaddr_in server;
  167. bool bConnected = false;
  168. if ( ProcessURL( WEEKLY_PRICE_URL, &server, szRequest, sizeof(szRequest) ) )
  169. {
  170. SOCKET socketHTML = ::socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
  171. if ( socketHTML != INVALID_SOCKET)
  172. {
  173. int iRet = ::connect( socketHTML, (LPSOCKADDR)&server, sizeof(SOCKADDR_IN) );
  174. if ( !iRet )
  175. {
  176. bConnected = true;
  177. if ( SendHTTPRequest( szRequest, socketHTML ) )
  178. {
  179. uint32 unHash = 0;
  180. bool bRet = ParseHTTPResponse( socketHTML, &unHash );
  181. closesocket( socketHTML );
  182. return bRet;
  183. }
  184. else
  185. {
  186. return false;
  187. }
  188. }
  189. else
  190. {
  191. closesocket( socketHTML );
  192. return false;
  193. }
  194. }
  195. }
  196. else
  197. {
  198. return false;
  199. }
  200. return true;
  201. }