home *** CD-ROM | disk | FTP | other *** search
- /*
- * Xceed Winsock Library Sample: Chat connectionless
- * Copyright (c) 2000 Xceed Software Inc.
- *
- * [ HttpServer.cpp : CHttpServer implementation ]
- *
- * This is a minimal implementation of an HTTP server. It
- * only handles the "GET" HTTP command. When a "GET" command
- * is received from a connected client, the server will send
- * the requested file to the client. This is enough functionality
- * to display a web site with bitmaps and regular HTML files.
- *
- * In particular, it demonstrate:
- * - How to create and use a listening socket to handle
- * incoming connections.
- * - How to use string and file transfer interfaces.
- * - Using "#import" with the Xceed Winsock Library.
- * - Using ATL to help implement event interfaces.
- *
- * This file is part of the Xceed Winsock Library Samples.
- * The source code in this file is only intended as a supplement
- * to Xceed Winsock Library's documentation, and is provided "as is",
- * without warranty of any kind, either expressed or implied.
- *
- */
-
- #include "stdafx.h"
- #include "HttpServer.h"
-
- //
- // Creation and destruction
- //
-
- HRESULT CHttpServer::FinalConstruct( void )
- {
- try
- {
- //
- // First, get a TCP protocol. We need the Protocols collection
- // to retrieve the protocol of interest.
- //
-
- IXWProtocolLookupPtr piProtocols( CLSID_Protocols );
- IXWProtocolInfoPtr piTCP;
-
- piProtocols->GetProtocol( wafInet, wstUnspecified, wptIP_TCP, &piTCP );
-
- //
- // Next, we want to create our listening socket. To create sockets,
- // you need the socket factory.
- //
-
- IXWSocketFactoryPtr piFactory( CLSID_SocketFactory );
-
- piFactory->CreateListeningSocket( piTCP, 0,
- const_cast< GUID* >( &__uuidof( m_piListener ) ),
- reinterpret_cast< void** >( &m_piListener ) );
-
- //
- // Finally, all connection-oriented socket that this listening socket will
- // generate, will inherit its advised interfaces. So we advise only once on
- // the listening socket to get events from all connection-oriented sockets.
- //
-
- DWORD dwCookie; // we don,t keep the cookie, we advise once and for all
-
- IXWAdviseConnectionEventsPtr piAdviseCon( m_piListener );
- IXWAdviseUnicodeStringTransferEventsPtr piAdviseString( m_piListener );
- IXWAdviseFileTransferEventsPtr piAdviseFile( m_piListener );
-
- piAdviseCon->ConnectionAdvise( static_cast< IXWConnectionEvents* >( this ),
- wcaAdviseDisconnected,
- &dwCookie );
-
- piAdviseString->UnicodeStringTransferAdvise( static_cast< IXWUnicodeStringTransferEvents* >( this ),
- wsaAdviseReceivedLineAlways,
- wnfAnsiStrings,
- &dwCookie );
-
- piAdviseFile->FileTransferAdvise( static_cast< IXWFileTransferEvents* >( this ),
- wfaAdviseFileSentCompleted,
- &dwCookie );
- }
- catch( const _com_error& xErr )
- {
- return xErr.Error();
- }
- catch ( ... )
- {
- return E_FAIL;
- }
-
- return S_OK;
- }
-
- void CHttpServer::FinalRelease( void )
- {
- //
- // Just release our listening socket
- //
-
- if( m_piListener )
- m_piListener.Release();
- }
-
- //
- // Action methods
- //
-
- HRESULT CHttpServer::Start( void )
- {
- if( m_piListener == NULL )
- return E_FAIL;
-
- try
- {
- //
- // We create an InetAddress for the address to listen on.
- // The address defaults to "any local address", so we just
- // need to complete the port.
- //
-
- IXWInetAddressInfoPtr piLocal( CLSID_InetAddress );
-
- piLocal->SetPort( 80 );
-
- //
- // We now start listening
- //
-
- m_piListener->StartListening( IXWAddressInfoPtr( piLocal ),
- static_cast< IXWIncomingConnectionEvents* >( this ),
- static_cast< EXWIncomingConnectionEventFlags >( wifAdviseConnectionProcessed |
- wifAdviseListeningError ) );
-
-
- // Getting the HostName of address 0.0.0.0 does not work on all Windows OS
- // so we make sure to handle a possible error nicely
- try
- {
- OLECHAR* pwszHostName = NULL;
- piLocal->GetHostName( &pwszHostName );
-
- printf( "Server available at http://%S/\n", pwszHostName );
-
- CoTaskMemFree( pwszHostName );
- }
- catch( ... )
- {
- printf( "Server available at http://localhost/\n" );
- }
- }
- catch( const _com_error& xErr )
- {
- printf( "\nERROR %08x in Start: %s\n", xErr.Error(), xErr.ErrorMessage() );
- return xErr.Error();
- }
- catch ( ... )
- {
- printf( "\nUNKNOWN ERROR in Start\n" );
- return E_FAIL;
- }
-
- return S_OK;
- }
-
- HRESULT CHttpServer::Stop( void )
- {
- if( m_piListener == NULL )
- return E_FAIL;
-
- try
- {
- //
- // Just tell the listening socket to stop listening for connections
- //
-
- m_piListener->StopListening();
- m_piListener.Release();
- }
- catch( const _com_error& xErr )
- {
- return xErr.Error();
- }
- catch ( ... )
- {
- return E_FAIL;
- }
-
- return S_OK;
- }
-
- //
- // Event methods
- //
-
- HRESULT CHttpServer::raw_OnConnection (
- struct IXWSocket * piListeningSocket,
- struct IXWAddressInfo * piRemoteAddress,
- unsigned long dwCallerDataSize,
- unsigned char * pcCallerData,
- unsigned long dwExpectedCalleeDataSize,
- unsigned long * pdwCalleeDataSize,
- unsigned char * * ppcCalleeData,
- struct SXWQualityOfServiceInfo * * ppsQualityOfService,
- unsigned long * pdwUserParam,
- long * pbReject )
- {
- // Nothing to do here
- return S_OK;
- }
-
- HRESULT CHttpServer::raw_OnConnectionProcessed (
- struct IXWSocket * piListeningSocket,
- struct IXWSocket * piIncomingSocket,
- unsigned long dwUserParam )
- {
- // We have a new connection
- CXcdConnectionInfo* pItem = new CXcdConnectionInfo;
- pItem->m_punkConnection = piIncomingSocket;
-
- // We keep this connection in our list
- m_lstConnections += pItem;
-
- try
- {
- // Let's display the remote address
- IXWAddressInfoPtr piRemote;
- HRESULT hr = piIncomingSocket->GetRemoteAddress( &piRemote );
-
- if( FAILED( hr ) ) _com_issue_error( hr );
-
- WCHAR* pwszAddress = NULL;
-
- try
- {
- piRemote->GetAddressString( &pwszAddress );
-
- printf( "New connection from %S\n", pwszAddress );
- CoTaskMemFree( pwszAddress );
- }
- catch( const _com_error& )
- {
- printf( "New connection from an unknown address\n" );
- }
- }
- catch( const _com_error& xErr )
- {
- return xErr.Error();
- }
- catch ( ... )
- {
- return E_FAIL;
- }
-
- return S_OK;
- }
-
- HRESULT CHttpServer::raw_OnListeningError (
- struct IXWSocket * piListeningSocket,
- unsigned long dwUserParam,
- HRESULT hResult )
- {
- printf( "\nListening error %08x\n", hResult );
- return S_OK;
- }
-
- HRESULT CHttpServer::raw_OnDisconnected (
- struct IXWSocket * piSocket,
- unsigned long dwCallerDataSize,
- unsigned char * pcCallerData,
- unsigned long * pdwCalleeDataSize,
- unsigned char * * ppcCalleeData )
- {
- HRESULT hr = S_OK;
-
- // We remove our instance from the list, preventing any other access
- m_lstConnections.Lock();
-
- try
- {
- // In COM, to compare objects, you can only compare their respective
- // IUnknown interface address. All other interface addresses could resolve to
- // two differents addreses even if it's the same instance.
- IUnknownPtr punkSocket( piSocket );
-
- CXcdConnectionList::iterator i;
-
- for( i = m_lstConnections.First(); i != m_lstConnections.End(); i++ )
- {
- CXcdConnectionInfo* pItem = *i;
-
- if( punkSocket == pItem->m_punkConnection )
- {
- // Yep, that's it!
- m_lstConnections -= pItem;
-
- // Let's display a message
- IXWAddressInfoPtr piRemote;
- piSocket->GetRemoteAddress( &piRemote );
-
- WCHAR* pwszAddress = NULL;
-
- try
- {
- piRemote->GetAddressString( &pwszAddress );
-
- printf( "Disconnection from %S\n", pwszAddress );
- CoTaskMemFree( pwszAddress );
- }
- catch( const _com_error& )
- {
- printf( "Disconnection from an unknown address\n" );
- }
-
- delete pItem;
-
- break;
- }
- }
- }
- catch( const _com_error& xErr )
- {
- hr = xErr.Error();
- }
- catch ( ... )
- {
- hr = E_FAIL;
- }
-
- m_lstConnections.Unlock();
-
- return hr;
- }
-
- HRESULT CHttpServer::raw_OnUnicodeStringSent (
- struct IXWUnicodeStringTransfer * piTransfer,
- unsigned long dwUserParam,
- HRESULT hResultCode )
- {
- // Nothing to do
- return S_OK;
- }
-
- HRESULT CHttpServer::raw_OnUnicodeStringReceived (
- struct IXWUnicodeStringTransfer * piTransfer,
- LPWSTR * ppwszString,
- unsigned long dwUserParam,
- HRESULT hResultCode )
- {
- if( !ppwszString || !*ppwszString )
- return E_INVALIDARG;
-
- HRESULT hr = S_OK;
-
- // Look for this connection in our connection list
- m_lstConnections.Lock();
-
- try
- {
- // In COM, to compare objects, you can only compare their respective
- // IUnknown interface address. All other interface addresses could resolve to
- // two differents addreses even if it's the same instance.
- IUnknownPtr punkSocket( piTransfer );
-
- CXcdConnectionList::iterator i;
-
- for( i = m_lstConnections.First(); i != m_lstConnections.End(); i++ )
- {
- CXcdConnectionInfo* pItem = *i;
-
- if( punkSocket == pItem->m_punkConnection )
- {
- // This is the good item.
- if( pItem->IsRequestComplete() )
- {
- _ASSERTE( false && "Received data after a complete HTTP request." );
- _com_issue_error( E_UNEXPECTED );
- }
-
- pItem->AppendRequestString( _bstr_t( *ppwszString ) );
-
- if( pItem->IsRequestComplete() )
- {
- // This request is complete. Start by retrieving the address string.
- IXWSocketPtr piSocket( piTransfer );
- IXWAddressInfoPtr piRemote;
-
- piSocket->GetRemoteAddress( &piRemote );
-
- _bstr_t bstrAddress;
- WCHAR* pwszAddress = NULL;
-
- try
- {
- piRemote->GetAddressString( &pwszAddress );
-
- bstrAddress = pwszAddress;
- CoTaskMemFree( pwszAddress );
- }
- catch( const _com_error& )
- {
- bstrAddress = L"an unknown address";
- }
-
- printf( "Request received from %S\n", static_cast< wchar_t* >( bstrAddress ) );
- printf( "----------\n%S", static_cast< wchar_t* >( pItem->m_sRequest ) );
-
- // Send the file
- printf( "Sending file %S to %S\n", static_cast< wchar_t* >( pItem->GetRelativeFilename() ),
- static_cast< wchar_t* >( bstrAddress ) );
-
- IXWFileTransferPtr piFileTransfer( piTransfer );
-
- _bstr_t sFilename = pItem->GetAbsoluteFilename();
-
- try
- {
- piFileTransfer->AsyncSendFile( sFilename, 0, 0, 0 );
- }
- catch( const _com_error& xErr )
- {
- printf( "\nERROR %08X on AsyncSendFile.\n", xErr.Error() );
- IXWConnectionPtr piConnection( piTransfer );
- piConnection->Disconnect();
-
- throw( xErr );
- }
- }
-
- break;
- }
- }
- }
- catch( const _com_error& xErr )
- {
- hr = xErr.Error();
- }
- catch ( ... )
- {
- hr = E_FAIL;
- }
-
- m_lstConnections.Unlock();
-
- // Save this line a trip back to the library
- CoTaskMemFree( *ppwszString );
- *ppwszString = NULL;
-
- return hr;
- }
-
- HRESULT CHttpServer::raw_OnUnicodeStringAvailable (
- struct IXWUnicodeStringTransfer * piTransfer,
- unsigned long dwCharsReceived,
- unsigned long dwCharsAvailable )
- {
- // Nothing to do
- return S_OK;
- }
-
- HRESULT CHttpServer::raw_OnOutOfBandUnicodeStringReceived (
- struct IXWUnicodeStringTransfer * piTransfer,
- LPWSTR * ppwszString,
- HRESULT hResultCode )
- {
- // Nothing to do
- return S_OK;
- }
-
- HRESULT CHttpServer::raw_OnFileSent (
- struct IXWFileTransfer * piTransfer,
- LPWSTR pwszFilename,
- unsigned long dwStartOffset,
- unsigned long dwBytesSent,
- unsigned long dwBytesTotal,
- unsigned long dwUserParam,
- long bTransferCompleted,
- HRESULT hResult )
- {
- try
- {
- // Disconnect this socket
- IXWConnectionPtr piConnection( piTransfer );
-
- piConnection->Disconnect();
- }
- catch( const _com_error& xErr )
- {
- printf( "\nERROR %08x on Disconnect\n", xErr.Error() );
- }
- catch ( ... )
- {
- return E_UNEXPECTED;
- }
-
- return S_OK;
- }
-
- HRESULT CHttpServer::raw_OnFileReceived (
- struct IXWFileTransfer * piTransfer,
- LPWSTR pwszFilename,
- unsigned long dwStartOffset,
- unsigned long dwBytesReceived,
- unsigned long dwBytesTotal,
- unsigned long dwUserParam,
- long bTransferCompleted,
- HRESULT hResult )
- {
- // Nothing to do
- return S_OK;
- }
-