--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/genericopenlibs/openenvcore/backend/src/corebackend/usocketbase.cpp Fri Jun 04 16:20:51 2010 +0100
@@ -0,0 +1,532 @@
+/*
+* Copyright (c) 2009 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 "fdesc.h"
+
+TInt CSockDescBase::Socket(RSocketServ& /*aSs*/, int /*family*/, int /*style*/, int /*protocol*/)
+ {
+ return KErrNotSupported;
+ }
+TInt CSockDescBase::Fcntl(TUint anArg, TUint aCmd)
+ {
+ //fcntl supports only F_SETFL and F_GETFL for Non-Blocking I/O
+ //If aCmd and anArg does not match these, return with Error
+ TInt retVal = KErrNone;
+
+ switch( aCmd )
+ {
+ case F_SETFL:
+ {
+
+ //Send the equivalent Flags of Symbian to RSocket
+ TUint flags = iFcntlFlag;
+ if( anArg & O_NONBLOCK )
+ {
+ retVal = iSocket.SetOpt(KSONonBlockingIO, KSOLSocket);
+ flags |= O_NONBLOCK;
+ }
+ else
+ {
+ retVal = iSocket.SetOpt(KSOBlockingIO, KSOLSocket);
+ flags &= ~O_NONBLOCK;
+ }
+ if (retVal == KErrNone)
+ {
+ retVal = iFcntlFlag = flags;
+ }
+ break;
+ }
+ case F_GETFL:
+ {
+ // Socket descriptors are always read/write
+ iFcntlFlag |= O_RDWR;
+ //Return fcntl flag
+ retVal = iFcntlFlag;
+ break;
+ }
+ default:
+ retVal = KErrNotSupported;
+ }
+ return retVal;
+
+
+ }
+
+TInt CSockDescBase::FStat(struct stat *st)
+ {
+
+ // I am a socket about which little is known
+ st->st_mode = S_IFSOCK;
+ st->st_blksize=0;
+ return KErrNone;
+
+ }
+
+TInt CSockDescBase::FinalClose()
+ {
+ iSocket.Close();
+ iReadLock.Close();
+ iWriteLock.Close();
+ iIoctlLock.Close();
+ return KErrNone;
+ }
+
+void CSockDescBase::Read(TDes8& aBuf, TRequestStatus& aStatus)
+ {
+ TSockXfrLength len;
+ TRequestStatus tempStatus;
+
+ iSocket.RecvOneOrMore(aBuf, 0, tempStatus, len); // needs a completion which returns the length
+ User::WaitForRequest(tempStatus);
+ if (tempStatus.Int() != KErrNone)
+ {
+ Complete(aStatus, tempStatus.Int());
+ }
+ else
+ {
+ Complete(aStatus, len());
+ }
+ }
+
+void CSockDescBase::Write(TDes8& aBuf, TRequestStatus& aStatus)
+ {
+ TRequestStatus tempStatus;
+ TInt bytesWritten = 0;
+ TInt bufLength = aBuf.Length();
+ TSockXfrLength len;
+ do
+ {
+ iSocket.Send(aBuf.Mid(bytesWritten), 0, tempStatus, len);
+ User::WaitForRequest(tempStatus);
+ if (len() == 0)
+ {
+ break;
+ }
+ bytesWritten += len();
+ } while (bytesWritten < bufLength);
+ if (tempStatus.Int() != KErrNone)
+ {
+ Complete(aStatus, tempStatus.Int());
+ }
+ else if ((len() == 0) && (bytesWritten == 0))
+ {
+ Complete(aStatus, KErrWouldBlock);
+ }
+ else
+ {
+ //to do change request complete with actual length written when defect
+ //is fixed
+ Complete(aStatus, bytesWritten);
+ }
+
+ }
+
+void CSockDescBase::RecvFrom(TDes8& aDesc, TSockAddr& from, int flags, TRequestStatus& aStatus)
+ {
+
+ //Map the flags to the RSocket flags
+ TUint rSockFlags = 0;
+ if( flags & MSG_PEEK ) //Peek at incoming data
+ rSockFlags |= KSockReadPeek;
+ /* No equivalent flags avaialble in RSocket for
+ MSG_OOB and MSG_WAITALL */
+
+ TSockXfrLength len;
+ TRequestStatus tempStatus;
+
+ switch (iStyle)
+ {
+ case SOCK_STREAM:
+ // recvfrom on a stream ignores the from address - get the peername
+ if (from.Length())
+ SockName(1,from);
+
+ iSocket.RecvOneOrMore(aDesc,rSockFlags,tempStatus,len);
+ break;
+
+ case SOCK_SEQPACKET:
+ // get the peername (as above)
+ if (from.Length())
+ SockName(1,from);
+ iSocket.Recv(aDesc, rSockFlags, tempStatus);
+ break;
+
+ default: // including SOCK_RAW, SOCK_DGRAM
+ // assume datagram, as per behavior of original stdlib code:
+ iSocket.RecvFrom(aDesc,from,rSockFlags,tempStatus,len);
+ }
+
+ User::WaitForRequest(tempStatus);
+ len = aDesc.Length();
+ if (tempStatus.Int() != KErrNone)
+ {
+ if (tempStatus.Int() == KErrEof || tempStatus.Int() == KErrDisconnected)
+ Complete(aStatus, len());
+ else
+ Complete(aStatus, tempStatus.Int());
+ }
+ else
+ {
+ Complete(aStatus, len());
+ }
+
+ }
+
+void CSockDescBase::SendTo(TDes8& aDesc, TSockAddr& to, int flags, TRequestStatus& aStatus)
+ {
+
+ TRequestStatus tempStatus;
+ TSockXfrLength len;
+ TBool sendflg = EFalse;
+
+ if (to.Length()==0)
+ {
+ iSocket.Send(aDesc,flags,tempStatus,len);
+ sendflg = ETrue;
+ }
+ else
+ {
+ if (isStream())
+ Complete(aStatus,KErrNotSupported); // can't sendto a stream
+ else
+ {
+ iSocket.SendTo(aDesc,to,flags,tempStatus,len);
+ sendflg = ETrue;
+ }
+ }
+
+ if(sendflg)
+ {
+ User::WaitForRequest(tempStatus);
+ if (tempStatus.Int() != KErrNone)
+ {
+ if (tempStatus.Int() == KErrEof )
+ Complete(aStatus, len());
+ else
+ Complete(aStatus, tempStatus.Int());
+ }
+ else
+ {
+ Complete(aStatus, len());
+ }
+ }
+
+
+ }
+
+TInt CSockDescBase::CompletionStatus(TInt& aLength, TInt aStatus)
+ {
+ aLength = aStatus;
+ if (aStatus >= 0)
+ {
+ return 0;
+ }
+ return aStatus;
+ }
+
+TInt CSockDescBase::Poll(TUint aEvents)
+ {
+ TInt status = 0;
+ TInt err = 0;
+ TInt readyEvents = 0;
+ err = iSocket.GetOpt(KSOSelectPoll, KSOLSocket, status);
+
+ if (err != KErrNone)
+ {
+ // Poll should return any of the requested events.
+ // In case of any error, the error will be set, and can be later checked by the descriptor.
+
+ iPollErr = err;
+ // For non-blocking socket, ensure to reset "iConnectInProgress" flag for a non-connected
+ // socket on which a connection is pending.
+ if(GetConnectionProgress())
+ {
+ SetConnectionProgress(EFalse);
+ }
+
+ // set all the events that has been requested for
+ // This handles a scenario where connect fails( in loopback )
+ // here poll should return all the events requested as ready
+ // not KErrNone or failure value as returning KErrNone will indicate
+ // no events are ready and notifyactivity will be used though the event has
+ // completed
+ if( aEvents & EReadyForReading )
+ {
+ readyEvents |= EReadyForReading;
+ }
+ if( aEvents & EReadyForWriting )
+ {
+ readyEvents |= EReadyForWriting;
+ }
+ if( aEvents & EAnyException )
+ {
+ readyEvents |= EAnyException;
+ }
+ return readyEvents;
+ }
+
+ if ((status & KSockSelectRead) && (aEvents & EReadyForReading))
+ {
+ readyEvents |= EReadyForReading;
+ }
+
+ if ((status & KSockSelectWrite) && (aEvents & EReadyForWriting))
+ {
+ readyEvents |= EReadyForWriting;
+ }
+
+ if (status & KSockSelectExcept)
+ {
+ if(GetConnectionProgress())
+ {
+ TBool setExceptFd = ETrue;
+ // Some special checks for non-blocking sockets.
+ if(aEvents & EReadyForWriting)
+ {
+ readyEvents |= EReadyForWriting;
+ setExceptFd = EFalse;
+ }
+
+ if(aEvents & EReadyForReading)
+ {
+ readyEvents |= EReadyForReading;
+ setExceptFd = EFalse;
+ }
+
+ if(setExceptFd && (aEvents & EAnyException))
+ {
+ readyEvents |= EAnyException;
+ }
+ }
+ else
+ {
+ if(aEvents & EAnyException)
+ {
+ readyEvents |= EAnyException;
+ }
+ }
+ }
+
+ if(GetConnectionProgress() && readyEvents)
+ {
+ SetConnectionProgress(EFalse);
+ }
+
+ return readyEvents;
+ }
+
+/* Register for notification of activity */
+TInt CSockDescBase::NotifyActivity(TUint aEvents, TRequestStatus& aRequest, TTimeIntervalMicroSeconds32 timeout)
+ {
+ if (timeout.Int())
+ {
+ TInt ret = iIoctlLock.Wait(timeout.Int());
+ if (ret != KErrNone)
+ {
+ return KErrCompletion;
+ }
+ }
+ else
+ {
+ iIoctlLock.Wait();
+ }
+
+ iSelectEvents() = 0;
+
+ if (aEvents & EReadyForReading)
+ {
+ iSelectEvents() = KSockSelectRead;
+ }
+ if (aEvents & EReadyForWriting)
+ {
+ iSelectEvents() |= KSockSelectWrite;
+ }
+ if (aEvents & EAnyException)
+ {
+ iSelectEvents() |= KSockSelectExcept;
+ }
+
+ iSocket.Ioctl(KIOctlSelect, aRequest, &iSelectEvents, KSOLSocket);
+ return KErrNone;
+ }
+
+// -----------------------------------------------------------------------------
+// CSockDescBase::TweakWatchedEvents
+// Requests for socket behaviour specific additional events
+// -----------------------------------------------------------------------------
+//
+void CSockDescBase::TweakWatchedEvents(TUint& events)
+ {
+ if((events & EReadyForReading) || (events & EReadyForWriting))
+ {
+ // Handles scenario of select called with writefds, after a non blocking connect on a socket
+ // as per connect specification, select with the writefds after connect should
+ // set writefds, irrespective of if the connection is successful or failure
+ // We request for an exception event, as in Symbian connect failure is
+ // an exception
+ if(GetConnectionProgress())
+ {
+ events |= EAnyException;
+ }
+ }
+ }
+// -----------------------------------------------------------------------------
+// CSockDescBase::TweakReadyEvents
+// Prepares the socket behaviours specific output events
+// -----------------------------------------------------------------------------
+//
+TInt CSockDescBase::TweakReadyEvents(TInt errval)
+ {
+ TInt returnEvents = 0;
+ if( errval >= KErrNone )
+ {
+ // This file descriptor is socket-like
+ // SelectEvents will also signal ioctlLock.
+ // This hack allows other threads to issue an ioctl on this socket now rather than later.
+ const TUint events = GetSelectEvents();
+ if (events & KSockSelectRead)
+ {
+ returnEvents |= EReadyForReading;
+ }
+ if (events & KSockSelectWrite)
+ {
+ returnEvents |= EReadyForWriting;
+ }
+ if (events & KSockSelectExcept)
+ {
+ // if it is a case of non blocking connect check for the flag
+ // though the flag indicates connection is in progress, we come out of
+ // waitforNrequest only after a event
+ if(GetConnectionProgress())
+ {
+ returnEvents |= EReadyForReading;
+ returnEvents |= EReadyForWriting;
+ }
+ else
+ {
+ returnEvents |= EAnyException;
+ }
+ }
+ }
+ else
+ {
+ if( GetConnectionProgress() )
+ {
+ // Dummy call to retrieve select events also unlocks the socket
+ const TUint events = GetSelectEvents();
+ // set all the events that has been requested for
+ // This handles a scenario where connect fails( in loopback )
+ // here all the events requested should be ready ready
+ // Since PrepareOutputEvents is not aware of the events requested, all are
+ // set as ready and it will be filteret in select
+ returnEvents |= EReadyForWriting;
+ returnEvents |= EReadyForReading;
+ returnEvents |= EAnyException;
+ }
+ else
+ {
+ returnEvents |= EAnyException;
+ }
+ }
+ return returnEvents;
+ }
+
+void CSockDescBase::CancelNotify()
+ {
+ iSocket.CancelIoctl();
+ iIoctlLock.Signal();
+ }
+
+TInt CSockDescBase::Listen(TUint qSize)
+ {
+ return iSocket.Listen(qSize);
+ }
+
+void CSockDescBase::ReadCancel()
+ {
+ iSocket.CancelRecv();
+ }
+
+TInt CSockDescBase::ReadCompletion(TDes8& /*aBuf*/, TInt aStatus)
+ {
+ if(KErrNone == aStatus)
+ {
+ return iLength();
+ }
+ return aStatus;
+ }
+
+void CSockDescBase::RecvFromCancel()
+ {
+ iSocket.CancelRecv();
+ }
+
+void CSockDescBase::SendToCancel()
+ {
+ iSocket.CancelSend();
+ }
+
+void CSockDescBase::WriteCancel()
+ {
+ iSocket.CancelWrite();
+ }
+
+TInt CSockDescBase::SockName(int anEnd, TSockAddr& anAddr)
+ {
+ const TUint KBadFamily = 0xFF000000;
+
+ TUSockAddr *addr;
+
+ addr = (TUSockAddr*)&anAddr;
+ if (addr->iError != 0)
+ {
+ return addr->iError;
+ }
+
+ anAddr.SetFamily(KBadFamily);
+ if (anEnd==0)
+ iSocket.LocalName(anAddr);
+ else
+ iSocket.RemoteName(anAddr);
+ if (anAddr.Family()==KBadFamily)
+ return ENOTCONN; // assume that the call failed, but there is no way to find out why
+ return KErrNone;
+ }
+
+void CSockDescBase::Shutdown(TUint aHow,TRequestStatus& aStatus)
+ {
+ RSocket::TShutdown how;
+
+ switch (aHow)
+ {
+ case SHUT_RD:
+ how = RSocket::EStopInput;
+ break;
+ case SHUT_WR:
+ how = RSocket::EStopOutput;
+ break;
+ case SHUT_RDWR:
+ how = RSocket::EImmediate;
+ break;
+ default:
+ Complete(aStatus,KErrArgument); // Invalid argument
+ return;
+ }
+ iSocket.Shutdown(how,aStatus);
+ return;
+ }