/**************************************************************
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 *************************************************************/



#include <stdio.h>

#include <rtl/memory.h>
#include <osl/time.h>
#include <vos/socket.hxx>
#include <vos/diagnose.hxx>
//#include <osl/tools.h>

using namespace vos;


VOS_IMPLEMENT_CLASSINFO(VOS_CLASSNAME(OSocketAddr, vos),
                        VOS_NAMESPACE(OSocketAddr, vos),
                        VOS_NAMESPACE(OObject, vos), 0);


/*****************************************************************************/
// OSocketAddr()
/*****************************************************************************/
OSocketAddr::OSocketAddr()
{
    m_SockAddr= 0;
}

/*****************************************************************************/
// OSocketAddr()
/*****************************************************************************/
OSocketAddr::OSocketAddr(oslSocketAddr Addr)
{
    m_SockAddr= Addr;
}

/*****************************************************************************/
// OSocketAddr()
/*****************************************************************************/
OSocketAddr::OSocketAddr(const OSocketAddr& Addr) :
ISocketAddr(), OObject()
{
    m_SockAddr= osl_copySocketAddr((oslSocketAddr)Addr);
}

/*****************************************************************************/
// ~OSocketAddr()
/*****************************************************************************/
OSocketAddr::~OSocketAddr()
{
    osl_destroySocketAddr(m_SockAddr);
}


/*****************************************************************************/
// getFamily()
/*****************************************************************************/
OSocketAddr::TAddrFamily OSocketAddr::getFamily() const
{
    return (TAddrFamily)osl_getFamilyOfSocketAddr(m_SockAddr);
}

/*****************************************************************************/
// operator oslSocketAddr ()
/*****************************************************************************/
OSocketAddr::operator oslSocketAddr() const
{
    return m_SockAddr;
}

/*****************************************************************************/
// getHostname()
/*****************************************************************************/
OSocketAddr::TResult OSocketAddr::getHostname(rtl::OUString& rBuffer ) const
{
    return (TResult)osl_getHostnameOfSocketAddr(m_SockAddr, &rBuffer.pData );
}

/*****************************************************************************/
// getLocalHostname()
/*****************************************************************************/
OSocketAddr::TResult OSocketAddr::getLocalHostname( rtl::OUString& pBuffer )
{
    return (TResult)osl_getLocalHostname( &pBuffer.pData );
}

/*****************************************************************************/
// resolveHostname()
/*****************************************************************************/
oslSocketAddr OSocketAddr::resolveHostname(const rtl::OUString& ustrHostname)
{
    return osl_resolveHostname( ustrHostname.pData );
}

/*****************************************************************************/
// operator= (oslSocketAddr Addr)
/*****************************************************************************/
void OSocketAddr::operator= (oslSocketAddr Addr)
{
    if(m_SockAddr) {
        osl_destroySocketAddr(m_SockAddr);
    }

    m_SockAddr= Addr;
}

/*****************************************************************************/
// operator== (oslSocketAddr Addr)
/*****************************************************************************/
sal_Bool OSocketAddr::operator== (oslSocketAddr Addr)
{
    return (osl_isEqualSocketAddr(m_SockAddr, Addr));
}

/*****************************************************************************/
// operator=(const OSocketAddr& Addr)
/*****************************************************************************/
OSocketAddr& OSocketAddr::operator=(const OSocketAddr& Addr)
{
    if(m_SockAddr) {
        osl_destroySocketAddr(m_SockAddr);
    }

    m_SockAddr= osl_copySocketAddr((oslSocketAddr)Addr);

    return *this;
}


VOS_IMPLEMENT_CLASSINFO(VOS_CLASSNAME(OInetSocketAddr, vos),
                        VOS_NAMESPACE(OInetSocketAddr, vos),
                        VOS_NAMESPACE(OSocketAddr, vos), 0);



/*****************************************************************************/
// OInetSocketAddr
// creates arbitrary inet-address (INADDR_ANY)
/*****************************************************************************/
OInetSocketAddr::OInetSocketAddr()
{
    m_SockAddr= osl_createEmptySocketAddr(osl_Socket_FamilyInet);
}

/*****************************************************************************/
// OInetSocketAddr
// uses the given oslSocketAddr as its own
/*****************************************************************************/
OInetSocketAddr::OInetSocketAddr(oslSocketAddr Addr) :
    OSocketAddr(Addr)
{
    VOS_ASSERT(osl_getFamilyOfSocketAddr(Addr) == osl_Socket_FamilyInet);
}

/*****************************************************************************/
// OInetSocketAddr
// Create a socket address either from a dotted decimal address
//(e.g. 141.99.128.50) or a hostname (e.g. www.stardiv.de).
/*****************************************************************************/
OInetSocketAddr::OInetSocketAddr(const rtl::OUString& ustrAddrOrHostname, sal_Int32 Port)
{
    // first try as dotted address.
    m_SockAddr= osl_createInetSocketAddr(ustrAddrOrHostname.pData, Port);

    // create failed, maybe it's an hostname
    if(m_SockAddr == 0)
    {
        m_SockAddr= osl_resolveHostname(ustrAddrOrHostname.pData);

        // host found?
        if(m_SockAddr)
        {
            // set port will fail if addrtype is not osl_Socket_FamilyInet
            VOS_VERIFY(osl_setInetPortOfSocketAddr(m_SockAddr, Port));
        }
    }
}

/*****************************************************************************/
// OInetSocketAddr(const OInetSocketAddr&)
/*****************************************************************************/
OInetSocketAddr::OInetSocketAddr(const OInetSocketAddr& sa) :
    OSocketAddr(sa)
{
    VOS_ASSERT(getFamily() == TFamily_Inet);
}

/*****************************************************************************/
// OInetSocketAddr(const OSocketAddr&)
/*****************************************************************************/
OInetSocketAddr::OInetSocketAddr(const OSocketAddr& sa) :
    OSocketAddr(sa)
{
    VOS_ASSERT(sa.getFamily() == TFamily_Inet);
}

