Hi Arno

Once again many thanks for the quick reply.

I have now implemented a working multithreaded test (server) application
which uses both the TWSocket and the TSslWSocket in a non-blocking
manner.

The "regular" WSocket is used to accept incoming sessions, which are
then carried on in a new client thread in which the sockethandle is
"dupped" onto a TSslWSocket for further processing.

I just have to be sure that I understood your reference to
f_ERR_remove_state(unsigned ThreadID).
Should I call this function just before the Thread's execute method
returns, sending the threads ThreadID as param ?

I have provided my sample code, for the benefit of others who had the
same initial problem as me.


If you can spare the time, I would be grateful if you could please
verify that my use of the TSslWSocket is correct ?
Excerpt of my sample code is listed below:



Best regards
Kurt



***Main Thread***

__fastcall TForm2::TForm2(TComponent* Owner)
        : TForm(Owner)
{
            ...
            
            // Enable safe OpenSSL Multithreading before creating any
ICS SSL sockets
        m_pSslDynamicLock = new TSslDynamicLock(NULL);
        m_pSslDynamicLock->Enabled = true;

        // Shared (thread-safe) SSL context
        m_pSslContext = new TSslContext(NULL);
        m_pSslContext->SslCertFile          = "c:\\MyCertificate.pem";
        m_pSslContext->SslPassPhrase        = "password";
        m_pSslContext->SslPrivKeyFile       = "c:\\MyKey.pem";
        m_pSslContext->SslCAFile            = "c:\\root.cer";
        m_pSslContext->SslCAPath            = "";
        m_pSslContext->SslVerifyPeer            = false;// No client
certificate verification

        // Listen for incoming connections
        m_pServerSocket = new TWSocket(NULL);
        m_pServerSocket->OnSessionAvailable =
ServerSocketSessionAvailable;
        m_pServerSocket->Addr = "0.0.0.0";
        m_pServerSocket->Port = "443";
        m_pServerSocket->MultiThreaded = false;// We're in mainthread
and should be fine.
        m_pServerSocket->Listen();
}
//----------------------------------------------------------------------
-----
void __fastcall TForm2::ServerSocketSessionAvailable(TObject *Sender,
          WORD ErrCode)
{
        try
        {
                // Accept incoming connection request
                unsigned int nSocketHandle = m_pServerSocket-> Accept();

                // Do we have a valid Socket handle ?
                if( nSocketHandle > 0 &&
                        nSocketHandle < INVALID_SOCKET - 1 )
                {
                        // Thread initially created as suspended
                        TSslClientThread* pClientThread = new
TSslClientThread( m_hVclComponentCreationMutex,
                                                         m_pSslContext,
nSocketHandle );
                        pClientThread->OnTerminate =
OnSslClientThreadTerminate;
                        pClientThread->OnDebug = OnSslClientThreadDebug;

                        // Add reference to thread, to keep track of
session count
                        m_SessionList.Add( pClientThread );

                        // Resume Thread
                        pClientThread->Resume();
                }
        }
        catch(Exception& ex)
        {
                DebugLog("TForm2::ServerSocketSessionAvailable,
exception: " + ex.Message);
        }

        UpdateSessionCount();
}
//----------------------------------------------------------------------
-----
void __fastcall TForm2::OnSslClientThreadTerminate(TObject* Sender)
{
        if( Sender != NULL &&
                Sender->ClassNameIs("TSslClientThread") )
        {
                TSslClientThread* pThread = (TSslClientThread*)Sender;

                // Remove thread from list of active sessions
                int nIndex = m_SessionList.IndexOf( pThread );

                // Valid index ?
                if( nIndex >= 0 &&
                        nIndex < m_SessionList.Count )
                {
                        m_SessionList.Remove( nIndex );// Only remove
reference, not deleting obj.
                }

                UpdateSessionCount();
        }
}
//----------------------------------------------------------------------
-----





***Session Thread***

__fastcall TSslClientThread::TSslClientThread(HANDLE hMutex,
TSslContext* pSslContext, unsigned int nSocketHandle )
        : TThread(true)// create suspended
{
        OnDebug = NULL;

        m_hVclComponentCreationMutex = hMutex;
        m_pSslContext = pSslContext;
        m_nSocketHandle = nSocketHandle;
        FreeOnTerminate = true;
}
//----------------------------------------------------------------------
-----
void __fastcall TSslClientThread::Execute()
{
        // Init members
            // using a shared Mutex to avoid errors with components
calling AllocateHwnd/DeallocateHwnd, which are not thread safe
        WaitForSingleObject( m_hVclComponentCreationMutex, INFINITE );
                Init();
        ReleaseMutex( m_hVclComponentCreationMutex );


        // Loop until terminated ...
        while(!Terminated)
        {
                m_pClientSocket->ProcessMessages();
                Sleep(1);
        }

        
        // Cleam up
        WaitForSingleObject( m_hVclComponentCreationMutex, INFINITE );
                UnInit();
        ReleaseMutex( m_hVclComponentCreationMutex );
}
//----------------------------------------------------------------------
-----
bool TSslClientThread::Init(void)
{
        bool bRetVal(false);

        try
        {
                m_pClientSocket = new TSslWSocket(NULL);
                m_pClientSocket->MultiThreaded   = true;// Tell
SslWSocket that it is run inside a seperate thread
                m_pClientSocket->SslContext      = m_pSslContext;//
According to Arno Garrels TSslContext should be threadsafe
                m_pClientSocket->SslMode                 =
sslModeServer;
                m_pClientSocket->OnDataAvailable = ClientDataAvailable;
                m_pClientSocket->OnSessionClosed = ClientSessionClosed;
                m_pClientSocket->SslEnable               = true;

                // Assign socket handle
                m_pClientSocket->Dup( m_nSocketHandle );

                bRetVal = true;
        }
        catch(Exception& ex)
        {
                Fire_OnDebug("TSslClientThread::Init, exception: " +
ex.Message);
        }

        return bRetVal;
}
//----------------------------------------------------------------------
-----
bool TSslClientThread::UnInit(void)
{
        bool bRetVal(false);

        try
        {
                m_pClientSocket->Close();

                while( m_pClientSocket->State != wsClosed )
                {
                        m_pClientSocket->ProcessMessages();
                        Sleep(1);
                }

                delete m_pClientSocket;
                m_pClientSocket = NULL;

                // DESCRIPTION
                // ERR_remove_state() frees the error queue associated
with thread pid.
                // If pid == 0, the current thread will have its error
queue removed.
                // Since error queue data structures are allocated
automatically for
                // new threads, they must be freed when threads are
terminated in order
                // to avoid memory leaks.
                f_ERR_remove_state(this->ThreadID);

                bRetVal = true;
        }
        catch(Exception& ex)
        {
                Fire_OnDebug("TSslClientThread::UnInit, exception: " +
ex.Message);
        }

        return bRetVal;
}
//----------------------------------------------------------------------
-----
void __fastcall TSslClientThread::ClientDataAvailable(TObject* Sender,
Word Error)
{
        try
        {
                TSslWSocket* pSocket = (TSslWSocket*)Sender;

                AnsiString msg = pSocket->ReceiveStr();
        }
        catch(Exception& ex)
        {
                Fire_OnDebug("TSslClientThread::ClientDataAvailable,
exception: " + ex.Message);
        }
}
//----------------------------------------------------------------------
-----
void __fastcall TSslClientThread::ClientSessionClosed(TObject* Sender,
Word Error)
{
        try
        {
                // Terminate this thread ...
                Terminate();
        }
        catch(Exception& ex)
        {
                Fire_OnDebug("TSslClientThread::ClientSessionClosed,
exception: " + ex.Message);
        }
}


--
To unsubscribe or change your settings for TWSocket mailing list
please goto http://lists.elists.org/cgi-bin/mailman/listinfo/twsocket
Visit our website at http://www.overbyte.be

Reply via email to