sdkcreationmw/sdkruntimes/wsock/src/wsock.cpp
author rajpuroh
Wed, 21 Apr 2010 09:56:53 +0530
changeset 1 ac50fd48361b
parent 0 b26acd06ea60
permissions -rw-r--r--
Second Contribution

/*
* Copyright (c) 2004-2007 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/


#define TRACE_PREFIX "WSOCK: "
#include "wsock.h"
#include <utf.h>
#include <etelpckt.h>
#include <ApEngineConsts.h>
#include <CNetworkControllerBase.h>
#include "WinsockAgentFactory.h"
#include "WinsockProtocolFamily.h"
#include "WinsockInterfaceFactory.h"
#include "WinsockUtils.h"

_LIT(KProxyTableName,"Proxies");
static const TInt KDefaultProxyPort = 8080;

enum TProxyUpdateFlags
{
    TProxyUpdateUseProxy                = 0x00000001,
    TProxyUpdateServerName              = 0x00000002,
    TProxyUpdateProtocol                = 0x00000004,
    TProxyUpdatePort                    = 0x00000008,
    TProxyUpdateName                    = 0x00000010
};

enum TBearerUpdateFlags
{
    TBearerUpdateAgent                  = 0x00000001,
    TBearerUpdateSocketActivityTimeout  = 0x00000002,
    TBearerUpdateSessionClosedTimeout   = 0x00000004,
    TBearerUpdateSocketClosedTimeout    = 0x00000008
};

enum TServiceUpdateFlags
{
    TServiceUpdateNetworks              = 0x00000001,
    TServiceUpdateAuthPrompt            = 0x00000002,
    TServiceUpdateAPN                   = 0x00000004,
    TServiceUpdateAPType                = 0x00000008
};

enum TIAPUpdateFlags
{
    TIAPUpdateService                   = 0x00000001,
    TIAPUpdateServiceType               = 0x00000002,
    TIAPUpdateBearer                    = 0x00000004,
    TIAPUpdateBearerType                = 0x00000008,
    TIAPUpdateNetwork                   = 0x00000010
};

enum TWapIpBearerUpdateFlags
{
    TWapIpBearerUpdateIAP               = 0x00000001,
    TWapIpBearerUpdateWspOption         = 0x00000002,
    TWapIpBearerUpdateProxyPort         = 0x00000004,
    TWapIpBearerUpdateSecurity          = 0x00000008,
    TWapIpBearerUpdateGatewayAddress    = 0x00000010,
    TWapIpBearerUpdateProxyLoginName    = 0x00000020,
    TWapIpBearerUpdateProxyLoginPass    = 0x00000040
};

#ifdef _REALLY_DEBUG
extern "C" int __stdcall IsDebuggerPresent(void);
void WsockAssert(const TText* s, const TText* file, TInt line)
{
    TRACE1("Assertion failed: %s",s);
    TRACE1("File: %s",file);
    TRACE1("Line: %d",line);

    #ifdef WSOCK_ASSERT_BREAKPOINT
    if (IsDebuggerPresent())
    {
        __BREAKPOINT();
    }
    #endif
}
TInt WsockAssertSuccess(TInt err, const TText* s, const TText* file, TInt line)
{
    if (err != KErrNone)
    {
        TRACE1("Unexpected error: %d",err);
        TRACE1("Expression: %s",s);
        TRACE1("File: %s",file);
        TRACE1("Line: %d",line);

        #ifdef WSOCK_ASSERT_BREAKPOINT
        if (IsDebuggerPresent())
        {
            __BREAKPOINT();
        }
        #endif
    }
    return err;
}
void WsockLeave(TInt err, const TText* s, const TText* file, TInt line)
{
    TRACE2("Leaving with error %d (%s)",err,s);
    TRACE1("File: %s",file);
    TRACE1("Line: %d",line);

    #ifdef WSOCK_ASSERT_BREAKPOINT
    if (IsDebuggerPresent())
    {
        __BREAKPOINT();
    }
    #endif
    User::Leave(err);
}
void WsockLeaveIfError(TInt err, const TText* s, const TText* file, TInt line)
{
    if (err != KErrNone)
    {
        TRACE1("Unexpected error: %d",err);
        TRACE1("Expression: %s",s);
        TRACE1("File: %s",file);
        TRACE1("Line: %d",line);

        #ifdef WSOCK_ASSERT_BREAKPOINT
        if (IsDebuggerPresent())
        {
            __BREAKPOINT();
        }
        #endif
        User::Leave(err);
    }
}
#endif // _REALLY_DEBUG

// WSOCK lock
class WsockLock
{
private:
    TBool iLocked;
    RMutex iMutex;
public:
    WsockLock() : iLocked(EFalse) {}
    ~WsockLock() {
        ASSERT(!iLocked);
        if (iLocked) Unlock();
    }

    // Locks the mutex, returning KErrNone on success
    TInt Lock()
    {
        _LIT(KMutexName, "WsockLock");
        ASSERT(!iLocked);
        TInt err = iMutex.CreateGlobal(KMutexName, EOwnerThread);
        while (err == KErrAlreadyExists) {
            err = iMutex.OpenGlobal(KMutexName, EOwnerThread);
            if (err == KErrNone) {
                TRACE("opened existing CommDb mutex");
            } else {
                TRACE("couldn't either create or open CommDb mutex, retry");
                err = iMutex.CreateGlobal(KMutexName, EOwnerThread);
            }
        }
        ASSERT_SUCCESS(err);
        if (err == KErrNone) {
            iMutex.Wait();
            iLocked = ETrue;
        }
        return err;
    }

    // Locks the mutex, leaves on failure
    void LockL()
    {
        LEAVE_IF_ERROR(Lock());
    }

    // Locks the mutex, leaves on failure, sets up cleanup callback
    void LockLC()
    {
        LEAVE_IF_ERROR(Lock());
        CleanupStack::PushL(TCleanupItem(UnlockOnLeave,this));
    }

    // Releases the mutex
    void Unlock()
    {
        ASSERT(iLocked);
        if (iLocked) {
            iLocked = EFalse;
            iMutex.Signal();
            iMutex.Close();
        }
    }

    // Cleanup callback. Unlocks WsockLock
    static void UnlockOnLeave(TAny* aPtr)
    {
        WsockLock* lock = (WsockLock*)aPtr;
        lock->Unlock();
    }
};

// Cleanup callback. Rolls back the transaction
static void WsockRollbackOnLeave(TAny* aDb)
{
    CCommsDatabase* db = (CCommsDatabase*)aDb;
    db->RollbackTransaction();
}

// Begins CommDb transaction
static void WsockBeginCommDbTransactionLC(CCommsDatabase* aDb)
{
    TInt err = aDb->BeginTransaction();
    TInt retriesLeft = KRetryCount;
    while ((err == KErrLocked || err == KErrAccessDenied) && --retriesLeft)
    {
        User::After(KRetryWait);
        err = aDb->BeginTransaction();
    }
    LEAVE_IF_ERROR(err); // Leaves if error
    CleanupStack::PushL(TCleanupItem(WsockRollbackOnLeave,aDb));
}

// Checks proxy settings in CommDb. Returns ETrue if transaction needs
// to be commited. If aProxyHost is NULL, does not check the proxy values,
// only makes sure that there is on and only one proxy record in CommDb.
// If we allow more than one record, Symbian HTTP framework gets confused
// what to use and more often than not uses the wrong one. Particularly,
// it appears to prefer proxy records associated with OutgoingGPRS service,
// ignoring LANService.
static TBool WsockCheckProxyL(CCommsDatabase* aDb,
                              TUint32 aServiceId,
                              TBool aUseProxy,
                              const TDesC* aProxyHost,
                              TUint aProxyPort)
{
    _LIT(KProxyProtocol,"http");
    _LIT(KProxyName, "Winsock Proxy Settings");
    const TDesC& TableName = KProxyTableName();
    const TDesC& ServiceType = KWinsockServiceType();
    TRACE1("examining %S table...",&TableName);
    CCommsDbTableView* view = aDb->OpenTableLC(TableName);

    // Column names
    TPtrC IdColumn(COMMDB_ID);
    TPtrC NameColumn(COMMDB_NAME);
    TPtrC ISPColumn(PROXY_ISP);
    TPtrC UseProxyColumn(PROXY_USE_PROXY_SERVER);
    TPtrC ServiceTypeColumn(PROXY_SERVICE_TYPE);
    TPtrC ServerNameColumn(PROXY_SERVER_NAME);
    TPtrC ProtocolColumn(PROXY_PROTOCOL_NAME);
    TPtrC ProxyPortColumn(PROXY_PORT_NUMBER);

    // Delete everything except our record
    TInt err;
    TUint32 id = 0;
    TBool recordFound = EFalse;
    TBool databaseUpdated  = EFalse;
    if (view->GotoFirstRecord() == KErrNone)
    {
        TUint32 number = 0;
        TBuf<KCommsDbSvrMaxFieldLength> text;
        do
        {
            // This one must exist
            TRAP(err, view->ReadUintL(IdColumn, id));
            if (err == KErrNone)
            {
                // We detect our record based on the values of "ISP"
                // and "ProxyServiceType" columns
                number = 0;
                TRAP(err, view->ReadUintL(ISPColumn,number));
                TRAP(err, view->ReadTextL(ServiceTypeColumn,text));
                TRACE4("  %S #%d -> %d,%S",&TableName,id,number,&text);
                if (err == KErrNone &&
                    text == ServiceType &&
                    number == aServiceId &&
                    !recordFound)
                {
                    TUint updateFlags = 0;
                    if (aProxyHost)
                    {
                        TBool useProxy = EFalse;
                        TRAP(err, view->ReadBoolL(UseProxyColumn,useProxy));
                        if (err != KErrNone || useProxy != aUseProxy)
                        {
                            updateFlags |= TProxyUpdateUseProxy;
                        }

                        HBufC* val = NULL;
                        TRAP(err, val = view->ReadLongTextLC(ServerNameColumn);
                        CleanupStack::Pop(val));
                        if (err != KErrNone || *val != *aProxyHost)
                        {
                            updateFlags |= TProxyUpdateServerName;
                        }
                        delete val;

                        TRAP(err, view->ReadUintL(ProxyPortColumn,number));
                        if (err != KErrNone || number != aProxyPort)
                        {
                            updateFlags |= TProxyUpdatePort;
                        }
                    }

                    TRAP(err, view->ReadTextL(NameColumn,text));
                    if (err != KErrNone || text != KProxyName())
                    {
                        updateFlags |= TProxyUpdateName;
                    }

                    TRAP(err, view->ReadTextL(ProtocolColumn,text));
                    if (err != KErrNone || text != KProxyProtocol())
                    {
                        updateFlags |= TProxyUpdateProtocol;
                    }

                    if (updateFlags)
                    {
                        TRACE3("updating %S #%d (flags: %08X)",&TableName,id,updateFlags);
                        LEAVE_IF_ERROR(view->UpdateRecord());

                        if (updateFlags & TProxyUpdateUseProxy)
                        {
                            TRAP(err,view->WriteBoolL(UseProxyColumn,aUseProxy));
                            ASSERT_SUCCESS(err);
                        }
                        if (updateFlags & TProxyUpdateServerName)
                        {
                            TRAP(err,view->WriteLongTextL(ServerNameColumn,*aProxyHost));
                            ASSERT_SUCCESS(err);
                        }
                        if (updateFlags & TProxyUpdateName)
                        {
                            TRAP(err,view->WriteTextL(NameColumn,KProxyName()));
                            ASSERT_SUCCESS(err);
                        }
                        if (updateFlags & TProxyUpdateProtocol)
                        {
                            TRAP(err,view->WriteTextL(ProtocolColumn,KProxyProtocol()));
                            ASSERT_SUCCESS(err);
                        }
                        if (updateFlags & TProxyUpdatePort)
                        {
                            TRAP(err,view->WriteUintL(ProxyPortColumn,aProxyPort));
                            ASSERT_SUCCESS(err);
                        }

                        LEAVE_IF_ERROR(view->PutRecordChanges());
                        databaseUpdated = ETrue;
                    }

                    recordFound = ETrue;
                    continue;
                }
            }
            TRACE4("  deleting proxy record: %S #%d -> %d,%S",&TableName,id,number,&text);
            VERIFY_SUCCESS(view->DeleteRecord());
            databaseUpdated = ETrue;
        }
        while (view->GotoNextRecord() == KErrNone);
    }

    // Create a new entry if it doesn't exist
    if (!recordFound)
    {
        LEAVE_IF_ERROR(view->InsertRecord(id));

        const TDesC& host = aProxyHost ? (*aProxyHost) : KNullDesC();
        TRACE2("created %S #%d",&TableName,id);
        TRAP(err,view->WriteUintL(ISPColumn,aServiceId));
        ASSERT_SUCCESS(err);
        TRAP(err,view->WriteTextL(ServiceTypeColumn,ServiceType));
        ASSERT_SUCCESS(err);
        TRAP(err,view->WriteBoolL(UseProxyColumn, aUseProxy));
        ASSERT_SUCCESS(err);
        TRAP(err,view->WriteTextL(NameColumn, KProxyName));
        ASSERT_SUCCESS(err);
        TRAP(err,view->WriteTextL(ProtocolColumn, KProxyProtocol));
        ASSERT_SUCCESS(err);
        TRAP(err,view->WriteUintL(ProxyPortColumn, aProxyPort));
        ASSERT_SUCCESS(err);
        TRAP(err,view->WriteLongTextL(ServerNameColumn, host));
        ASSERT_SUCCESS(err);
        LEAVE_IF_ERROR(view->PutRecordChanges());
        databaseUpdated = ETrue;
    }

    CleanupStack::PopAndDestroy(view);
    return databaseUpdated;
}

// Shortcut for making sure that there's no garbage in the proxy settings table
static TBool WsockCheckProxyL(CCommsDatabase* aDb, TUint32 aServiceId)
{
    return WsockCheckProxyL(aDb, aServiceId, EFalse, NULL, KDefaultProxyPort);
}

// Makes sure our IAP is in the Network table
static TBool WsockCheckNetworkL(CCommsDatabase* aDb, TUint32& aNetworkId)
{
    _LIT(KNetworkTable,"Network");
    const TDesC& TableName = KNetworkTable();
    TRACE1("examining %S table...",&TableName);
    CCommsDbTableView* view = aDb->OpenTableLC(TableName);

    // Column names
    TPtrC IdColumn(COMMDB_ID);
    TPtrC NameColumn(COMMDB_NAME);

    // Walk the table
    TInt err;
    TUint32 id = 0;
    TBool found = EFalse;
    TBool needCommit = EFalse;
    if (view->GotoFirstRecord() == KErrNone)
    {
        TBuf<KCommsDbSvrMaxFieldLength> text;
        do
        {
            // This one must exist
            TRAPD(err, view->ReadUintL(IdColumn, id));
            if (err == KErrNone)
            {
                TRAP(err, view->ReadTextL(NameColumn,text));
                TRACE3("  %S #%d -> %S",&TableName,id,&text);
                if (err == KErrNone && text == KWinsockAPName)
                {
                    if (!found)
                    {
                        found = ETrue;
                    }
                    else
                    {
                        TRACE1("  deleting record #%d",id);
                        LEAVE_IF_ERROR(view->DeleteRecord());
                        needCommit = ETrue;
                    }
                }
            }
        }
        while (view->GotoNextRecord() == KErrNone);
    }

    // Create a new entry if it doesn't exist
    if (!found)
    {
        LEAVE_IF_ERROR(view->InsertRecord(id));
        TRACE2("created %S #%d",&TableName,id);
        TRAP(err,view->WriteTextL(NameColumn, KWinsockAPName));
        ASSERT_SUCCESS(err);
        LEAVE_IF_ERROR(view->PutRecordChanges());
        needCommit = ETrue;
    }

    aNetworkId = id;
    CleanupStack::PopAndDestroy(view);
    return needCommit;
}

// Finds our records in CommDb, creating one if necessary. Returns ETrue
// if transaction needs to be commited.
static TBool WsockCheckBearerTypeL(CCommsDatabase* aDb, TUint32& aBearerId)
{
    const TDesC& TableName = KWinsockBearerType();
    TRACE1("examining %S table...",&TableName);
    CCommsDbTableView* view = aDb->OpenTableLC(TableName);

    TBuf<KCommsDbSvrMaxFieldLength> agent;
    agent.Copy(KWinsockAgent);
    agent.Append(_L(".agt"));

    // Column names
    TPtrC IdColumn(COMMDB_ID);
    TPtrC NameColumn(COMMDB_NAME);
    TPtrC IfNameColumn(IF_NAME);
    TPtrC AgentColumn(AGENT_NAME);
    TPtrC SocketActivityTimeoutColumn(LAST_SOCKET_ACTIVITY_TIMEOUT);
    TPtrC SessionClosedTimeoutColumn(LAST_SESSION_CLOSED_TIMEOUT);
    TPtrC SocketClosedTimeoutColumn(LAST_SOCKET_CLOSED_TIMEOUT);

    // Walk the table
    TInt err;
    TBool needCommit = EFalse;
    if (view->GotoFirstRecord() == KErrNone)
    {
        TUint32 number = 0;
        TBuf<KCommsDbSvrMaxFieldLength> text;
        do
        {
            // This one must exist
            TUint32 id = 0;
            TRAPD(err, view->ReadUintL(IdColumn, id));
            if (err == KErrNone)
            {
                // We detect our record based on the value of the "IfName"
                // column, it must point to our interface.
                TRAP(err, view->ReadTextL(IfNameColumn,text));
                TRACE3("  %S #%d -> %S",&TableName,id,&text);
                if (err == KErrNone && text == KWinsockInterface)
                {
                    aBearerId = id;
                    TUint updateFlags = 0;
                    TRAP(err, view->ReadTextL(AgentColumn,text));
                    if (err != KErrNone || text != agent)
                    {
                       updateFlags |= TBearerUpdateAgent;
                    }
                    TRAP(err, view->ReadUintL(SocketActivityTimeoutColumn,number));
                    if (err != KErrNone || number != KWinsockSocketActivityTimeout)
                    {
                       updateFlags |= TBearerUpdateSocketActivityTimeout;
                    }
                    TRAP(err, view->ReadUintL(SessionClosedTimeoutColumn,number));
                    if (err != KErrNone || number != KWinsockSessionClosedTimeout)
                    {
                       updateFlags |= TBearerUpdateSessionClosedTimeout;
                    }
                    TRAP(err, view->ReadUintL(SocketClosedTimeoutColumn,number));
                    if (err != KErrNone || number != KWinsockSocketClosedTimeout)
                    {
                       updateFlags |= TBearerUpdateSocketClosedTimeout;
                    }

                    if (updateFlags)
                    {
                        needCommit = ETrue;
                        TRACE3("updating %S #%d (flags: %08X)",&TableName,id,updateFlags);
                        LEAVE_IF_ERROR(view->UpdateRecord());

                        if (updateFlags & TBearerUpdateAgent)
                        {
                            TRAP(err,view->WriteTextL(AgentColumn,agent));
                            ASSERT_SUCCESS(err);
                        }
                        if (updateFlags & TBearerUpdateSocketActivityTimeout)
                        {
                            TRAP(err,view->WriteUintL(SocketActivityTimeoutColumn,
                                KWinsockSocketActivityTimeout));
                            ASSERT_SUCCESS(err);
                        }
                        if (updateFlags & TBearerUpdateSessionClosedTimeout)
                        {
                            TRAP(err,view->WriteUintL(SessionClosedTimeoutColumn,
                                KWinsockSessionClosedTimeout));
                            ASSERT_SUCCESS(err);
                        }
                        if (updateFlags & TBearerUpdateSocketClosedTimeout)
                        {
                            TRAP(err,view->WriteUintL(SocketClosedTimeoutColumn,
                                KWinsockSocketClosedTimeout));
                            ASSERT_SUCCESS(err);
                        }

                        LEAVE_IF_ERROR(view->PutRecordChanges());
                    }

                    // Done
                    CleanupStack::PopAndDestroy(view);
                    return needCommit;
                }
            }
        }
        while (view->GotoNextRecord() == KErrNone);
    }

    // Create a new entry
    LEAVE_IF_ERROR(view->InsertRecord(aBearerId));

    TRACE2("created %S #%d",&TableName,aBearerId);
    TRAP(err,view->WriteTextL(NameColumn,KWinsockBearerName));
    ASSERT_SUCCESS(err);
    TRAP(err,view->WriteTextL(IfNameColumn,KWinsockInterface));
    ASSERT_SUCCESS(err);
    TRAP(err,view->WriteTextL(AgentColumn,agent));
    ASSERT_SUCCESS(err);
    TRAP(err,view->WriteUintL(SocketActivityTimeoutColumn, KWinsockSocketClosedTimeout));
    ASSERT_SUCCESS(err);
    TRAP(err,view->WriteUintL(SessionClosedTimeoutColumn, KWinsockSessionClosedTimeout));
    ASSERT_SUCCESS(err);
    TRAP(err,view->WriteUintL(SocketClosedTimeoutColumn, KWinsockSocketClosedTimeout));
    ASSERT_SUCCESS(err);

    // These must be present in the LANBearer table, otherwise
    // PutRecordChanges fails because these fields are mandatory
    _LIT(something,"foo");
    TRAP(err,view->WriteTextL(TPtrC(LAN_BEARER_LDD_NAME),something));
    TRAP(err,view->WriteTextL(TPtrC(LAN_BEARER_PDD_NAME),something));

    LEAVE_IF_ERROR(view->PutRecordChanges());
    CleanupStack::PopAndDestroy(view);
    return ETrue;
}

// Finds our records in CommDb, creating one if necessary. Returns ETrue
// if transaction needs to be commited.
static TBool WsockCheckServiceTypeL(CCommsDatabase* aDb, TUint32& aServiceId)
{
    const TDesC& TableName = KWinsockServiceType();
    TRACE1("examining %S table...",&TableName);
    CCommsDbTableView* view = aDb->OpenTableLC(TableName);

    // We will need the list of networks and the agent ame
    TBuf<KCommsDbSvrMaxFieldLength> networks;
    CWinsockProtocolFamily::ProtocolNamesfownetwork(networks);

    // Column names
    TPtrC IdColumn(COMMDB_ID);
    TPtrC NameColumn(COMMDB_NAME);
    TPtrC APNColumn(GPRS_APN);
    TPtrC APTypeColumn(GPRS_AP_TYPE);
    TPtrC NetworksColumn(SERVICE_IF_NETWORKS);
    TPtrC AuthPromptColumn(ISP_IF_PROMPT_FOR_AUTH);

    // Walk the table
    TInt err;
    if (view->GotoFirstRecord() == KErrNone)
    {
        TBuf<KCommsDbSvrMaxFieldLength> text;
        do
        {
            // This one must exist
            TUint32 id = 0;
            TRAPD(err, view->ReadUintL(IdColumn, id));
            if (err == KErrNone)
            {
                TRAP(err, view->ReadTextL(NameColumn,text));
                TRACE3("  %S #%d -> %S",&TableName,id,&text);
                if (err == KErrNone && text == KWinsockServiceName)
                {
                    // This is our record. Make sure it looks right.
                    aServiceId = id;
                    TBool authPrompt = EFalse;
                    TInt updateFlags = 0;
                    TRAP(err, view->ReadTextL(NetworksColumn,text));
                    if (err != KErrNone || text != networks)
                    {
                        updateFlags |= TServiceUpdateNetworks;
                    }
                    // The following one is not present in the LANService
                    // table. Ignore it if it's not there.
                    TRAP(err, view->ReadBoolL(AuthPromptColumn,authPrompt));
                    if (err == KErrNone && authPrompt)
                    {
                        updateFlags |= TServiceUpdateAuthPrompt;
                    }

                    // The above statement also applies to APN column
                    TBuf<KCommsDbSvrMaxFieldLength> text;
                    TRAP(err, view->ReadTextL(APNColumn,text));
                    if (err == KErrNone && text != KWinsockAPName)
                    {
                        updateFlags |= TServiceUpdateAPN;
                    }

#ifndef WSOCK_LAN_SERVICE
                    // This one is important. If this number isn't set, our
                    // access point almost (!) never shows up in the list of
                    // access points, at least if we use "OutgoingGPRS"
                    // service type (hence the #ifdef).
                    TUint32 n = 0;
                    TRAP(err, view->ReadUintL(APTypeColumn, n));
                    if (err != KErrNone || n != KWinsockAPType)
                    {
                        updateFlags |= TServiceUpdateAPType;
                    }
#endif // !WSOCK_LAN_SERVICE

                    TBool update = (updateFlags != 0);
                    if (update)
                    {
                        TRACE3("updating %S #%d (flags: %08X)",&TableName,id,updateFlags);
                        LEAVE_IF_ERROR(view->UpdateRecord());

                        if (updateFlags & TServiceUpdateNetworks)
                        {
                            TRAP(err,view->WriteTextL(NetworksColumn,networks));
                            ASSERT_SUCCESS(err);
                        }
                        if (updateFlags & TServiceUpdateAuthPrompt)
                        {
                            TRAP(err,view->WriteBoolL(AuthPromptColumn,EFalse));
                            ASSERT_SUCCESS(err);
                        }
                        if (updateFlags & TServiceUpdateAPN)
                        {
                            TRAP(err,view->WriteTextL(APNColumn,KWinsockAPName));
                            ASSERT_SUCCESS(err);
                        }
                        if (updateFlags & TServiceUpdateAPType)
                        {
                            TRAP(err,view->WriteUintL(APTypeColumn,KWinsockAPType));
                            ASSERT_SUCCESS(err);
                        }

                        LEAVE_IF_ERROR(view->PutRecordChanges());
                    }

                    // Done
                    CleanupStack::PopAndDestroy(view);
                    return update;
                }
            }
        }
        while (view->GotoNextRecord() == KErrNone);

        TRACE1("  did not find %S",&KWinsockServiceName);
    }

    // Create a new entry
    LEAVE_IF_ERROR(view->InsertRecord(aServiceId));

    TRACE2("created %S #%d",&TableName,aServiceId);
    TRAP(err,view->WriteTextL(NameColumn,KWinsockServiceName));
    ASSERT_SUCCESS(err);
    TRAP(err,view->WriteTextL(NetworksColumn,networks));
    ASSERT_SUCCESS(err);

    // Ignore the errors below - LANService table does not have these entries.
    // Only OutgoingGPRS does. But we try anyway, in case if Symbian unifies
    // the formats of the service tables in CommDb.
    TRAP(err,view->WriteBoolL(AuthPromptColumn,EFalse));
    TRAP(err,view->WriteTextL(APNColumn,KWinsockAPName));
    TRAP(err,view->WriteUintL(APTypeColumn,KWinsockAPType));
    TRAP(err,view->WriteUintL(TPtrC(GPRS_PDP_TYPE),KWinsockPdpType));

    // We don't use these fields, but they are mandatory.
    TRAP(err,view->WriteBoolL(TPtrC(SERVICE_IP_ADDR_FROM_SERVER),EFalse));
    ASSERT_SUCCESS(err);
    TRAP(err,view->WriteBoolL(TPtrC(SERVICE_IP_DNS_ADDR_FROM_SERVER),EFalse));
    ASSERT_SUCCESS(err);

    LEAVE_IF_ERROR(view->PutRecordChanges());
    CleanupStack::PopAndDestroy(view);
    return ETrue;
}

// Finds our record in WAPAccessPoint table, creating one if necessary.
// Returns ETrue if transaction needs to be commited.
static TBool WsockCheckWapAccessPointL(CCommsDatabase* aDb, TUint32& aWapApId)
{
    TPtrC TableName(WAP_ACCESS_POINT);
    TRACE1("examining %S table...",&TableName);
    CCommsDbTableView* view = aDb->OpenTableLC(TableName);

    // Column names
    TPtrC IdColumn(COMMDB_ID);
    TPtrC NameColumn(COMMDB_NAME);
    TPtrC CurrentBearerColumn(WAP_CURRENT_BEARER);

    // Walk the table
    TInt err;
    TUint32 id = 0;
    TBool found = EFalse;
    TBool commit = EFalse;
    if (view->GotoFirstRecord() == KErrNone)
    {
        TBuf<KCommsDbSvrMaxFieldLength> text;
        do
        {
            // This one must exist
            TRAPD(err, view->ReadUintL(IdColumn, id));
            if (err == KErrNone)
            {
                TRAP(err, view->ReadTextL(NameColumn,text));
                TRACE3("  %S #%d -> %S",&TableName,id,&text);
                if (err == KErrNone && text == KWinsockAPName)
                {
                    if (!found)
                    {
                        aWapApId = id;
                        found = ETrue;
                        TRAP(err, view->ReadTextL(CurrentBearerColumn,text));
                        if (err != KErrNone || text != KWinsockWapBearer)
                        {
                            TRACE1("  updating \"%S\"",&CurrentBearerColumn);
                            LEAVE_IF_ERROR(view->UpdateRecord());
                            TRAP(err,view->WriteTextL(CurrentBearerColumn,
                                                      KWinsockWapBearer));
                            ASSERT_SUCCESS(err);
                            LEAVE_IF_ERROR(view->PutRecordChanges());
                            commit = ETrue;
                        }
                    }
                    else
                    {
                        TRACE1("  deleting record #%d",id);
                        LEAVE_IF_ERROR(view->DeleteRecord());
                        commit = ETrue;
                    }
                }
            }
        }
        while (view->GotoNextRecord() == KErrNone);
    }

    // Create a new entry if it doesn't exist
    if (!found)
    {
        LEAVE_IF_ERROR(view->InsertRecord(id));
        TRACE2("created %S #%d",&TableName,id);
        TRAP(err,view->WriteTextL(NameColumn, KWinsockAPName));
        ASSERT_SUCCESS(err);
        TRAP(err,view->WriteTextL(CurrentBearerColumn, KWinsockWapBearer));
        ASSERT_SUCCESS(err);
        LEAVE_IF_ERROR(view->PutRecordChanges());
        aWapApId = id;
        commit = ETrue;
    }

    CleanupStack::PopAndDestroy(view);
    return commit;
}

// Finds our records in WAPIPBearer table, creating one if necessary.
// Returns ETrue if transaction needs to be commited.
static TBool WsockCheckWapIpBearerL(CCommsDatabase* aDb,
                                    TUint32 aWapApId,
                                    TUint32 aIapId)
{
    const TDesC& TableName = KWinsockWapBearer();
    TRACE1("examining %S table...",&TableName);
    CCommsDbTableView* view = aDb->OpenTableLC(TableName);

    // Column names
    TPtrC IdColumn(COMMDB_ID);
    TPtrC NameColumn(COMMDB_NAME);
    TPtrC AccessPointIdColumn(WAP_ACCESS_POINT_ID);
    TPtrC IAPColumn(WAP_IAP);
    TPtrC ProxyPortColumn(WAP_PROXY_PORT);
    TPtrC WspOptionColumn(WAP_WSP_OPTION);
    TPtrC SecurityColumn(WAP_SECURITY);
    TPtrC GatewayAddressColumn(WAP_GATEWAY_ADDRESS);
    TPtrC ProxyLoginNameColumn(WAP_PROXY_LOGIN_NAME);
    TPtrC ProxyLoginPassColumn(WAP_PROXY_LOGIN_PASS);

    // Walk the table
    TInt err;
    TUint32 id = 0;
    if (view->GotoFirstRecord() == KErrNone)
    {
        do
        {
            // This one must exist
            TRAPD(err, view->ReadUintL(IdColumn, id));
            if (err == KErrNone)
            {
                // We detect our record based on WAP access point id
                TUint32 wap = 0;
                TRAPD(err, view->ReadUintL(AccessPointIdColumn, wap));
                TRACE3("  %S #%d -> %d", &TableName, id, wap);
                if (err == KErrNone && wap == aWapApId)
                {
                    TUint32 n = 0;
                    TBool b = EFalse;
                    TUint updateFlags = 0;
                    TBuf<KCommsDbSvrMaxFieldLength> text;
                    TBool commit = EFalse;

                    TRAPD(err, view->ReadUintL(IAPColumn, n));
                    if (err != KErrNone || n != aIapId)
                    {
                        updateFlags |= TWapIpBearerUpdateIAP;
                    }
                    TRAP(err, view->ReadUintL(WspOptionColumn, n));
                    if (err != KErrNone)
                    {
                        updateFlags |= TWapIpBearerUpdateWspOption;
                    }
                    TRAP(err, view->ReadUintL(ProxyPortColumn, n));
                    if (err != KErrNone)
                    {
                        updateFlags |= TWapIpBearerUpdateProxyPort;
                    }
                    TRAP(err, view->ReadBoolL(SecurityColumn, b));
                    if (err != KErrNone)
                    {
                        updateFlags |= TWapIpBearerUpdateSecurity;
                    }
                    TRAP(err, view->ReadTextL(GatewayAddressColumn,text));
                    if (err != KErrNone || text != KWinsockGatewayAddress)
                    {
                        updateFlags |= TWapIpBearerUpdateGatewayAddress;
                    }
                    TRAP(err, view->ReadTextL(ProxyLoginNameColumn,text));
                    if (err != KErrNone)
                    {
                        updateFlags |= TWapIpBearerUpdateProxyLoginName;
                    }
                    TRAP(err, view->ReadTextL(ProxyLoginPassColumn,text));
                    if (err != KErrNone)
                    {
                        updateFlags |= TWapIpBearerUpdateProxyLoginPass;
                    }

                    TBool update = (updateFlags != 0);
                    if (updateFlags)
                    {
                        // Update the existing table
                        TRACE3("updating %S #%d (flags: %08X)",&TableName,id,updateFlags);
                        LEAVE_IF_ERROR(view->UpdateRecord());
                        if (updateFlags & TWapIpBearerUpdateIAP)
                        {
                            TRACE1("  updating \"%S\"",&IAPColumn);
                            TRAP(err,view->WriteUintL(IAPColumn, aIapId));
                            ASSERT_SUCCESS(err);
                        }
                        if (updateFlags & TWapIpBearerUpdateWspOption)
                        {
                            TRACE1("  updating \"%S\"",&WspOptionColumn);
                            TRAP(err,view->WriteUintL(WspOptionColumn,0));
                            ASSERT_SUCCESS(err);
                        }
                        if (updateFlags & TWapIpBearerUpdateProxyPort)
                        {
                            TRACE1("  updating \"%S\"",&ProxyPortColumn);
                            TRAP(err,view->WriteUintL(ProxyPortColumn,0));
                            ASSERT_SUCCESS(err);
                        }
                        if (updateFlags & TWapIpBearerUpdateSecurity)
                        {
                            TRACE1("  updating \"%S\"",&SecurityColumn);
                            TRAP(err,view->WriteBoolL(SecurityColumn,EFalse));
                            ASSERT_SUCCESS(err);
                        }
                        if (updateFlags & TWapIpBearerUpdateGatewayAddress)
                        {
                            TRACE1("  updating \"%S\"",&GatewayAddressColumn);
                            TRAP(err,view->WriteTextL(GatewayAddressColumn,
                                                      KWinsockGatewayAddress));
                            ASSERT_SUCCESS(err);
                        }
                        if (updateFlags & TWapIpBearerUpdateProxyLoginName)
                        {
                            TRACE1("  updating \"%S\"",&ProxyLoginNameColumn);
                            TRAP(err,view->WriteTextL(ProxyLoginNameColumn,
                                                      KNullDesC));
                            ASSERT_SUCCESS(err);
                        }
                        if (updateFlags & TWapIpBearerUpdateProxyLoginPass)
                        {
                            TRACE1("  updating \"%S\"",&ProxyLoginPassColumn);
                            TRAP(err,view->WriteTextL(ProxyLoginPassColumn,
                                                      KNullDesC));
                            ASSERT_SUCCESS(err);
                        }
                        LEAVE_IF_ERROR(view->PutRecordChanges());
                        commit = ETrue;
                    }

                    // Done
                    CleanupStack::PopAndDestroy(view);
                    return commit;
                }
            }
        }
        while (view->GotoNextRecord() == KErrNone);
    }

    // Create a new entry
    LEAVE_IF_ERROR(view->InsertRecord(id));

    TRACE2("created %S #%d",&TableName,id);
    TRAP(err,view->WriteTextL(NameColumn,KWinsockBearerName));
    ASSERT_SUCCESS(err);
    TRAP(err,view->WriteUintL(AccessPointIdColumn, aWapApId));
    ASSERT_SUCCESS(err);
    TRAP(err,view->WriteUintL(IAPColumn, aIapId));
    ASSERT_SUCCESS(err);
    TRAP(err,view->WriteUintL(ProxyPortColumn, 0));
    ASSERT_SUCCESS(err);
    TRAP(err,view->WriteUintL(WspOptionColumn, 0));
    ASSERT_SUCCESS(err);
    TRAP(err,view->WriteBoolL(SecurityColumn, EFalse));
    ASSERT_SUCCESS(err);
    TRAP(err,view->WriteTextL(GatewayAddressColumn,KWinsockGatewayAddress));
    ASSERT_SUCCESS(err);
    TRAP(err,view->WriteTextL(ProxyLoginNameColumn,KNullDesC));
    ASSERT_SUCCESS(err);
    TRAP(err,view->WriteTextL(ProxyLoginPassColumn,KNullDesC));
    ASSERT_SUCCESS(err);

    LEAVE_IF_ERROR(view->PutRecordChanges());
    CleanupStack::PopAndDestroy(view);
    return ETrue;
}

static TBool WsockCheckConnPreferencesL(CCommsDatabase* aDb, TUint32 aIapId)
{
    TRACE("examining Connection Preferences...");
    CCommsDbConnectionPrefTableView *view = aDb->OpenConnectionPrefTableLC();

    CCommsDbConnectionPrefTableView::TCommDbIapConnectionPref myPrefs;
    myPrefs.iBearer.iIapId      = aIapId;
    myPrefs.iDirection          = ECommDbConnectionDirectionOutgoing;
    myPrefs.iDialogPref         = ECommDbDialogPrefPrompt;
    myPrefs.iRanking            = 1;
    myPrefs.iBearer.iBearerSet  = KCommDbBearerCSD
                                | KCommDbBearerWcdma
                                | KCommDbBearerLAN
                                | KCommDbBearerVirtual;
    // Walk the table
    TInt err;
    if (view->GotoFirstRecord() == KErrNone)
    {
        do
        {
            CCommsDbConnectionPrefTableView::TCommDbIapConnectionPref prefs;
            TRAP(err, view->ReadConnectionPreferenceL(prefs));
            if (err == KErrNone)
            {
                // check, whether this is our record
                if (prefs.iBearer.iIapId == myPrefs.iBearer.iIapId)
                {
                    TBool update = EFalse;

                    // This is our record. Make sure it looks right.
                    if (prefs.iDialogPref != myPrefs.iDialogPref)
                    {
                        TRACE("updating DialogPref");
                        view->UpdateDialogPrefL(myPrefs.iDialogPref);
                        update = ETrue;
                    }
                    if (prefs.iRanking != myPrefs.iRanking)
                    {
                        TRACE("updating Ranking");
                        view->ChangeConnectionPreferenceRankL(myPrefs.iRanking);
                        update = ETrue;
                    }
                    if (prefs.iBearer.iBearerSet != myPrefs.iBearer.iBearerSet)
                    {
                        TRACE("updating Bearer");
                        view->UpdateBearerL(myPrefs.iBearer);
                        update = ETrue;
                    }
                    CleanupStack::PopAndDestroy(view);
                    return update;
                }
            }
        }
        while (view->GotoNextRecord() == KErrNone);
    }

    // Create a new entry
    view->InsertConnectionPreferenceL(myPrefs);
    TRACE("created connection preferences");
    CleanupStack::PopAndDestroy(view);
    return ETrue;
}

// Finds our records in CommDb, creating one if necessary.
void WsockCheckCommDbL(TUint32& aIapId,
                       TUint32& aNetworkId,
                       TUint32& aServiceId,
                       TUint32& aBearerId)
{
    TRACE("checking CommDb");
    CCommsDatabase* db = CCommsDatabase::NewL();
    CleanupStack::PushL(db);
    WsockBeginCommDbTransactionLC(db);
    TBool commit = EFalse;
    TUint32 number = 0;
    TInt err;

    // This must be 2
    TPtrC ConnectionAttempts(CONNECTION_ATTEMPTS);
    TRAP(err, db->GetGlobalSettingL(ConnectionAttempts, number));
    if (err != KErrNone || number < 2)
    {
        TRACE1("Resetting ConnectionAttempts (%d) to 2",number);
        TRAP(err, db->SetGlobalSettingL(ConnectionAttempts, 2));
        ASSERT_SUCCESS(err);
        commit = ETrue;
    }

    // Not sure if we need this check...
    _LIT(KTsy, "PHONETSY");
    TFileName tsy;
    TPtrC BearerAvailabilityCheckTsy(BEARER_AVAILABILITY_CHECK_TSY);
    TRAP(err, db->GetGlobalSettingL(BearerAvailabilityCheckTsy, tsy));
    if (err != KErrNone || tsy.CompareF(KTsy))
    {
        TRACE1("Updating BearerAvailabilityCheckTSY (%S)",&tsy);
        TRAP(err, db->SetGlobalSettingL(BearerAvailabilityCheckTsy, KTsy));
        ASSERT_SUCCESS(err);
        commit = ETrue;
    }

    // Check a few other things
    if (WsockCheckServiceTypeL(db, aServiceId)) commit = ETrue;
    if (WsockCheckBearerTypeL(db, aBearerId)) commit = ETrue;
    if (WsockCheckNetworkL(db, aNetworkId)) commit = ETrue;

    // Initialize descriptors
    TPtrC TableName(IAP);
    TPtrC IdColumn(COMMDB_ID);
    TPtrC NameColumn(COMMDB_NAME);
    TPtrC IAPNetworkColumn(IAP_NETWORK);
    TPtrC IAPServiceColumn(IAP_SERVICE);
    TPtrC IAPServiceTypeColumn(IAP_SERVICE_TYPE);
    TPtrC IAPBearerColumn(IAP_BEARER);
    TPtrC IAPBearerTypeColumn(IAP_BEARER_TYPE);

    // Open the IAP table
    CCommsDbTableView* view = db->OpenTableLC(TableName);

    // Find our access point
    TRACE("examining APs...");
    if (view->GotoFirstRecord() == KErrNone)
    {
        TBuf<KCommsDbSvrMaxFieldLength> text;
        do
        {
            // This one must exist
            TUint32 id = 0;
            TRAP(err, view->ReadUintL(IdColumn, id));
            if (err == KErrNone)
            {
                TRAP(err, view->ReadTextL(NameColumn,text));
                TRACE3("  %S #%d -> %S",&TableName,id,&text);
                if (err == KErrNone && text == KWinsockAPName)
                {
                    aIapId = id;
                    TUint updateFlags = 0;
                    TRAP(err, view->ReadUintL(IAPServiceColumn,number));
                    if (err != KErrNone || number != aServiceId)
                    {
                       updateFlags |= TIAPUpdateService;
                    }
                    TRAP(err, view->ReadTextL(IAPServiceTypeColumn,text));
                    if (err == KErrNone && text != KWinsockServiceType)
                    {
                        updateFlags |= TIAPUpdateServiceType;
                    }
                    TRAP(err, view->ReadUintL(IAPBearerColumn,number));
                    if (err != KErrNone || number != aBearerId)
                    {
                       updateFlags |= TIAPUpdateBearer;
                    }
                    TRAP(err, view->ReadTextL(IAPBearerTypeColumn,text));
                    if (err == KErrNone && text != KWinsockBearerType)
                    {
                        updateFlags |= TIAPUpdateBearerType;
                    }
                    TRAP(err, view->ReadUintL(IAPNetworkColumn,number));
                    if (err != KErrNone || number != aNetworkId)
                    {
                       updateFlags |= TIAPUpdateNetwork;
                    }

                    if (updateFlags)
                    {
                        // Update the existing table
                        TRACE2("updating AP \"%S\" (flags: %08X)",&KWinsockAPName(), updateFlags);
                        LEAVE_IF_ERROR(view->UpdateRecord());

                        if (updateFlags & TIAPUpdateService)
                        {
                            TRACE2("  updating \"%S\": %u",&IAPServiceColumn, aServiceId);
                            TRAP(err,view->WriteUintL(IAPServiceColumn,aServiceId));
                            ASSERT_SUCCESS(err);
                        }
                        if (updateFlags & TIAPUpdateServiceType)
                        {
                            TRACE2("  updating \"%S\": %S",&IAPServiceTypeColumn, &KWinsockServiceType);
                            TRAP(err,view->WriteTextL(IAPServiceTypeColumn,KWinsockServiceType));
                            ASSERT_SUCCESS(err);
                        }
                        if (updateFlags & TIAPUpdateBearer)
                        {
                            TRACE2("  updating \"%S\": %u",&IAPServiceTypeColumn, aBearerId);
                            TRAP(err,view->WriteUintL(IAPBearerColumn,aBearerId));
                            ASSERT_SUCCESS(err);
                        }
                        if (updateFlags & TIAPUpdateBearerType)
                        {
                            TRACE2("  updating \"%S\": %S",&IAPBearerTypeColumn, &KWinsockBearerType);
                            TRAP(err,view->WriteTextL(IAPBearerTypeColumn,KWinsockBearerType));
                            ASSERT_SUCCESS(err);
                        }
                        if (updateFlags & TIAPUpdateNetwork)
                        {
                            TRACE2("  updating \"%S\": %u",&IAPNetworkColumn, aNetworkId);
                            TRAP(err,view->WriteUintL(IAPNetworkColumn,aNetworkId));
                            ASSERT_SUCCESS(err);
                        }

                        LEAVE_IF_ERROR(view->PutRecordChanges());
                        commit = ETrue;
                    }

                    TUint32 wap = 0;
                    if (WsockCheckWapAccessPointL(db,wap)) commit = ETrue;
                    if (WsockCheckWapIpBearerL(db,wap,aIapId)) commit = ETrue;
                    if (WsockCheckConnPreferencesL(db, aIapId)) commit = ETrue;
                    if (commit)
                    {
                        TRACE("commit CommDb transaction");
                        LEAVE_IF_ERROR(db->CommitTransaction());
                    }

                    // Done
                    CleanupStack::PopAndDestroy(view);
                    CleanupStack::Pop(); // WsockRollbackOnLeave
                    CleanupStack::PopAndDestroy(db);

                    TRACE4("selected AP=%d, network=%d, service=%d, bearer=%d",
                        aIapId,aNetworkId,aServiceId,aBearerId);
                    return;
                }
            }
        }
        while (view->GotoNextRecord() == KErrNone);
    }

    // Find any valid location id
    TUint32 locationId = 1;
    CCommsDbTableView* locationView = db->OpenTableLC(TPtrC(LOCATION));
    if (locationView->GotoFirstRecord() == KErrNone)
    {
        TRAPD(err, locationView->ReadUintL(IdColumn, locationId));
    }
    CleanupStack::PopAndDestroy(locationView);

    // Create new IAP entry
    err = view->InsertRecord(aIapId);
    ASSERT_SUCCESS(err);

    TRACE1("created AP #%d",aIapId);
    TRAP(err,view->WriteTextL(NameColumn,KWinsockAPName));
    ASSERT_SUCCESS(err);
    TRAP(err,view->WriteUintL(IAPServiceColumn,aServiceId));
    ASSERT_SUCCESS(err);
    TRAP(err,view->WriteTextL(IAPServiceTypeColumn,KWinsockServiceType));
    ASSERT_SUCCESS(err);
    TRAP(err,view->WriteUintL(IAPBearerColumn,aBearerId));
    ASSERT_SUCCESS(err);
    TRAP(err,view->WriteTextL(IAPBearerTypeColumn,KWinsockBearerType));
    ASSERT_SUCCESS(err);
    TRAP(err,view->WriteUintL(IAPNetworkColumn,aNetworkId));
    ASSERT_SUCCESS(err);

    // These must be present in the LANBearer table, otherwise
    // PutRecordChanges fails because these fields are mandatory
    _LIT(something,"foo");
    TRAP(err,view->WriteUintL(TPtrC(IAP_NETWORK_WEIGHTING),0));
    ASSERT_SUCCESS(err);
    TRAP(err,view->WriteUintL(TPtrC(IAP_LOCATION),locationId));
    ASSERT_SUCCESS(err);

    LEAVE_IF_ERROR(view->PutRecordChanges());
    CleanupStack::PopAndDestroy(view);
    CleanupStack::Pop(); // WsockRollbackOnLeave

    TUint32 wap = 0;
    WsockCheckWapAccessPointL(db, wap);
    WsockCheckWapIpBearerL(db, wap, aIapId);
    WsockCheckConnPreferencesL(db, aIapId);

    TRACE("commit CommDb transaction");
    LEAVE_IF_ERROR(db->CommitTransaction());
    CleanupStack::PopAndDestroy(db);
    TRACE4("selected AP=%d, network=%d, service=%d, bearer=%d",
        aIapId,aNetworkId,aServiceId,aBearerId);
}

// Creating necessary entries in CommDB if necessary.
static TInt WsockCheckCommDb()
{
    TUint32 apId, apNetwork, apService, apBearer;

    // Make sure Winsock is initialized
    static TBool initWinsock = ETrue;
    if (initWinsock) {
        WSADATA wsaData;
        TRACE("initializing Winsock");
        WSAStartup(MAKEWORD(1,1),&wsaData);
        initWinsock = EFalse;
    }

    WsockLock lock;
    lock.Lock();
    TRAPD(err, WsockCheckCommDbL(apId, apNetwork, apService, apBearer));
    lock.Unlock();

    if (err == KErrNone)
    {
        TRACE("CommDB check successful");
    }
    else
    {
        TRACE1("CommDB check failed, err %d",err);
    }
    return err;
}

// Deletes Wsock access points
static TBool WsockDeleteApsL(CCommsDatabase* aDb)
{
    TBool needCommit = EFalse;

    // Initialize descriptors
    TPtrC TableName(IAP);
    TPtrC IdColumn(COMMDB_ID);
    TPtrC NameColumn(COMMDB_NAME);

    // Open the IAP table
    CCommsDbTableView* view = aDb->OpenTableLC(TableName);

    // Find our access points
    TRACE("looking for APs to delete...");
    if (view->GotoFirstRecord() == KErrNone)
    {
        TUint32 number = 0;
        TBuf<KCommsDbSvrMaxFieldLength> text;
        do
        {
            // This one must exist
            TUint32 id = 0;
            TRAPD(err, view->ReadUintL(IdColumn, id));
            if (err == KErrNone)
            {
                TRAP(err, view->ReadTextL(NameColumn,text));
                TRACE3("  %S #%d -> %S",&TableName,id,&text);
                if (err == KErrNone && text == KWinsockAPName)
                {
                    TRACE1("deleting AP #%d",id);
                    LEAVE_IF_ERROR(view->DeleteRecord());
                    needCommit = ETrue;
                }
            }
        }
        while (view->GotoNextRecord() == KErrNone);
    }

    CleanupStack::PopAndDestroy(view);
    return needCommit;
}

// Configures wsock settings, leaves on failure
static void WsockSetConfigL(TBool aUseWsock, TBool aUseProxy,
                            const TDesC* aHost, TUint aPort)
{
    // Synchronize access to the database
    WsockLock lock;
    lock.LockLC();

    // Figure out the service id - we will need it
    CCommsDatabase* db = CCommsDatabase::NewL();
    CleanupStack::PushL(db);
    WsockBeginCommDbTransactionLC(db);
    TUint32 serviceId;
    TBool commit = WsockCheckServiceTypeL(db, serviceId);

    // Now that we know the service id, we can update the proxy settings
    if (WsockCheckProxyL(db,serviceId,aUseProxy,aHost,aPort)) commit = ETrue;
    if (!aUseWsock && WsockDeleteApsL(db)) commit = ETrue;
    if (commit)
    {
        TRACE("commit CommDb transaction");
        LEAVE_IF_ERROR(db->CommitTransaction());
    }
    CleanupStack::Pop(); // WsockRollbackOnLeave
    CleanupStack::PopAndDestroy(db);

    if (aUseWsock)
    {
        // Final touch
        TUint32 apId, networkId, bearerId;
        TRAPD(err, WsockCheckCommDbL(apId, networkId, serviceId, bearerId));
    }

    CleanupStack::PopAndDestroy(); // WsockLock::UnlockOnLeave
}

// Reads Wsock settings, leaves on failure
static void WsockQueryConfigL(TBool& aUseProxy, HBufC*& aHost, TUint& aPort)
{
    // Default values
    aUseProxy = EFalse;
    aHost = NULL;
    aPort = KDefaultProxyPort;

    // Synchronize access to the database
    WsockLock lock;
    lock.LockLC();

    // Figure out the service id - we will need it
    CCommsDatabase* db = CCommsDatabase::NewL();
    CleanupStack::PushL(db);
    WsockBeginCommDbTransactionLC(db);
    TUint32 serviceId;
    TBool commit = EFalse;
    if (WsockCheckServiceTypeL(db, serviceId)) commit = ETrue;
    if (WsockCheckProxyL(db, serviceId)) commit = ETrue;

    // At this point there should be only one record in the proxy table
    const TDesC& TableName = KProxyTableName();
    const TDesC& ServiceType = KWinsockServiceType();
    CCommsDbTableView* view = db->OpenTableLC(TableName);

    // Column names
    TPtrC UseProxyColumn(PROXY_USE_PROXY_SERVER);
    TPtrC ProxyPortColumn(PROXY_PORT_NUMBER);
    TPtrC ServerNameColumn(PROXY_SERVER_NAME);

    // Walk the table and deleted everything except our settings
    TInt status = KErrNotFound;
    if (view->GotoFirstRecord() == KErrNone)
    {
        status = KErrNone;
        TUint32 number = KDefaultProxyPort;
        view->ReadBoolL(UseProxyColumn,aUseProxy);
        view->ReadUintL(ProxyPortColumn, number);
        aPort = number;
        aHost = view->ReadLongTextLC(ServerNameColumn);
        CleanupStack::Pop(aHost);
    }

    if (commit)
    {
        TRACE("commit CommDb transaction");
        LEAVE_IF_ERROR(db->CommitTransaction());
    }

    CleanupStack::PopAndDestroy(view);
    CleanupStack::Pop();            // WsockRollbackOnLeave
    CleanupStack::PopAndDestroy(db);
    CleanupStack::PopAndDestroy();  // WsockLock::UnlockOnLeave

    LEAVE_IF_ERROR(status);
}

// Entry point #1
extern "C"EXPORT_C CProtocolFamilyBase * WsockCreateProtocolFamily()
{
    TRACE("WsockCreateProtocolFamily");
    VERIFY_SUCCESS(WsockCheckCommDb());
    return new CWinsockProtocolFamily(KAfInet);
}

// Entry point #2
extern "C" EXPORT_C CNifAgentFactory* WsockCreateAgentFactory()
{
    TRACE("WsockCreateAgentFactory");
    return new CWinsockAgentFactory;
}

// Entry point #3
extern "C" EXPORT_C CNifIfFactory* WsockCreateInterfaceFactory()
{
    TRACE("WsockCreateInterfaceFactory");
    return new CWinsockInterfaceFactory;
}

// Entry point #4
extern "C" EXPORT_C TInt WsockQueryConfiguration(TBool& aUseProxy,
                                                 HBufC*& aProxyHost,
                                                 TUint& aProxyPort)
{
    TRACE("WsockQueryProxy");
    TRAPD(err,WsockQueryConfigL(aUseProxy,aProxyHost,aProxyPort));
    if (err == KErrNone)
    {
        TRACE3("WsockQueryConfig: %d,%S:%d",aUseProxy,aProxyHost,aProxyPort);
    }
    else
    {
        TRACE1("configuration query failed, err %d",err);
    }
    return err;
}

// Entry point #5
extern "C" EXPORT_C TInt WsockSetConfiguration(TBool aUseWsock,
                                               TBool aUseProxy,
                                               const TDesC* aProxyHost,
                                               TUint aProxyPort)
{
    TRACE4("WsockSetConfig(%d,%d,%S:%d)",aUseWsock,aUseProxy,
        aProxyHost,aProxyPort);
    TRAPD(err,WsockSetConfigL(aUseWsock, aUseProxy, aProxyHost, aProxyPort));
    if (err == KErrNone)
    {
        TRACE("configuration updated ok");
    }
    else
    {
        TRACE1("configuration update failed, err %d",err);
    }
    return err;
}

// Entry point #6
extern "C"EXPORT_C CProtocolFamilyBase * WsockCreateProtocolFamily6()
{
    TRACE("WsockCreateProtocolFamily6");
    VERIFY_SUCCESS(WsockCheckCommDb());
    return new CWinsockProtocolFamily(KAfInet6);
}

#ifndef EKA2
// Required function
GLDEF_C TInt E32Dll(TDllReason /*aReason*/)
{
    return(KErrNone);
}
#endif // !EKA2

/**
 * Local Variables:
 * c-basic-offset: 4
 * indent-tabs-mode: nil
 * End:
 */