/*****************************************************************************/
// ~OInetSocketAddr
/*****************************************************************************/
OInetSocketAddr::~OInetSocketAddr()
{
}

/*****************************************************************************/
// operator= (oslSocketAddr Addr)
/*****************************************************************************/
void OInetSocketAddr::operator= (oslSocketAddr Addr)
{
    VOS_PRECOND(osl_getFamilyOfSocketAddr(Addr) == osl_Socket_FamilyInet,
                "oslSocketAddr not of type osl_Socket_FamilyInet!");

    OSocketAddr::operator=(Addr);
}

/*****************************************************************************/
// operator== (oslSocketAddr Addr)
/*****************************************************************************/
sal_Bool OInetSocketAddr::operator== (oslSocketAddr Addr)
{
    return (osl_isEqualSocketAddr(m_SockAddr, Addr));
}

/*****************************************************************************/
// operator=(const OInetSocketAddr& Addr)
/*****************************************************************************/
OInetSocketAddr& OInetSocketAddr::operator=(const OInetSocketAddr& Addr)
{
    VOS_ASSERT(Addr.getFamily() == TFamily_Inet);

    OSocketAddr::operator=(Addr);

    return *this;
}

/*****************************************************************************/
// operator=(const OSocketAddr& Addr)
/*****************************************************************************/
OInetSocketAddr& OInetSocketAddr::operator=(const OSocketAddr& Addr)
{
    VOS_ASSERT(Addr.getFamily() == TFamily_Inet);

    OSocketAddr::operator=(Addr);

    return *this;
}

/*****************************************************************************/
// getServicePort()
/*****************************************************************************/
sal_Int32 OInetSocketAddr::getServicePort(const rtl::OUString& ustrServiceName,
                                    const rtl::OUString& ustrProtocolName)
{
    return osl_getServicePort(ustrServiceName.pData, ustrProtocolName.pData);
}


/*****************************************************************************/
// getPort()
/*****************************************************************************/
sal_Int32 OInetSocketAddr::getPort () const
{
    return osl_getInetPortOfSocketAddr(m_SockAddr);
}


/*****************************************************************************/
// setPort()
/*****************************************************************************/
sal_Bool OInetSocketAddr::setPort (sal_Int32 Port)
{
    return osl_setInetPortOfSocketAddr(m_SockAddr, Port);
}


/*****************************************************************************/
// getDottedAddr()
/*****************************************************************************/
OSocketAddr::TResult OInetSocketAddr::getDottedAddr( rtl::OUString& pBuffer ) const
{
    return (TResult)osl_getDottedInetAddrOfSocketAddr(m_SockAddr, &pBuffer.pData );
}

/*****************************************************************************/
// setAddr()
/*****************************************************************************/
sal_Bool OInetSocketAddr::setAddr(const rtl::OUString& ustrAddrOrHostname)
{
    sal_Int32 Port = 0;

    if(m_SockAddr) {

        // retrieve old port
        Port= getPort();

        // free old address
        osl_destroySocketAddr(m_SockAddr);
        m_SockAddr= 0;
    }

    // first try as dotted address.
    m_SockAddr= osl_createInetSocketAddr(ustrAddrOrHostname.pData, Port);

    // create failed, maybe it's an hostname
    if(m_SockAddr == 0)
    {

        m_SockAddr= osl_resolveHostname( ustrAddrOrHostname.pData );

        // host found?
        if(m_SockAddr==0)
        {
            return sal_False;
        }

        // set port will fail if addrtype is not osl_Socket_FamilyInet
        VOS_VERIFY(osl_setInetPortOfSocketAddr(m_SockAddr, Port));

    }

    return sal_True;
}

///////////////////////////////////////////////////////////////////////////////
// OIpxSocketAddr

VOS_IMPLEMENT_CLASSINFO(VOS_CLASSNAME(OIpxSocketAddr, vos),
                        VOS_NAMESPACE(OIpxSocketAddr, vos),
                        VOS_NAMESPACE(OSocketAddr, vos), 0);


/*****************************************************************************/
// OIpxSocketAddr()
/*****************************************************************************/
OIpxSocketAddr::OIpxSocketAddr()
{
    m_SockAddr= osl_createEmptySocketAddr(osl_Socket_FamilyIpx);
}

/*****************************************************************************/
// OIpxSocketAddr(oslSocketAddr)
/*****************************************************************************/
OIpxSocketAddr::OIpxSocketAddr(oslSocketAddr Addr) :
    OSocketAddr(Addr)
{
    VOS_ASSERT(osl_getFamilyOfSocketAddr(Addr) == osl_Socket_FamilyIpx);
}

/*****************************************************************************/
// OIpxSocketAddr()
/*****************************************************************************/
OIpxSocketAddr::OIpxSocketAddr(const rtl::OUString&,
                               const rtl::OUString&,
                               sal_uInt32 )
{
    // jbu : functionality removed from vos
}

/*****************************************************************************/
// OIpxSocketAddr(OIpxSocketAddr&)
/*****************************************************************************/
OIpxSocketAddr::OIpxSocketAddr(const OIpxSocketAddr& sa) :
    OSocketAddr(sa)
{
    VOS_ASSERT(sa.getFamily() == TFamily_Ipx);
}


/*****************************************************************************/
// OIpxSocketAddr(OSocketAddr&)
/*****************************************************************************/
OIpxSocketAddr::OIpxSocketAddr(const OSocketAddr& sa) :
    OSocketAddr(sa)
{
    VOS_ASSERT(sa.getFamily() == TFamily_Ipx);
}

/*****************************************************************************/
// ~OIpxSocketAddr()
/*****************************************************************************/
OIpxSocketAddr::~OIpxSocketAddr()
{
}


