home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 September / Chip_2002-09_cd1.bin / zkuste / vbasic / Data / Utils / XZipComp.exe / XceedWinsock.Cab / F112761_HttpServer.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-05-15  |  13.2 KB  |  513 lines

  1. /*
  2.  * Xceed Winsock Library Sample: Chat connectionless
  3.  * Copyright (c) 2000 Xceed Software Inc.
  4.  *
  5.  * [ HttpServer.cpp : CHttpServer implementation ]
  6.  *
  7.  * This is a minimal implementation of an HTTP server. It
  8.  * only handles the "GET" HTTP command. When a "GET" command
  9.  * is received from a connected client, the server will send
  10.  * the requested file to the client. This is enough functionality
  11.  * to display a web site with bitmaps and regular HTML files.
  12.  *
  13.  * In particular, it demonstrate:
  14.  *  - How to create and use a listening socket to handle
  15.  *    incoming connections.
  16.  *  - How to use string and file transfer interfaces.
  17.  *  - Using "#import" with the Xceed Winsock Library.
  18.  *  - Using ATL to help implement event interfaces.
  19.  *
  20.  * This file is part of the Xceed Winsock Library Samples.
  21.  * The source code in this file is only intended as a supplement
  22.  * to Xceed Winsock Library's documentation, and is provided "as is", 
  23.  * without warranty of any kind, either expressed or implied.
  24.  *
  25.  */
  26.  
  27. #include "stdafx.h"
  28. #include "HttpServer.h"
  29.  
  30. //
  31. // Creation and destruction
  32. //
  33.  
  34. HRESULT CHttpServer::FinalConstruct( void )
  35. {
  36.   try
  37.   {
  38.     //
  39.     // First, get a TCP protocol. We need the Protocols collection
  40.     // to retrieve the protocol of interest.
  41.     //
  42.  
  43.     IXWProtocolLookupPtr  piProtocols( CLSID_Protocols );
  44.     IXWProtocolInfoPtr    piTCP;
  45.  
  46.     piProtocols->GetProtocol( wafInet, wstUnspecified, wptIP_TCP, &piTCP );
  47.  
  48.     //
  49.     // Next, we want to create our listening socket. To create sockets,
  50.     // you need the socket factory.
  51.     //
  52.  
  53.     IXWSocketFactoryPtr piFactory( CLSID_SocketFactory );
  54.  
  55.     piFactory->CreateListeningSocket( piTCP, 0, 
  56.                                       const_cast< GUID* >( &__uuidof( m_piListener ) ), 
  57.                                       reinterpret_cast< void** >( &m_piListener ) );
  58.  
  59.     //
  60.     // Finally, all connection-oriented socket that this listening socket will
  61.     // generate, will inherit its advised interfaces. So we advise only once on 
  62.     // the listening socket to get events from all connection-oriented sockets.
  63.     //
  64.  
  65.     DWORD dwCookie; // we don,t keep the cookie, we advise once and for all
  66.  
  67.     IXWAdviseConnectionEventsPtr            piAdviseCon( m_piListener );
  68.     IXWAdviseUnicodeStringTransferEventsPtr piAdviseString( m_piListener );
  69.     IXWAdviseFileTransferEventsPtr          piAdviseFile( m_piListener );
  70.  
  71.     piAdviseCon->ConnectionAdvise( static_cast< IXWConnectionEvents* >( this ), 
  72.                                    wcaAdviseDisconnected, 
  73.                                    &dwCookie );
  74.  
  75.     piAdviseString->UnicodeStringTransferAdvise( static_cast< IXWUnicodeStringTransferEvents* >( this ), 
  76.                                                  wsaAdviseReceivedLineAlways, 
  77.                                                  wnfAnsiStrings, 
  78.                                                  &dwCookie );
  79.  
  80.     piAdviseFile->FileTransferAdvise( static_cast< IXWFileTransferEvents* >( this ), 
  81.                                       wfaAdviseFileSentCompleted, 
  82.                                       &dwCookie );
  83.   }
  84.   catch( const _com_error& xErr ) 
  85.   {
  86.     return xErr.Error();
  87.   }
  88.   catch ( ... ) 
  89.   {
  90.     return E_FAIL;
  91.   }
  92.  
  93.   return S_OK;
  94. }
  95.  
  96. void CHttpServer::FinalRelease( void )
  97. {
  98.   //
  99.   // Just release our listening socket
  100.   //
  101.  
  102.   if( m_piListener )
  103.     m_piListener.Release();
  104. }
  105.  
  106. //
  107. // Action methods
  108. //
  109.  
  110. HRESULT CHttpServer::Start( void )
  111. {
  112.   if( m_piListener == NULL )
  113.     return E_FAIL;
  114.  
  115.   try
  116.   {
  117.     //
  118.     // We create an InetAddress for the address to listen on.
  119.     // The address defaults to "any local address", so we just
  120.     // need to complete the port.
  121.     //
  122.  
  123.     IXWInetAddressInfoPtr piLocal( CLSID_InetAddress );
  124.  
  125.     piLocal->SetPort( 80 );
  126.  
  127.     //
  128.     // We now start listening
  129.     //
  130.  
  131.     m_piListener->StartListening( IXWAddressInfoPtr( piLocal ), 
  132.                                   static_cast< IXWIncomingConnectionEvents* >( this ), 
  133.                                   static_cast< EXWIncomingConnectionEventFlags >( wifAdviseConnectionProcessed | 
  134.                                                                                   wifAdviseListeningError ) );
  135.  
  136.  
  137.     // Getting the HostName of address 0.0.0.0 does not work on all Windows OS
  138.     // so we make sure to handle a possible error nicely
  139.     try
  140.     {
  141.       OLECHAR* pwszHostName = NULL;
  142.       piLocal->GetHostName( &pwszHostName );
  143.  
  144.       printf( "Server available at http://%S/\n", pwszHostName );
  145.  
  146.       CoTaskMemFree( pwszHostName );
  147.     }
  148.     catch( ... )
  149.     {
  150.       printf( "Server available at http://localhost/\n" );
  151.     }
  152.   }
  153.   catch( const _com_error& xErr ) 
  154.   {
  155.     printf( "\nERROR %08x in Start: %s\n", xErr.Error(), xErr.ErrorMessage() );
  156.     return xErr.Error();
  157.   }
  158.   catch ( ... ) 
  159.   {
  160.     printf( "\nUNKNOWN ERROR in Start\n" );
  161.     return E_FAIL;
  162.   }
  163.  
  164.   return S_OK;
  165. }
  166.  
  167. HRESULT CHttpServer::Stop( void )
  168. {
  169.   if( m_piListener == NULL )
  170.     return E_FAIL;
  171.  
  172.   try
  173.   {
  174.     //
  175.     // Just tell the listening socket to stop listening for connections
  176.     //
  177.  
  178.     m_piListener->StopListening();
  179.     m_piListener.Release();
  180.   }
  181.   catch( const _com_error& xErr ) 
  182.   {
  183.     return xErr.Error();
  184.   }
  185.   catch ( ... ) 
  186.   {
  187.     return E_FAIL;
  188.   }
  189.  
  190.   return S_OK;
  191. }
  192.  
  193. //
  194. // Event methods
  195. //
  196.  
  197. HRESULT CHttpServer::raw_OnConnection (
  198.     struct IXWSocket * piListeningSocket,
  199.     struct IXWAddressInfo * piRemoteAddress,
  200.     unsigned long dwCallerDataSize,
  201.     unsigned char * pcCallerData,
  202.     unsigned long dwExpectedCalleeDataSize,
  203.     unsigned long * pdwCalleeDataSize,
  204.     unsigned char * * ppcCalleeData,
  205.     struct SXWQualityOfServiceInfo * * ppsQualityOfService,
  206.     unsigned long * pdwUserParam,
  207.     long * pbReject )
  208. {
  209.   // Nothing to do here
  210.   return S_OK;
  211. }
  212.  
  213. HRESULT CHttpServer::raw_OnConnectionProcessed (
  214.     struct IXWSocket * piListeningSocket,
  215.     struct IXWSocket * piIncomingSocket,
  216.     unsigned long dwUserParam )
  217. {
  218.   // We have a new connection
  219.   CXcdConnectionInfo* pItem = new CXcdConnectionInfo;
  220.   pItem->m_punkConnection = piIncomingSocket;
  221.  
  222.   // We keep this connection in our list
  223.   m_lstConnections  += pItem;
  224.  
  225.   try
  226.   {
  227.     // Let's display the remote address
  228.     IXWAddressInfoPtr piRemote;
  229.     HRESULT hr = piIncomingSocket->GetRemoteAddress( &piRemote );
  230.  
  231.     if( FAILED( hr ) ) _com_issue_error( hr );
  232.  
  233.     WCHAR*  pwszAddress = NULL;
  234.  
  235.     try
  236.     {
  237.       piRemote->GetAddressString( &pwszAddress );
  238.  
  239.       printf( "New connection from %S\n", pwszAddress );
  240.       CoTaskMemFree( pwszAddress );
  241.     }
  242.     catch( const _com_error& )
  243.     {
  244.       printf( "New connection from an unknown address\n" );
  245.     }
  246.   }
  247.   catch( const _com_error& xErr ) 
  248.   {
  249.     return xErr.Error();
  250.   }
  251.   catch ( ... ) 
  252.   {
  253.     return E_FAIL;
  254.   }
  255.  
  256.   return S_OK;
  257. }
  258.  
  259. HRESULT CHttpServer::raw_OnListeningError (
  260.     struct IXWSocket * piListeningSocket,
  261.     unsigned long dwUserParam,
  262.     HRESULT hResult )
  263. {
  264.   printf( "\nListening error %08x\n", hResult );
  265.   return S_OK;
  266. }
  267.  
  268. HRESULT CHttpServer::raw_OnDisconnected (
  269.     struct IXWSocket * piSocket,
  270.     unsigned long dwCallerDataSize,
  271.     unsigned char * pcCallerData,
  272.     unsigned long * pdwCalleeDataSize,
  273.     unsigned char * * ppcCalleeData )
  274. {
  275.   HRESULT hr = S_OK;
  276.  
  277.   // We remove our instance from the list, preventing any other access
  278.   m_lstConnections.Lock();
  279.  
  280.   try
  281.   {
  282.     // In COM, to compare objects, you can only compare their respective 
  283.     // IUnknown interface address. All other interface addresses could resolve to
  284.     // two differents addreses even if it's the same instance.
  285.     IUnknownPtr punkSocket( piSocket );
  286.  
  287.     CXcdConnectionList::iterator  i;
  288.  
  289.     for( i = m_lstConnections.First(); i != m_lstConnections.End(); i++ )
  290.     {
  291.       CXcdConnectionInfo* pItem = *i;
  292.  
  293.       if( punkSocket == pItem->m_punkConnection )
  294.       {
  295.         // Yep, that's it!
  296.         m_lstConnections  -= pItem;
  297.  
  298.         // Let's display a message
  299.         IXWAddressInfoPtr piRemote;
  300.         piSocket->GetRemoteAddress( &piRemote );
  301.  
  302.         WCHAR*  pwszAddress = NULL;
  303.  
  304.         try
  305.         {
  306.           piRemote->GetAddressString( &pwszAddress );
  307.  
  308.           printf( "Disconnection from %S\n", pwszAddress );
  309.           CoTaskMemFree( pwszAddress );
  310.         }
  311.         catch( const _com_error& )
  312.         {
  313.           printf( "Disconnection from an unknown address\n" );
  314.         }
  315.  
  316.         delete pItem;
  317.  
  318.         break;
  319.       }
  320.     }
  321.   }
  322.   catch( const _com_error& xErr ) 
  323.   {
  324.     hr = xErr.Error();
  325.   }
  326.   catch ( ... ) 
  327.   {
  328.     hr = E_FAIL;
  329.   }
  330.  
  331.   m_lstConnections.Unlock();
  332.  
  333.   return hr;
  334. }
  335.  
  336. HRESULT CHttpServer::raw_OnUnicodeStringSent (
  337.     struct IXWUnicodeStringTransfer * piTransfer,
  338.     unsigned long dwUserParam,
  339.     HRESULT hResultCode )
  340. {
  341.   // Nothing to do
  342.   return S_OK;
  343. }
  344.  
  345. HRESULT CHttpServer::raw_OnUnicodeStringReceived (
  346.     struct IXWUnicodeStringTransfer * piTransfer,
  347.     LPWSTR * ppwszString,
  348.     unsigned long dwUserParam,
  349.     HRESULT hResultCode )
  350. {
  351.   if( !ppwszString || !*ppwszString )
  352.     return E_INVALIDARG;
  353.  
  354.   HRESULT hr = S_OK;
  355.  
  356.   // Look for this connection in our connection list
  357.   m_lstConnections.Lock();
  358.  
  359.   try
  360.   {
  361.     // In COM, to compare objects, you can only compare their respective 
  362.     // IUnknown interface address. All other interface addresses could resolve to
  363.     // two differents addreses even if it's the same instance.
  364.     IUnknownPtr punkSocket( piTransfer );
  365.  
  366.     CXcdConnectionList::iterator i;
  367.  
  368.     for( i = m_lstConnections.First(); i != m_lstConnections.End(); i++ )
  369.     {
  370.       CXcdConnectionInfo* pItem = *i;
  371.  
  372.       if( punkSocket == pItem->m_punkConnection )
  373.       {
  374.         // This is the good item.
  375.         if( pItem->IsRequestComplete() )
  376.         {
  377.           _ASSERTE( false && "Received data after a complete HTTP request." );
  378.           _com_issue_error( E_UNEXPECTED );
  379.         }
  380.  
  381.         pItem->AppendRequestString( _bstr_t( *ppwszString ) );
  382.  
  383.         if( pItem->IsRequestComplete() )
  384.         {
  385.           // This request is complete. Start by retrieving the address string.
  386.           IXWSocketPtr      piSocket( piTransfer );
  387.           IXWAddressInfoPtr piRemote;
  388.  
  389.           piSocket->GetRemoteAddress( &piRemote );
  390.  
  391.           _bstr_t bstrAddress;
  392.           WCHAR*  pwszAddress = NULL;
  393.  
  394.           try
  395.           {
  396.             piRemote->GetAddressString( &pwszAddress );
  397.  
  398.             bstrAddress = pwszAddress;
  399.             CoTaskMemFree( pwszAddress );
  400.           }
  401.           catch( const _com_error& )
  402.           {
  403.             bstrAddress = L"an unknown address";
  404.           }
  405.  
  406.           printf( "Request received from %S\n", static_cast< wchar_t* >( bstrAddress ) );
  407.           printf( "----------\n%S", static_cast< wchar_t* >( pItem->m_sRequest ) );
  408.  
  409.           // Send the file
  410.           printf( "Sending file %S to %S\n", static_cast< wchar_t* >( pItem->GetRelativeFilename() ), 
  411.                                              static_cast< wchar_t* >( bstrAddress ) );
  412.  
  413.           IXWFileTransferPtr  piFileTransfer( piTransfer );
  414.  
  415.           _bstr_t sFilename = pItem->GetAbsoluteFilename();
  416.  
  417.           try
  418.           {
  419.             piFileTransfer->AsyncSendFile( sFilename, 0, 0, 0 );
  420.           }
  421.           catch( const _com_error& xErr )
  422.           {
  423.             printf( "\nERROR %08X on AsyncSendFile.\n", xErr.Error() );
  424.             IXWConnectionPtr  piConnection( piTransfer );
  425.             piConnection->Disconnect();
  426.  
  427.             throw( xErr );
  428.           }
  429.         }
  430.  
  431.         break;
  432.       }
  433.     }
  434.   }
  435.   catch( const _com_error& xErr ) 
  436.   {
  437.     hr = xErr.Error();
  438.   }
  439.   catch ( ... ) 
  440.   {
  441.     hr = E_FAIL;
  442.   }
  443.  
  444.   m_lstConnections.Unlock();
  445.  
  446.   // Save this line a trip back to the library
  447.   CoTaskMemFree( *ppwszString );
  448.   *ppwszString  = NULL;
  449.  
  450.   return hr;
  451. }
  452.  
  453. HRESULT CHttpServer::raw_OnUnicodeStringAvailable (
  454.     struct IXWUnicodeStringTransfer * piTransfer,
  455.     unsigned long dwCharsReceived,
  456.     unsigned long dwCharsAvailable )
  457. {
  458.   // Nothing to do
  459.   return S_OK;
  460. }
  461.  
  462. HRESULT CHttpServer::raw_OnOutOfBandUnicodeStringReceived (
  463.     struct IXWUnicodeStringTransfer * piTransfer,
  464.     LPWSTR * ppwszString,
  465.     HRESULT hResultCode )
  466. {
  467.   // Nothing to do
  468.   return S_OK;
  469. }
  470.  
  471. HRESULT CHttpServer::raw_OnFileSent (
  472.     struct IXWFileTransfer * piTransfer,
  473.     LPWSTR pwszFilename,
  474.     unsigned long dwStartOffset,
  475.     unsigned long dwBytesSent,
  476.     unsigned long dwBytesTotal,
  477.     unsigned long dwUserParam,
  478.     long bTransferCompleted,
  479.     HRESULT hResult )
  480. {
  481.   try
  482.   {
  483.     // Disconnect this socket
  484.     IXWConnectionPtr piConnection( piTransfer );
  485.  
  486.     piConnection->Disconnect();
  487.   }
  488.   catch( const _com_error& xErr ) 
  489.   {
  490.     printf( "\nERROR %08x on Disconnect\n", xErr.Error() );
  491.   }
  492.   catch ( ... ) 
  493.   {
  494.     return E_UNEXPECTED;
  495.   }
  496.  
  497.   return S_OK;
  498. }
  499.  
  500. HRESULT CHttpServer::raw_OnFileReceived (
  501.     struct IXWFileTransfer * piTransfer,
  502.     LPWSTR pwszFilename,
  503.     unsigned long dwStartOffset,
  504.     unsigned long dwBytesReceived,
  505.     unsigned long dwBytesTotal,
  506.     unsigned long dwUserParam,
  507.     long bTransferCompleted,
  508.     HRESULT hResult )
  509. {
  510.   // Nothing to do
  511.   return S_OK;
  512. }
  513.