javacommons/gcfprotocols/socket/serverconnection/src/socketserverconnection.cpp
branchRCL_3
changeset 14 04becd199f91
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javacommons/gcfprotocols/socket/serverconnection/src/socketserverconnection.cpp	Tue Apr 27 16:30:29 2010 +0300
@@ -0,0 +1,395 @@
+/*
+* Copyright (c) 2007-2007 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 "socketserverconnection.h"
+#include "socketserverconnectionfactory.h"
+#include "pushexception.h"
+#include "pusherrorcodes.h"
+
+#define SOCKET_ERROR   (-1)
+#define INVALID_SOCKET (-1)
+#define IO_WOULDBLOCK -2
+
+using namespace java::util;
+
+SocketServerConnection::SocketServerConnection()
+{
+    LOG(ESOCKET, EInfo, "+SocketServerConnection - default constructor");
+    mListener = NULL,
+                mThreadId = 0;
+    mKeepRunning = false;
+    mListenSocket = INVALID_SOCKET;
+    mAcceptSocket = INVALID_SOCKET;
+    mPort = 0;
+    mIsNormalServerConnection = true;
+    mOpenMonitor = 0;
+    mError = 0;
+}
+OS_EXPORT SocketServerConnection::SocketServerConnection
+(const std::wstring& aUri,
+ const std::wstring& aFilter)
+        : mListener(0),
+        mThreadId(0),
+        mKeepRunning(false),
+        mListenSocket(INVALID_SOCKET),
+        mAcceptSocket(INVALID_SOCKET),
+        mUri(aUri),
+        mFilter(aFilter),
+        mPort(0)
+
+{
+    JELOG2(ESOCKET);
+    LOG(ESOCKET, EInfo, "+SocketServerConnection::SocketServerConnection");
+    // sanity check for url
+    mIsAppRunning = false;
+    mIsNormalServerConnection = false;
+    mOpenMonitor = 0;
+    mError = 0;
+
+    // create monitors only when connection comes via push plugin
+    if (0 == mOpenMonitor)
+    {
+        mOpenMonitor = Monitor::createMonitor();
+    }
+    if (aUri.find(L"socket://:") != std::wstring::npos)
+    {
+        if (aUri.length() == 10)
+            mPort = 0;
+        else
+        {
+            std::wstring port = aUri.substr(10); // "socket://:"
+            mPort = JavaCommonUtils::wstringToInt(port);
+        }
+        LOG1(ESOCKET, EInfo, "created SocketServerConnection on port %d", mPort);
+    }
+    else
+    {
+        mPort = -1;
+        LOG(ESOCKET, EInfo, "SocketServerConnection::SocketServerConnection() Invalid url");
+    }
+}
+
+OS_EXPORT SocketServerConnection::~SocketServerConnection()
+{
+    JELOG2(ESOCKET);
+    if (mOpenMonitor)
+    {
+        delete mOpenMonitor;
+    }
+}
+
+
+/* ----------------------------------------------------------------------
+
+Starting point for socket server. A new thread is created which inturn initializes the server socket and waits
+for an incoming connection.
+
+pthread_create(): This OpenC call is used to create the new thread. listenThread() is passed as the start point
+of the thread.
+
+-------------------------------------------------------------------------*/
+OS_EXPORT void SocketServerConnection::open(ConnectionListener* aListener)
+{
+    JELOG2(ESOCKET);
+    mListener = aListener;
+
+    mKeepRunning = true;
+
+    int rc = pthread_create(&mThreadId, NULL,  SocketServerConnection::listenThread, this);
+    mOpenMonitor->wait();    // wait for open to return
+
+    ILOG2(ESOCKET,"after release rc = %dm mPort = %d",rc,mPort);
+    if (rc < 0 || mError < 0)
+    {
+        ELOG1(ESOCKET,"Socket server conn already exists on Port %d : Open Failed",mPort);
+        std::string errTxt("ERROR!!! Opening of SocketServer failed");
+        throw PushException(COMMON_SRV_CONN_PLUGIN_ERROR,errTxt,__FILE__,  __FUNCTION__,__LINE__);
+    }
+}
+
+
+// Since server socket is non-blocking, a accept() is called in a new thread
+
+void* SocketServerConnection::listenThread(void* aParams)
+{
+    JELOG2(ESOCKET);
+
+    SocketServerConnection* pThis = reinterpret_cast<SocketServerConnection*>(aParams);
+
+    pThis->mListenSocket  = pThis->open(pThis->mPort);
+    ILOG1(ESOCKET,  "+SocketServerConnection::listenThread - pThis->mListenSocket = %d",pThis->mListenSocket);
+
+    if (pThis->mListenSocket < 0)
+    {
+        pThis->mError = -errno;
+        (pThis->mOpenMonitor)->notify();
+        pthread_exit(0);
+    }
+    (pThis->mOpenMonitor)->notify();
+
+
+    int fd = INVALID_SOCKET;
+
+    if (fd < 0 && pThis->mKeepRunning)
+    {
+        fd = pThis->accept();
+    }
+
+    if (!(fd<0))  // we have incoming connection
+    {
+        pThis->mAcceptSocket = fd;
+        if (pThis->mIsAppRunning == true)
+        {
+            pThis->setActivityFlag(false);
+            pthread_exit(0);
+        }
+        else
+        {
+            if (pThis->mListener)
+            {
+                pThis->mListener->msgArrived();
+            }
+            pThis->setActivityFlag(true);
+        }
+    }
+
+    pthread_exit(0);
+    return 0;
+}
+
+
+/* ----------------------------------------------------------------------
+This function is used to open a server socket connection.
+
+@param:  aPort - Port on which the server will bind and start lisetening.
+
+OpenC apis used
+
+htons(), htonl() : to convert values between host and network byte order
+
+socket():  creates an endpoint for communication and returns a descriptor. We create a "STREAM" socket
+
+bind(): We bind to address INADDR_ANY, which indicates listen happens on all networking interfaces present
+
+listen(): listens for incoming connection.
+
+accept(): accepts a connection on a socket.
+
+-------------------------------------------------------------------------*/
+OS_EXPORT int SocketServerConnection::open()
+{
+    JELOG2(ESOCKET);
+
+    mIsAppRunning = true;
+
+    if (mKeepRunning) // we are listening for push connection
+    {
+        mKeepRunning = false;
+        pthread_join(mThreadId, NULL);
+    }
+    else
+    {
+        mListenSocket = open(mPort);
+    }
+    setActivityFlag(false);
+    return mListenSocket;
+}
+
+int SocketServerConnection::open(int aPort)
+{
+    JELOG2(ESOCKET);
+    int fd  = socket(AF_INET, SOCK_STREAM, 0);
+    if (fd == INVALID_SOCKET)
+    {
+        int err = -errno;
+        return err;
+    }
+
+    struct sockaddr_in addr;
+    addr.sin_family      = AF_INET;
+    addr.sin_port        = htons((unsigned short)aPort);
+    addr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+    int res = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
+    if (res != SOCKET_ERROR)
+    {
+        res = listen(fd, SOMAXCONN);
+        if (res != SOCKET_ERROR)
+        {
+            // setNonBlocking(fd);
+            return fd;
+        }
+    }
+    int err = -errno;
+    LOG(ESOCKET,EInfo,"closing ..");
+    close(fd);
+    return err;
+}
+
+OS_EXPORT int SocketServerConnection::accept()
+{
+    JELOG2(ESOCKET);
+    int sock_fd = INVALID_SOCKET;
+
+    if (mAcceptSocket != INVALID_SOCKET) // incoming push connection
+    {
+        sock_fd = mAcceptSocket;
+        mAcceptSocket = INVALID_SOCKET;
+    }
+    else
+    {
+        sock_fd = accept(mListenSocket);
+    }
+
+    return sock_fd;
+}
+
+int SocketServerConnection::accept(int fd)
+{
+    // paramter fd, is the socket descriptor returned during server socket creation.
+    struct sockaddr_in sa;
+    socklen_t saLen = sizeof(sa);
+    int res = 0;
+
+
+    LOG(ESOCKET, EInfo, "before accept");
+    res = ::accept(fd, (struct sockaddr *)&sa, &saLen);
+    LOG1(ESOCKET, EInfo, "accept returned %d",res);
+    if ((res == -1) && (errno == EWOULDBLOCK))
+    {
+        res = IO_WOULDBLOCK;
+    }
+    if (res == -1)
+    {
+        int err = -errno;
+        return err;
+    }
+    return res;
+}
+OS_EXPORT bool SocketServerConnection::isNormalServerConnection()
+{
+    return mIsNormalServerConnection;
+}
+
+OS_EXPORT void SocketServerConnection::setNormalServerConnection()
+{
+    LOG(ESOCKET,EInfo,"Push is enabled");
+    mIsNormalServerConnection = true;
+}
+
+OS_EXPORT void SocketServerConnection::close()
+{
+    JELOG2(ESOCKET);
+
+    if (mListenSocket != INVALID_SOCKET)
+    {
+        int ret = shutdown(mListenSocket,SHUT_RDWR);
+        close(mListenSocket);
+        LOG1(ESOCKET, EInfo, "shutdown of mListenSocket returned %d",ret);
+    }
+
+    if (mAcceptSocket != INVALID_SOCKET)
+    {
+        int ret = shutdown(mAcceptSocket,SHUT_RDWR);
+        close(mAcceptSocket);
+        LOG1(ESOCKET, EInfo, "shutdown of mAcceptSocket returned %d",ret);
+    }
+
+    if (mKeepRunning) // we are listening for push connection
+    {
+        mKeepRunning = false;
+        pthread_join(mThreadId, NULL);
+    }
+    // reset members
+    mListenSocket = INVALID_SOCKET;
+    mAcceptSocket = INVALID_SOCKET;
+
+    mListener = 0;
+    mThreadId = 0;
+    //mKeepRunning = false;
+
+}
+
+OS_EXPORT std::wstring SocketServerConnection::getUri() const
+{
+    return mUri;
+}
+
+OS_EXPORT std::wstring SocketServerConnection::getFilter() const
+{
+    return mFilter;
+}
+
+OS_EXPORT void SocketServerConnection::setFilter(const std::wstring& aFilter)
+{
+    JELOG2(ESOCKET);
+    mFilter = aFilter;
+    return;
+}
+
+OS_EXPORT int SocketServerConnection::close(int fd)
+{
+    LOG(ESOCKET, EInfo, "+SocketServerConnection::close(int fd)");
+    if (mListenSocket != INVALID_SOCKET)
+    {
+        int ret = shutdown(mListenSocket,SHUT_RDWR);
+        LOG1(ESOCKET, EInfo, "shutdown of mListenSocket returned %d",ret);
+    }
+
+    if (mAcceptSocket != INVALID_SOCKET)
+    {
+        int ret = shutdown(mAcceptSocket,SHUT_RDWR);
+        LOG1(ESOCKET, EInfo, "shutdown of mAcceptSocket returned %d",ret);
+    }
+
+    int ret = ::close(fd);
+    // reset members
+    mListenSocket = INVALID_SOCKET;
+    mAcceptSocket = INVALID_SOCKET;
+
+    LOG(ESOCKET, EInfo, "-SocketServerConnection::close(int fd)");
+    return ret;
+}
+
+void SocketServerConnection::setNonBlocking(int fd)
+{
+    // first get the flags associated with this descriptor.
+    int flags = fcntl(fd, F_GETFL, 0);
+    if (flags < 0)
+    {
+        return; // check errno
+    }
+
+    // set the non-blocking flag to make the accept() call as non-blocking.
+    flags = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+
+    if (flags < 0)
+    {
+        return; // throw exception
+    }
+
+}
+
+void SocketServerConnection::setActivityFlag(bool aFlag)
+{
+    SocketServerConnectionFactory& scf =
+        SocketServerConnectionFactory::getFactory();
+    scf.setPendingMsgFlag(mUri, aFlag);
+}
+