/*****************************************************************************/
// operator=()
/*****************************************************************************/
void OIpxSocketAddr::operator= (oslSocketAddr Addr)
{
    VOS_PRECOND(osl_getFamilyOfSocketAddr(Addr) == osl_Socket_FamilyIpx,
            "oslSocketAddr not of type osl_Socket_FamilyIpx!");

    OSocketAddr::operator=(Addr);
}

/*****************************************************************************/
// operator== (oslSocketAddr Addr)
/*****************************************************************************/
sal_Bool OIpxSocketAddr::operator== (oslSocketAddr Addr)
{
    return (osl_isEqualSocketAddr(m_SockAddr, Addr));
}

/*****************************************************************************/
// operator=(const OIpxSocketAddr& Addr)
/*****************************************************************************/
OIpxSocketAddr& OIpxSocketAddr::operator=(const OIpxSocketAddr& Addr)
{
    VOS_ASSERT(Addr.getFamily() == TFamily_Ipx);

    OSocketAddr::operator=(Addr);

    return *this;
}

/*****************************************************************************/
// operator=(const OSocketAddr& Addr)
/*****************************************************************************/
OIpxSocketAddr& OIpxSocketAddr::operator=(const OSocketAddr& Addr)
{
    VOS_ASSERT(Addr.getFamily() == TFamily_Ipx);

    OSocketAddr::operator=(Addr);

    return *this;
}

/*****************************************************************************/
// getNetNumber()
/*****************************************************************************/
OSocketAddr::TResult OIpxSocketAddr::getNetNumber(TIpxNetNumber&) const
{
    // jbu : functionality removed from vos
    return (TResult)0;
}

/*****************************************************************************/
// getNodeNumber()
/*****************************************************************************/
OSocketAddr::TResult OIpxSocketAddr::getNodeNumber(TIpxNodeNumber& ) const
{
    // jbu : functionality removed from vos
    return (TResult)0;
}

/*****************************************************************************/
// getSocketNumber()
/*****************************************************************************/
sal_uInt32 OIpxSocketAddr::getSocketNumber() const
{
//      return osl_getIpxSocketNumber(m_SockAddr);
    return (TResult)0;
}


/*****************************************************************************/
// getAddressString()
/*****************************************************************************/
//void OIpxSocketAddr::getAddressString(sal_Char* Buffer, sal_uInt32 Len) const
void OIpxSocketAddr::getAddressString( rtl::OUString& ) const
{
    // jbu : functionality removed from vos
}


///////////////////////////////////////////////////////////////////////////////
// Socket


VOS_IMPLEMENT_CLASSINFO(VOS_CLASSNAME(OSocket, vos),
                        VOS_NAMESPACE(OSocket, vos),
                        VOS_NAMESPACE(OObject, vos), 0);

/*****************************************************************************/
// OSocket()
/*****************************************************************************/
OSocket::OSocket()
{
    m_pRecvTimeout = 0;
    m_pSendTimeout = 0;

    m_pSockRef= 0;
}


/*****************************************************************************/
// OSocket()
/*****************************************************************************/
OSocket::OSocket(TSocketType Type,
                 TAddrFamily Family,
                 TProtocol   Protocol)
{
    m_pRecvTimeout = 0;
    m_pSendTimeout = 0;

    m_pSockRef=
        new SockRef(osl_createSocket((oslAddrFamily)Family,
                                     (oslSocketType)Type,
                                     (oslProtocol)Protocol));

    VOS_POSTCOND(m_pSockRef != 0, "OSocket(): new failed.\n");
    VOS_POSTCOND((*m_pSockRef)(), "OSocket(): creation of socket failed!\n");
}

/*****************************************************************************/
// OSocket()
/*****************************************************************************/
OSocket::OSocket(const OSocket& sock) :
ISocketTypes(), OReference(), OObject()
{
    m_pRecvTimeout = 0;
    m_pSendTimeout = 0;
    m_pSockRef=0;

    VOS_ASSERT(sock.m_pSockRef != 0);

    if ( sock.m_pSockRef !=0 )
    {
        m_pSockRef= sock.m_pSockRef;

        setRecvTimeout(sock.m_pRecvTimeout);
        setSendTimeout(sock.m_pSendTimeout);

        m_pSockRef->acquire();
    }
}

/*****************************************************************************/
// OSocket()
/*****************************************************************************/
OSocket::OSocket(oslSocket Socket)
{
    m_pRecvTimeout = 0;
    m_pSendTimeout = 0;

    m_pSockRef = new SockRef(Socket);
}


/*****************************************************************************/
// ~OSocket()
/*****************************************************************************/
OSocket::~OSocket()
{
    close();

    delete m_pRecvTimeout;
    delete m_pSendTimeout;
}


/*****************************************************************************/
// create
/*****************************************************************************/
sal_Bool OSocket::create(TSocketType Type,
                        TAddrFamily Family,
                        TProtocol   Protocol)
{
    // if this was a valid socket, decrease reference
    if ((m_pSockRef) && (m_pSockRef->release() == 0))
    {
        osl_releaseSocket((*m_pSockRef)());
        delete m_pSockRef;
        m_pSockRef= 0;
    }

    m_pSockRef=
        new SockRef(osl_createSocket((oslAddrFamily)Family,
                                     (oslSocketType)Type,
                                     (oslProtocol)Protocol));

    VOS_POSTCOND(m_pSockRef != 0, "OSocket(): new failed.\n");

    return (*m_pSockRef)() != 0;
}

/*****************************************************************************/
// operator=
/*****************************************************************************/
OSocket& OSocket::operator= (const OSocket& sock)
{
    VOS_PRECOND(sock.m_pSockRef != 0, "OSocket::operator=: tried to assign an empty/invalid socket\n");

    if (m_pSockRef == sock.m_pSockRef)
        return *this;

    // if this was a valid socket, decrease reference
    if ((m_pSockRef) && (m_pSockRef->release() == 0))
    {
        osl_releaseSocket((*m_pSockRef)());
        delete m_pSockRef;
        m_pSockRef= 0;
    }

    m_pSockRef= sock.m_pSockRef;

    setRecvTimeout(sock.m_pRecvTimeout);
    setSendTimeout(sock.m_pSendTimeout);

    m_pSockRef->acquire();

    return *this;
}

