javaextensions/wma/sms_cbs/pushplugin/sms/src.s60/smsserverconnection.cpp
branchRCL_3
changeset 19 04becd199f91
child 23 98ccebc37403
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javaextensions/wma/sms_cbs/pushplugin/sms/src.s60/smsserverconnection.cpp	Tue Apr 27 16:30:29 2010 +0300
@@ -0,0 +1,468 @@
+/*
+* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "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:
+ *
+*/
+
+
+#include <fstream>
+#include <smsustrm.h> // For RSmsSocketWriteStream
+#include <gsmubuf.h>
+#include <smsuaddr.h>
+
+#include "logger.h"
+#include "monitor.h"
+#include "pushexception.h"
+#include "pusherrorcodes.h"
+#include "s60commonutils.h"
+#include "applicationinfo.h"
+#include "fileutilities.h"
+#include "javacommonutils.h"
+#include "connectionlistener.h"
+#include "smsserverconnection.h"
+#include "smsserverconnectionfactory.h"
+
+using namespace java::util;
+using namespace java::fileutils;
+
+namespace java
+{
+namespace wma
+{
+const TInt KErrDoesNotMatchFilter = -20003;
+
+OS_EXPORT SmsServerConnection::SmsServerConnection(const std::wstring& aUri,
+        const std::wstring& aFilter)
+        :CActive(EPriorityStandard),ServerConnectionBase(aUri, aFilter),
+        mSocketServerOpened(EFalse),mState(EReceivingMessageForNotify)
+{
+    JELOG2(EWMA);
+    std::wstring port = aUri.substr(KPortFieldStartIndex); // "sms://:"
+    mPort = JavaCommonUtils::wstringToInt(port);
+    LOG1(EWMA, EInfo, "created SmsServerConnection on port %d", mPort);
+}
+
+ServerConnection* ServerConnectionBase::getServerConnection(
+    const std::wstring& aUri, const std::wstring& aFilter)
+{
+    JELOG2(EWMA);
+    SmsServerConnection * serverConn = new SmsServerConnection(aUri, aFilter);
+    return serverConn;
+}
+
+OS_EXPORT SmsServerConnection::~SmsServerConnection()
+{
+    JELOG2(EWMA);
+    // As per internal spec the message store should be removed only when
+    // Application is unintalled / UnRegistered from push
+    removeDir(mMessageStoreDirName);
+    delete mMessage;
+    delete mFilterDes;
+    delete mOpenMonitor;
+}
+
+void SmsServerConnection::open(ConnectionListener* aListener,
+                               bool aIsAppLaunched)
+{
+    JELOG2(EWMA);
+    mIsAppLaunched = aIsAppLaunched;
+    SmsServerConnection::open(aListener);
+}
+
+OS_EXPORT void SmsServerConnection::open(ConnectionListener* aListener)
+{
+    JELOG2(EWMA);
+    int error = 0;
+    mListener = aListener;
+    // If we previously have messages on store while opening,
+    // we immediately inform the newly opened Java WMA connection
+    // of the number of messages on the queue. Otherwise we start listening.
+    if (mMessagesOnStore > 0)
+    {
+        mListener->msgArrived();
+        SmsServerConnectionFactory::getFactory().setPendingMsgFlag(mUri, false);
+    }
+    else if (!mIsListening)
+    {
+        if (0 == mOpenMonitor)
+        {
+            mOpenMonitor = Monitor::createMonitor();
+        }
+        TRAP(error,
+        {
+            getSocketServerL();
+            if (0 == mFilterDes)
+            {
+                mFilterDes = S60CommonUtils::wstringToDes(mFilter.c_str());
+            }
+            if (0 == mMessage)
+            {
+                CSmsBuffer* smsBuffer = CSmsBuffer::NewL();
+                mMessage = CSmsMessage::NewL(mFs, CSmsPDU::ESmsDeliver, smsBuffer);
+            }
+            error = pthread_mutex_init(&mMutex, 0);
+            if (error == 0)
+            {
+                error = pthread_cond_init(&mCondVar, 0);
+            }
+            if (0 != error)
+            {
+                User::Leave(error);
+            }
+        });
+        if (KErrNone != error)
+        {
+            ELOG1(EWMA,"SMS server connection open failed %d",error);
+            std::string errTxt("ERROR!!! SMS server conn : Open Failed");
+            throw PushException(COMMON_SRV_CONN_PLUGIN_ERROR,errTxt,__FILE__,
+                                __FUNCTION__,__LINE__);
+        }
+        LOG(EWMA, EInfo, "SMS : Open a SMS Server Socket For Listening");
+        // Need to bind socket
+        error = mSocket.Open(mSocketServer, KSMSAddrFamily, KSockDatagram,
+                             KSMSDatagramProtocol);
+        if (KErrNone == error)
+        {
+            TSockAddr smsReceiveAddress;
+            smsReceiveAddress.SetFamily(ESmsAddrApplication16BitPort);
+            smsReceiveAddress.SetPort(mPort);
+            LOG1(EWMA, EInfo, "SMS: Binding the Socket on Port %d",mPort);
+            error = mSocket.Bind(smsReceiveAddress);
+            if (KErrNone == error)
+            {
+                //create a message store
+                const java::runtime::ApplicationInfo& appInf =
+                    java::runtime::ApplicationInfo::getInstance();
+                const std::wstring& root = appInf.getRootPath();
+                LOG1(EWMA, EInfo,"SMS Store path %S",root.c_str());
+                error = createMessageStore(root + SMS_STORE_PATH);
+                mState = EReceivingMessageForNotify;
+                if (KErrNone == error)
+                {
+                    error = pthread_create(&mThreadId, NULL,
+                                           SmsServerConnection::listenThread, this);
+                    mOpenMonitor->wait();
+                }
+            }
+        }
+        if (KErrNone != error)
+        {
+            ELOG1(EWMA,"SMS server connection open failed %d",error);
+            std::string errTxt("ERROR!!! SMS server conn : Open Failed");
+            throw PushException(COMMON_SRV_CONN_PLUGIN_ERROR,errTxt,__FILE__,
+                                __FUNCTION__,__LINE__);
+        }
+        if (mMessagesOnStore > 0)
+        {
+            mListener->msgArrived();
+        }
+        mIsListening = true;
+    }
+}
+
+void* SmsServerConnection::listenThread(void* aParams)
+{
+    JELOG2(EWMA);
+    CTrapCleanup* tc = CTrapCleanup::New();
+    SmsServerConnection* serverConn =
+        reinterpret_cast<SmsServerConnection*>(aParams);
+    // As there is no possibility of active scheduler being installed to this
+    // thread prior to this , there is no need for any checks.
+    CActiveScheduler* activeScheduler = new CActiveScheduler();
+    CActiveScheduler::Install(activeScheduler);
+    CActiveScheduler::Add(serverConn);
+    serverConn->mIoctlBuf() = KSockSelectRead;
+    LOG(EWMA, EInfo, "SMS : Starting For Listening for incoming Messages");
+    (serverConn->mSocket).Ioctl(KIOctlSelect, serverConn->iStatus,
+                                &(serverConn->mIoctlBuf), KSOLSocket);
+    serverConn->SetActive();
+    (serverConn->mOpenMonitor)->notify();
+    serverConn->mIsRunning = ETrue;
+    activeScheduler->Start();
+    delete activeScheduler;
+    delete tc;
+    return 0;
+}
+
+void SmsServerConnection::RunL()
+{
+    JELOG2(EWMA);
+    int err = KErrNone;
+    err = iStatus.Int();
+    pthread_mutex_lock(&mMutex);
+    if (err < KErrNone && mState != EExit)
+    {
+        // Otherwise report back to client as a system error occurred
+        mListener->error(mUri, err, "Error Receiving Message");
+        mState = EReceivingMessageForNotify;
+        mIoctlBuf() = KSockSelectRead;
+        mSocket.Ioctl(KIOctlSelect, iStatus, &mIoctlBuf, KSOLSocket);
+        SetActive();
+        return;
+    }
+    switch (mState)
+    {
+    case EReceivingMessageForNotify:
+    {
+        mState = ENotifyingReadSucceeded;
+        int ioctl = KIoctlReadMessageSucceeded;
+
+        TRAP(err,readMessageFromStackL());
+
+        if (err != KErrNone)
+        {
+            // If there was an system error in saving the message,
+            // we report the failure to the SMS stack, so that it will
+            // return the same message next time
+            if (err != KErrDiskFull && err != KErrDoesNotMatchFilter)
+            {
+                ioctl = KIoctlReadMessageFailed;
+            }
+            mState = ENotifyingReadFailed;
+        }
+
+        mSocket.Ioctl(ioctl, iStatus, &mIoctlBuf, KSolSmsProv);
+        SetActive();
+        break;
+    }
+    case ENotifyingReadSucceeded:
+    {
+        mMessagesOnStore++;
+        // If listening by push setPendingMsgFlag to true.
+        // This is required as per push framework , so that
+        // listConnections & other push calls works fine.
+        if (!mIsAppLaunched)
+        {
+            SmsServerConnectionFactory::getFactory().setPendingMsgFlag(
+                mUri, true);
+        }
+        //Notify the listener
+        mListener->msgArrived();
+        mState = EReceivingMessageForNotify;
+        // Start a new listen immediately
+        mSocket.Ioctl(KIOctlSelect, iStatus, &mIoctlBuf, KSOLSocket);
+        SetActive();
+        break;
+    }
+    case ENotifyingReadFailed:
+    {
+        if (err != KErrDiskFull || err != KErrDoesNotMatchFilter)
+        {
+            // Report back to client as a system error occurred
+            mListener->error(mUri, err, "Error Receiving Message");
+        }
+        mState = EReceivingMessageForNotify;
+        // Start a new listen immediately.
+        mSocket.Ioctl(KIOctlSelect, iStatus,
+                      &mIoctlBuf, KSOLSocket);
+        SetActive();
+        break;
+    }
+    case EExit:
+    {
+        pthread_cond_signal(&mCondVar);
+        mIsRunning = EFalse;
+        CActiveScheduler::Stop();
+    }
+    default:
+    {
+        LOG(EWMA, EInfo, "SMS : Not a valid case");
+        break;
+    }
+    }
+    pthread_mutex_unlock(&mMutex);
+}
+
+void SmsServerConnection::getSocketServerL()
+{
+    JELOG2(EWMA);
+    if (!mSocketServerOpened)
+    {
+        mSocketServerOpened = ETrue;
+        LOG(EWMA, EInfo, "Sms :: Connecting to socket server");
+        User::LeaveIfError(mSocketServer.Connect());
+        User::LeaveIfError(mSocketServer.ShareAuto());
+    }
+}
+
+
+void SmsServerConnection::close()
+{
+    JELOG2(EWMA);
+    // the close and RunL are synchronized to make it SMP safe.
+    if (mState != EExit && mIsListening)
+    {
+        pthread_mutex_lock(&mMutex);
+        mState = EExit;
+        mMessagesOnStore = 0;
+        mIsListening = false;
+        mIsAppLaunched = false;
+        if (IsActive())
+        {
+            DoCancel();
+        }
+        if (mIsRunning)
+        {
+            pthread_cond_wait(&mCondVar, &mMutex);
+        }
+        pthread_mutex_unlock(&mMutex);
+        pthread_mutex_destroy(&mMutex);
+        pthread_cond_destroy(&mCondVar);
+    }
+}
+
+void SmsServerConnection::DoCancel()
+{
+    JELOG2(EWMA);
+    mSocket.CancelIoctl();
+    mSocket.Close();
+    mSocketServer.Close();
+}
+
+TInt SmsServerConnection::RunError(TInt aError)
+{
+    JELOG2(EWMA);
+    mListener->error(mUri, aError, "SMS :Error Receiving Message");
+    pthread_cond_signal(&mCondVar);
+    pthread_mutex_unlock(&mMutex);
+    mIsRunning = EFalse;
+    CActiveScheduler::Stop();
+    return KErrNone;
+}
+
+OS_EXPORT int SmsServerConnection::retrieveMessage(
+    TJavaMessageParametersBuf& aSmsBuf)
+{
+    JELOG2(EWMA);
+    std::wstring path;
+    path += mMessageStoreDirName;
+    // Read the SMS file contents
+    readStream.exceptions(std::ifstream::failbit|std::ifstream::badbit);
+    try
+    {
+        path += JavaCommonUtils::intToWstring(mFirstMessageInStore);
+        char* messagePath = JavaCommonUtils::wstringToUtf8(path);
+        readStream.open(messagePath, std::ios::in | std::ios::binary);
+        readStream.read((char*) aSmsBuf.Ptr(), mSmsParameters.Size());
+        readStream.read((char*)(aSmsBuf().mData).Ptr(), aSmsBuf().mDataSize * 2);
+        readStream.close();
+        (aSmsBuf().mData).SetLength(aSmsBuf().mDataSize);
+        deleteMessage();
+        delete[] messagePath;
+    }
+    catch (std::ifstream::failure e)
+    {
+        ELOG(EWMA,"SMS : Exception while opening/reading file");
+        readStream.close();
+        return KErrGeneral;
+    }
+    catch (ExceptionBase ex)
+    {
+        return KErrGeneral;
+    }
+    return KErrNone;
+}
+
+TBool SmsServerConnection::match()
+{
+    JELOG2(EWMA);
+    if (mSmsParameters().mAddress.Match(*mFilterDes) != KErrNotFound)
+    {
+        return ETrue;
+    }
+    return EFalse;
+}
+
+void SmsServerConnection::readMessageFromStackL()
+{
+    JELOG2(EWMA);
+    // We have to read the message from socket before we leave
+    RSmsSocketReadStream readstream(mSocket);
+    readstream >> *mMessage;
+    readstream.Close();
+    CSmsPDU& pdu = mMessage->SmsPDU();
+    mSmsParameters().mAddress = pdu.ToFromAddress();
+    //check whether we are intended to receive messages from this host
+    if (0 == mFilterDes || match())
+    {
+        // Check available space and delete old messages if necessary
+        long long availableSpace = FileUtilities::availableSize(
+                                       mMessageStoreDirName);
+        while ((availableSpace >= 0) && (availableSpace < KSmsMaxDataSize)
+                && (mMessagesOnStore > 0))
+        {
+            LOG(EWMA, EInfo, "SMS : Deleting old message...");
+            deleteMessage();
+            availableSpace = FileUtilities::availableSize(mMessageStoreDirName);
+        }
+        if (availableSpace < KSmsMaxDataSize)
+        {
+            User::LeaveIfError(KErrDiskFull);
+        }
+        // Get the port that the message was sent from
+        int receivedToPort;
+        int receivedFromPort;
+        TBool is16Bit;
+        TBool portAddressing = pdu.ApplicationPortAddressing(receivedToPort,
+                               receivedFromPort, &is16Bit);
+        mSmsParameters().mPort = static_cast<TUint16>(receivedFromPort);
+        // Get encoding
+        mSmsParameters().mEncoding = (mMessage->SmsPDU()).Alphabet();
+        // Get timestamp
+        mSmsParameters().mTimestamp = mMessage->Time();
+        // Copy SMS data into buffer to transfer back
+        CSmsBufferBase& smsBuffer = mMessage->Buffer();
+        mSmsParameters().mDataSize = smsBuffer.Length();
+        smsBuffer.Extract(mSmsDataBuf, 0, mSmsParameters().mDataSize);
+        std::wstring path(mMessageStoreDirName);
+        char* messagePath = 0;
+        // Write message to file
+        LOG(EWMA, EInfo,"SmsPushPlugin , Writing the message to message store");
+        std::ofstream writeStream;
+        writeStream.exceptions(std::ofstream::failbit|std::ofstream::badbit);
+        try
+        {
+            path += JavaCommonUtils::intToWstring(mNextMessageInStore);
+            messagePath = JavaCommonUtils::wstringToUtf8(path);
+            writeStream.open(messagePath, std::ios::out | std::ios::binary);
+            writeStream.write((char*) mSmsParameters.Ptr(), mSmsParameters.Size());
+            writeStream.write((char*) mSmsDataBuf.Ptr(), mSmsDataBuf.Size());
+            writeStream.close();
+        }
+        catch (std::ofstream::failure e)
+        {
+            ELOG(EWMA,"SMS : Exception while creating/writing file");
+            writeStream.close();
+            User::Leave(KErrGeneral);
+        }
+        catch (ExceptionBase ex)
+        {
+            User::Leave(KErrGeneral);
+        }
+        // Record we have another SMS
+        if (mFirstMessageInStore == -1)
+        {
+            mFirstMessageInStore = mNextMessageInStore;
+        }
+        mNextMessageInStore++;
+        delete[] messagePath;
+    }
+    else
+    {
+        User::LeaveIfError(KErrDoesNotMatchFilter);
+    }
+}
+
+}// end of namespace wma
+}// end of namespace java