diff -r f5050f1da672 -r 04becd199f91 javacommons/gcfprotocols/socket/serverconnection/src/socketserverconnection.cpp --- /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(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); +} +