/*****************************************************************************/
// operator oslSocket()
/*****************************************************************************/
OSocket::operator oslSocket() const
{
    VOS_ASSERT(m_pSockRef);
    return (*m_pSockRef)();
}

/*****************************************************************************/
// isValid()
/*****************************************************************************/
sal_Bool OSocket::isValid() const
{
    return m_pSockRef != 0 && (*m_pSockRef)() != 0;
}


/*****************************************************************************/
// close
/*****************************************************************************/
void OSocket::close()
{
    if (m_pSockRef && (*m_pSockRef)() && (m_pSockRef->release() == 0))
    {
        osl_releaseSocket((*m_pSockRef)());
        delete m_pSockRef;
    }

    m_pSockRef= 0;
}

/*****************************************************************************/
// getLocalAddr
/*****************************************************************************/
void OSocket::getLocalAddr(OSocketAddr& sa) const
{
    VOS_ASSERT(m_pSockRef && (*m_pSockRef)());

    if ( m_pSockRef && (*m_pSockRef)() )
    {
        sa= osl_getLocalAddrOfSocket((*m_pSockRef)());
    }
}

/*****************************************************************************/
// getLocalPort
/*****************************************************************************/
sal_Int32 OSocket::getLocalPort() const
{
    VOS_ASSERT(m_pSockRef && (*m_pSockRef)());

    sal_Int32 Port= OSL_INVALID_PORT;

    if ( m_pSockRef && (*m_pSockRef)() )
    {
        oslSocketAddr Addr= osl_getLocalAddrOfSocket((*m_pSockRef)());

        if(Addr)
        {
            Port= osl_getInetPortOfSocketAddr(Addr);
            osl_destroySocketAddr(Addr);
        }
    }

    return Port;
}

/*****************************************************************************/
// getLocalHost
/*****************************************************************************/
OSocket::TResult OSocket::getLocalHost( rtl::OUString& pBuffer) const
{
    VOS_ASSERT(m_pSockRef && (*m_pSockRef)());

    if ( m_pSockRef && (*m_pSockRef)() )
    {
        oslSocketAddr Addr= osl_getLocalAddrOfSocket((*m_pSockRef)());

        if(Addr)
        {
//          TResult Result= (TResult)osl_getHostnameOfSocketAddr(Addr,
//                                                      pBuffer, BufferSize);
            TResult Result= (TResult)osl_getHostnameOfSocketAddr(Addr,
                                                             &pBuffer.pData );

            osl_destroySocketAddr(Addr);

            return Result;
        }
    }

    return TResult_Error;
}

/*****************************************************************************/
// getPeerAddr
/*****************************************************************************/
void OSocket::getPeerAddr(OSocketAddr& sa) const
{
    VOS_ASSERT(m_pSockRef && (*m_pSockRef)());

    if ( m_pSockRef && (*m_pSockRef)() )
    {
        sa= osl_getPeerAddrOfSocket((*m_pSockRef)());
    }
}

/*****************************************************************************/
// getPeerPort
/*****************************************************************************/
sal_Int32 OSocket::getPeerPort() const
{
    VOS_ASSERT(m_pSockRef && (*m_pSockRef)());

    sal_Int32 Port= OSL_INVALID_PORT;

    if ( m_pSockRef && (*m_pSockRef)() )
    {
        oslSocketAddr Addr= osl_getPeerAddrOfSocket((*m_pSockRef)());

        if(Addr)
        {
            Port= osl_getInetPortOfSocketAddr(Addr);
            osl_destroySocketAddr(Addr);
        }
    }

    return Port;
}

/*****************************************************************************/
// getPeerHost
/*****************************************************************************/
OSocket::TResult OSocket::getPeerHost( rtl::OUString& pBuffer ) const
{
    VOS_ASSERT(m_pSockRef && (*m_pSockRef)());

    if ( m_pSockRef && (*m_pSockRef)() )
    {
        oslSocketAddr Addr= osl_getPeerAddrOfSocket((*m_pSockRef)());

        if(Addr)
        {
//          TResult Result= (TResult)osl_getHostnameOfSocketAddr(Addr,
//                                                      pBuffer, BufferSize);
            TResult Result= (TResult)osl_getHostnameOfSocketAddr(Addr,
                                                             &pBuffer.pData );

            osl_destroySocketAddr(Addr);

            return Result;
        }
    }

    return TResult_Error;
}

/*****************************************************************************/
// bind
/*****************************************************************************/
sal_Bool OSocket::bind(const OSocketAddr& Addr)
{
    VOS_ASSERT(m_pSockRef && (*m_pSockRef)());

    if ( m_pSockRef && (*m_pSockRef)() )
    {
        return osl_bindAddrToSocket((*m_pSockRef)(), (oslSocketAddr)Addr);
    }

    return sal_False;
}


/*****************************************************************************/
// setSendTimeout
/*****************************************************************************/
void OSocket::setSendTimeout(const TimeValue* pTimeout)
{
    delete m_pSendTimeout;

    if (pTimeout)
        m_pSendTimeout = new TimeValue(*pTimeout);
    else
        m_pSendTimeout = 0;
}

/*****************************************************************************/
// setRecvTimeout
/*****************************************************************************/
void OSocket::setRecvTimeout(const TimeValue* pTimeout)
{
    delete m_pRecvTimeout;

    if (pTimeout)
        m_pRecvTimeout = new TimeValue(*pTimeout);
    else
        m_pRecvTimeout = 0;
}

/*****************************************************************************/
// isRecvReady
/*****************************************************************************/
sal_Bool OSocket::isRecvReady(const TimeValue* pTimeout) const
{
    VOS_ASSERT(m_pSockRef && (*m_pSockRef)());

    if ( m_pSockRef && (*m_pSockRef)() )
    {
        return osl_isReceiveReady((*m_pSockRef)(), pTimeout);
    }

    return sal_False;
}

/*****************************************************************************/
// isSendReady
/*****************************************************************************/
sal_Bool OSocket::isSendReady(const TimeValue* pTimeout) const
{
    VOS_ASSERT(m_pSockRef && (*m_pSockRef)());

    if ( m_pSockRef && (*m_pSockRef)() )
    {
        return osl_isSendReady((*m_pSockRef)(), pTimeout);
    }

    return sal_False;
}

/*****************************************************************************/
// isExceptionPending
/*****************************************************************************/
sal_Bool OSocket::isExceptionPending(const TimeValue* pTimeout) const
{
    VOS_ASSERT(m_pSockRef && (*m_pSockRef)());

    if ( m_pSockRef && (*m_pSockRef)() )
    {
        return osl_isExceptionPending((*m_pSockRef)(), pTimeout);
    }

    return sal_False;
}


/*****************************************************************************/
// getOption
/*****************************************************************************/
sal_Int32 OSocket::getOption(TSocketOption Option,
                              void* pBuffer,
                           sal_uInt32 BufferLen,
                           TSocketOptionLevel Level) const
{
    VOS_ASSERT(m_pSockRef && (*m_pSockRef)());

    if ( m_pSockRef && (*m_pSockRef)() )
    {
        return osl_getSocketOption((*m_pSockRef)(),
                                   (oslSocketOptionLevel)Level,
                                   (oslSocketOption)Option,
                                   pBuffer,
                                   BufferLen);
    }

    return sal_False;
}

/*****************************************************************************/
// setOption
/*****************************************************************************/
sal_Bool OSocket::setOption(TSocketOption Option,
                           void* pBuffer,
                           sal_uInt32 BufferLen,
                           TSocketOptionLevel Level) const
{
    VOS_ASSERT(m_pSockRef && (*m_pSockRef)());

    if ( m_pSockRef && (*m_pSockRef)() )
    {
        return osl_setSocketOption((*m_pSockRef)(),
                                   (oslSocketOptionLevel)Level,
                                   (oslSocketOption)Option,
                                   pBuffer,
                                   BufferLen);
    }

    return sal_False;
}


/*****************************************************************************/
// enableNonBlockingMode
/*****************************************************************************/
sal_Bool OSocket::enableNonBlockingMode(sal_Bool On)
{
    VOS_ASSERT(m_pSockRef && (*m_pSockRef)());

    if ( m_pSockRef && (*m_pSockRef)() )
    {
        return osl_enableNonBlockingMode((*m_pSockRef)(), On);
    }

    return sal_False;
}

/*****************************************************************************/
// isNonBlockingMode
/*****************************************************************************/
sal_Bool OSocket::isNonBlockingMode() const
{
    VOS_ASSERT(m_pSockRef && (*m_pSockRef)());

    if ( m_pSockRef && (*m_pSockRef)() )
    {
        return osl_isNonBlockingMode((*m_pSockRef)());
    }

    return sal_False;
}

/*****************************************************************************/
// getType
/*****************************************************************************/
OSocket::TSocketType OSocket::getType() const
{
    VOS_ASSERT(m_pSockRef && (*m_pSockRef)());

    if ( m_pSockRef && (*m_pSockRef)() )
    {
        return (TSocketType)osl_getSocketType((*m_pSockRef)());
    }

    return TType_Invalid;
}

/*****************************************************************************/
// clearError
/*****************************************************************************/
sal_Int32 OSocket::clearError() const
{
    sal_Int32 err = 0;

    getOption(TOption_Error, &err, sizeof(err));

    return err;
}

/*****************************************************************************/
// setDebug
/*****************************************************************************/
sal_Int32 OSocket::setDebug(sal_Int32 opt) const
{
    sal_Int32 old= 0;

    getOption(TOption_Debug, &old, sizeof(old));

    if (opt != -1)
        setOption(TOption_Debug, &opt, sizeof(opt));

    return old;
}

/*****************************************************************************/
// setReuseAddr
/*****************************************************************************/
sal_Int32 OSocket::setReuseAddr(sal_Int32 opt) const
{
    sal_Int32 old = 0;

    getOption(TOption_ReuseAddr, &old, sizeof(old));

    if (opt != -1)
        setOption(TOption_ReuseAddr, &opt, sizeof(opt));

    return (old);
}

/*****************************************************************************/
// setKeepAlive
/*****************************************************************************/
sal_Int32 OSocket::setKeepAlive(sal_Int32 opt) const
{
    sal_Int32 old = 0;

    getOption(TOption_KeepAlive, &old, sizeof(old));

    if (opt != -1)
        setOption(TOption_KeepAlive, &opt, sizeof(opt));

    return (old);
}

/*****************************************************************************/
// setDontRoute
/*****************************************************************************/
sal_Int32 OSocket::setDontRoute(sal_Int32 opt) const
{
    sal_Int32 old = 0;

    getOption(TOption_DontRoute, &old, sizeof(old));

    if (opt != -1)
        setOption(TOption_DontRoute, &opt, sizeof(opt));

    return (old);
}

/*****************************************************************************/
// setBroadcast
/*****************************************************************************/
sal_Int32 OSocket::setBroadcast(sal_Int32 opt) const
{
    sal_Int32 old = 0;

    getOption(TOption_Broadcast, &old, sizeof(old));

    if (opt != -1)
        setOption(TOption_Broadcast, &opt, sizeof(opt));

    return (old);
}

/*****************************************************************************/
// setOobinline
/*****************************************************************************/
sal_Int32 OSocket::setOobinline(sal_Int32 opt) const
{
    sal_Int32 old = 0;

    getOption(TOption_OOBinLine, &old, sizeof(old));

    if (opt != -1)
        setOption(TOption_OOBinLine, &opt, sizeof(opt));

    return (old);
}

/*****************************************************************************/
// setLinger
/*****************************************************************************/
sal_Int32 OSocket::setLinger(sal_Int32 time) const
{
    /* local decl. of linger-struct */
    struct SockLinger
    {
        sal_Int32 m_onoff;    // option on/off
        sal_Int32 m_linger;   // linger time
    };


    SockLinger  old = { 0, 0 };

    getOption(TOption_Linger, &old, sizeof(old));

    if (time > 0) // enable linger with wait-times > 0
    {
        SockLinger nw = { 1, time };
        setOption(TOption_Linger, &nw, sizeof(nw));
    }
    else if (time == 0) // disable linger with wait-time == 0
    {
        SockLinger nw = { 0, old.m_linger };
        setOption(TOption_Linger, &nw, sizeof(nw));
    }

    // returns 0 if linger was off, else the linger-time
    return (old.m_onoff ? old.m_linger : 0);
}

/*****************************************************************************/
// setSendBufSize
/*****************************************************************************/
sal_Int32 OSocket::setSendBufSize(sal_Int32 sz) const
{
    sal_Int32 old = 0;

    getOption(TOption_SndBuf, &old, sizeof(old));

    if (sz >= 0)
        setOption(TOption_SndBuf, &sz, sizeof(sz));

    return (old);
}

/*****************************************************************************/
// setRecvBufSize
/*****************************************************************************/
sal_Int32 OSocket::setRecvBufSize(sal_Int32 sz) const
{
    sal_Int32 old = 0;

    getOption(TOption_RcvBuf, &old, sizeof(old));

    if (sz >= 0)
        setOption(TOption_RcvBuf, &sz, sizeof(sz));

    return (old);
}

/*****************************************************************************/
// setTcpNoDelay
/*****************************************************************************/
sal_Int32 OSocket::setTcpNoDelay(sal_Int32 sz) const
{
    sal_Int32 old = 0;

    getOption(TOption_TcpNoDelay, &old, sizeof(old), TLevel_Tcp);

    if (sz >= 0)
        setOption(TOption_TcpNoDelay, &sz, sizeof(sz), TLevel_Tcp);

    return (old);
}

/*****************************************************************************/
// getError
/*****************************************************************************/
//void OSocket::getError(sal_Char* pBuffer, sal_uInt32 nSize) const
void OSocket::getError( rtl::OUString& pBuffer ) const
{
    VOS_ASSERT(m_pSockRef && (*m_pSockRef)());

    if (m_pSockRef && (*m_pSockRef)())
        osl_getLastSocketErrorDescription((*m_pSockRef)(), &pBuffer.pData );
    else
        osl_getLastSocketErrorDescription(NULL, &pBuffer.pData );
}

/*****************************************************************************/
// getError
/*****************************************************************************/
OSocket::TSocketError OSocket::getError() const
{
    VOS_ASSERT(m_pSockRef && (*m_pSockRef)());

    if (m_pSockRef && (*m_pSockRef)())
        return (TSocketError)osl_getLastSocketError((*m_pSockRef)());
    else
        return (TSocketError)osl_getLastSocketError(NULL);
}



VOS_IMPLEMENT_CLASSINFO(VOS_CLASSNAME(OAcceptorSocket, vos),
                        VOS_NAMESPACE(OAcceptorSocket, vos),
                        VOS_NAMESPACE(OSocket, vos), 0);


/*****************************************************************************/
// OAcceptorSocket
/*****************************************************************************/
OAcceptorSocket::OAcceptorSocket(TAddrFamily Family,
                                 TProtocol   Protocol,
                                 TSocketType Type) :
    OSocket(Type, Family, Protocol)
{
}

/*****************************************************************************/
// OAcceptorSocket
/*****************************************************************************/
OAcceptorSocket::OAcceptorSocket(const OAcceptorSocket& sock) :
    OSocket(sock)
{
}

/*****************************************************************************/
// ~OAcceptorSocket
/*****************************************************************************/
OAcceptorSocket::~OAcceptorSocket()
{
    if (m_pSockRef && (*m_pSockRef)() && (m_pSockRef->release() == 0))
    {
        /* mfe: prepare for forthcoming api change */
        osl_closeSocket((*m_pSockRef)());
        osl_releaseSocket((*m_pSockRef)());
        delete m_pSockRef;
        m_pSockRef = 0;
    }
}

/*****************************************************************************/
// close
/*****************************************************************************/
void OAcceptorSocket::close()
{
    if (m_pSockRef && (*m_pSockRef)() && (m_pSockRef->release() == 0))
    {
        osl_closeSocket((*m_pSockRef)());
    }

    m_pSockRef= 0;
}

/*****************************************************************************/
// listen
/*****************************************************************************/
sal_Bool OAcceptorSocket::listen(sal_Int32 MaxPendingConnections)
{
    VOS_ASSERT(m_pSockRef && (*m_pSockRef)());

    if ( m_pSockRef && (*m_pSockRef)() )
    {
        return osl_listenOnSocket((*m_pSockRef)(), MaxPendingConnections);
    }

    return sal_False;
}


/*****************************************************************************/
// acceptConnection
/*****************************************************************************/
OSocket::TResult OAcceptorSocket::acceptConnection(OStreamSocket& connection)
{
    if (m_pRecvTimeout && ! isRecvReady(m_pRecvTimeout))
        return TResult_TimedOut;

    VOS_ASSERT(m_pSockRef && (*m_pSockRef)());
    OStreamSocket aSocket;

    if ( m_pSockRef && (*m_pSockRef)() )
    {
        aSocket = osl_acceptConnectionOnSocket((*m_pSockRef)(), 0);
    }

    if( aSocket.isValid() )
    {
        connection = aSocket;
        return TResult_Ok;
    }
    else
    {
        return TResult_Error;
    }

}

/*****************************************************************************/
// acceptConnection
/*****************************************************************************/
OSocket::TResult OAcceptorSocket::acceptConnection(OStreamSocket& connection,
                                                   OSocketAddr& sa)
{
    oslSocketAddr PeerAddr = 0;
    oslSocket     Socket = 0;

    if (m_pRecvTimeout && ! isRecvReady(m_pRecvTimeout))
        return TResult_TimedOut;

    VOS_ASSERT(m_pSockRef && (*m_pSockRef)());

    if ( m_pSockRef && (*m_pSockRef)() )
    {
        Socket= osl_acceptConnectionOnSocket((*m_pSockRef)(), &PeerAddr);
    }

    if (Socket)
    {
        sa= PeerAddr;
        connection= Socket;
        return TResult_Ok;
    }
    else
    {
        return TResult_Error;
    }
}


VOS_IMPLEMENT_CLASSINFO(VOS_CLASSNAME(OStreamSocket, vos),
                        VOS_NAMESPACE(OStreamSocket, vos),
                        VOS_NAMESPACE(OSocket, vos), 0);



/*****************************************************************************/
// OStreamSocket
/*****************************************************************************/
OStreamSocket::OStreamSocket()
{
}

/*****************************************************************************/
// OStreamSocket
/*****************************************************************************/
OStreamSocket::OStreamSocket(TAddrFamily Family,
                             TProtocol   Protocol,
                             TSocketType Type) :
    OSocket(Type, Family, Protocol)
{
}


/*****************************************************************************/
// OStreamSocket
/*****************************************************************************/
OStreamSocket::OStreamSocket(oslSocket Socket) :
    OSocket(Socket)
{
}

/*****************************************************************************/
// OStreamSocket
// copy constructor
/*****************************************************************************/
OStreamSocket::OStreamSocket(const OStreamSocket& sock) :
    OSocket(sock), IStream()
{
}

/*****************************************************************************/
// OStreamSocket
// copy constructor
/*****************************************************************************/
OStreamSocket::OStreamSocket(const OSocket& sock) :
    OSocket(sock)
{
}

/*****************************************************************************/
// ~OStreamSocket
/*****************************************************************************/
OStreamSocket::~OStreamSocket()
{
}

/*****************************************************************************/
// close
/*****************************************************************************/
void OStreamSocket::close()
{
    if (m_pSockRef && (*m_pSockRef)() && (m_pSockRef->release() == 0))
    {
        shutdown();
        osl_releaseSocket((*m_pSockRef)());
        delete m_pSockRef;
    }

    m_pSockRef= 0;
}


/*****************************************************************************/
// operator=(oslSocket)
/*****************************************************************************/
OStreamSocket& OStreamSocket::operator=(oslSocket Socket)
{
    OSocket::operator=(Socket);

    return *this;
}

/*****************************************************************************/
// operator=
/*****************************************************************************/
OStreamSocket& OStreamSocket::operator= (const OSocket& sock)
{
    OSocket::operator=(sock);

    return *this;
}

/*****************************************************************************/
// operator=
/*****************************************************************************/
OStreamSocket& OStreamSocket::operator= (const OStreamSocket& sock)
{
    OSocket::operator=(sock);

    return *this;
}

/*****************************************************************************/
// read
/*****************************************************************************/
sal_Int32 OStreamSocket::read(void* pBuffer, sal_uInt32 n) const
{
    sal_uInt8 *Ptr = (sal_uInt8  *)pBuffer;

    if (m_pRecvTimeout && ! isRecvReady(m_pRecvTimeout))
        return 0;

    VOS_ASSERT(m_pSockRef && (*m_pSockRef)());

    if ( ! ( m_pSockRef && (*m_pSockRef)() ) )
    {
        return -1;
    }

    /* loop until all desired bytes were read or an error occured */
    sal_uInt32 BytesRead= 0;
    sal_uInt32 BytesToRead= n;
    while (BytesToRead > 0)
    {
        sal_Int32 RetVal;
        RetVal= osl_receiveSocket((*m_pSockRef)(),
                                   Ptr,
                                   BytesToRead,
                                   osl_Socket_MsgNormal);

        /* error occured? */
        if(RetVal <= 0)
        {
            break;
        }

        BytesToRead -= RetVal;
        BytesRead += RetVal;
        Ptr += RetVal;

        /* wait for next available data or timeout */
        if ( BytesToRead > 0 && m_pRecvTimeout && ! isRecvReady(m_pRecvTimeout))
            break;

    }

    return BytesRead;
}

/*****************************************************************************/
// write
/*****************************************************************************/
sal_Int32 OStreamSocket::write(const void* pBuffer, sal_uInt32 n)
{
    sal_uInt8 *Ptr = (sal_uInt8 *)pBuffer;

    if (m_pSendTimeout && ! isSendReady(m_pSendTimeout))
        return 0;

    VOS_ASSERT(m_pSockRef && (*m_pSockRef)());

    if ( ! ( m_pSockRef && (*m_pSockRef)() ) )
    {
        return -1;
    }

    /* loop until all desired bytes were send or an error occured */
    sal_uInt32 BytesSend= 0;
    sal_uInt32 BytesToSend= n;
    while (BytesToSend > 0)
    {
        sal_Int32 RetVal;

        RetVal= osl_sendSocket((*m_pSockRef)(),
                                Ptr,
                                BytesToSend,
                                osl_Socket_MsgNormal);

        /* error occured? */
        if(RetVal <= 0)
        {
            break;
        }

        BytesToSend -= RetVal;
        BytesSend += RetVal;
        Ptr += RetVal;

        /* wait till new data is available or timeout occures */
        if ( BytesToSend > 0 && m_pSendTimeout && ! isSendReady(m_pSendTimeout))
            break;
    }

    return BytesSend;
}

sal_Bool OStreamSocket::isEof() const
{
    return isValid();
    // BHO not enough
}

/*****************************************************************************/
// recv
/*****************************************************************************/
sal_Int32 OStreamSocket::recv(void* pBuffer,
                            sal_uInt32 BytesToRead,
                            TSocketMsgFlag Flag)
{
    if (m_pRecvTimeout && ! isRecvReady(m_pRecvTimeout))
        return 0;

    VOS_ASSERT(m_pSockRef && (*m_pSockRef)());

    if ( ! ( m_pSockRef && (*m_pSockRef)() ) )
    {
        return -1;
    }

    return osl_receiveSocket((*m_pSockRef)(),
                             pBuffer,
                             BytesToRead,
                             (oslSocketMsgFlag)Flag);
}

/*****************************************************************************/
// send
/*****************************************************************************/
sal_Int32 OStreamSocket::send(const void* pBuffer,
                            sal_uInt32 BytesToSend,
                            TSocketMsgFlag Flag)
{
    if (m_pSendTimeout && ! isSendReady(m_pSendTimeout))
        return 0;

    VOS_ASSERT(m_pSockRef && (*m_pSockRef)());

    if ( ! ( m_pSockRef && (*m_pSockRef)() ) )
    {
        return -1;
    }

    return osl_sendSocket((*m_pSockRef)(),
                          pBuffer,
                          BytesToSend,
                          (oslSocketMsgFlag)Flag);
}

/*****************************************************************************/
// shutdown
/*****************************************************************************/
sal_Bool OStreamSocket::shutdown(TSocketDirection Direction)
{
    VOS_ASSERT(m_pSockRef && (*m_pSockRef)());

    if ( m_pSockRef && (*m_pSockRef)() )
    {
        return osl_shutdownSocket((*m_pSockRef)(), (oslSocketDirection)Direction);
    }

    return sal_False;
}



VOS_IMPLEMENT_CLASSINFO(VOS_CLASSNAME(OConnectorSocket, vos),
                        VOS_NAMESPACE(OConnectorSocket, vos),
                        VOS_NAMESPACE(OStreamSocket, vos), 0);



/*****************************************************************************/
// OConnectorSocket
/*****************************************************************************/
OConnectorSocket::OConnectorSocket(TAddrFamily Family,
                                   TProtocol   Protocol,
                                   TSocketType Type) :
    OStreamSocket(Family, Protocol, Type)
{
}

/*****************************************************************************/
// OConnectorSocket
/*****************************************************************************/
OConnectorSocket::OConnectorSocket(const OConnectorSocket& sock) :
    OStreamSocket(sock)
{
}

/*****************************************************************************/
// ~OConnectorSocket
/*****************************************************************************/
OConnectorSocket::~OConnectorSocket()
{
}

/*****************************************************************************/
// connect
/*****************************************************************************/
OSocket::TResult OConnectorSocket::connect(const OSocketAddr& Addr,
                                           const TimeValue* pTimeout)
{

    VOS_ASSERT(m_pSockRef && (*m_pSockRef)());

    if ( m_pSockRef && (*m_pSockRef)() )
    {
        return (TResult)osl_connectSocketTo((*m_pSockRef)(),
                                            (oslSocketAddr)Addr,
                                            pTimeout);
    }

    return TResult_Error;
}


VOS_IMPLEMENT_CLASSINFO(VOS_CLASSNAME(ODatagramSocket, vos),
                        VOS_NAMESPACE(ODatagramSocket, vos),
                        VOS_NAMESPACE(OSocket, vos), 0);


/*****************************************************************************/
// ODatagramSocket
/*****************************************************************************/
ODatagramSocket::ODatagramSocket(TAddrFamily Family,
                                 TProtocol   Protocol,
                                 TSocketType Type) :
    OSocket(Type, Family, Protocol)
{
}

/*****************************************************************************/
// ODatagramSocket
/*****************************************************************************/
ODatagramSocket::ODatagramSocket(const ODatagramSocket& sock) :
    OSocket(sock)
{
}

/*****************************************************************************/
// ~ODatagramSocket
/*****************************************************************************/
ODatagramSocket::~ODatagramSocket()
{
}


/*****************************************************************************/
// recvFrom
/*****************************************************************************/
sal_Int32 ODatagramSocket::recvFrom(void* pBuffer,
                                  sal_uInt32 BufferSize,
                                    OSocketAddr* pSenderAddr,
                                    TSocketMsgFlag Flag)
{

    if (m_pRecvTimeout && ! isRecvReady(m_pRecvTimeout))
        return 0;

    VOS_ASSERT(m_pSockRef && (*m_pSockRef)());

    if ( ! ( m_pSockRef && (*m_pSockRef)() ) )
    {
        return -1;
    }

    sal_Int32 BytesRead;

    if(pSenderAddr)
    {
        // we are interested in the senders address
        oslSocketAddr SenderAddr= osl_createEmptySocketAddr(osl_Socket_FamilyInet);

        BytesRead=
            osl_receiveFromSocket((*m_pSockRef)(),
                                   SenderAddr,
                                   pBuffer,
                                   BufferSize,
                                   (oslSocketMsgFlag)Flag);

        *pSenderAddr= SenderAddr;
    }
    else
    {
        // we don't want to know the senders address

        BytesRead=
            osl_receiveFromSocket((*m_pSockRef)(),
                                   0,
                                   pBuffer,
                                   BufferSize,
                                   (oslSocketMsgFlag)Flag);
    }

    return BytesRead;
}


/*****************************************************************************/
// sendTo
/*****************************************************************************/
sal_Int32 ODatagramSocket::sendTo(const OSocketAddr& ReceiverAddr,
                                const void* pBuffer,
                                sal_uInt32 BufferSize,
                                TSocketMsgFlag Flag)
{
    if (m_pSendTimeout && ! isSendReady(m_pSendTimeout))
        return 0;

    VOS_ASSERT(m_pSockRef && (*m_pSockRef)());

    if ( ( m_pSockRef && (*m_pSockRef)() ) )
    {

        return osl_sendToSocket((*m_pSockRef)(),
                                (oslSocketAddr)ReceiverAddr,
                                pBuffer,
                                BufferSize,
                                (oslSocketMsgFlag)Flag);
    }

    return -1;
}