MediaSinkNet::MediaSinkNet(string pTarget, Requirements *pTransportRequirements, enum MediaSinkType pType, bool pRtpActivated):
    MediaSink(pType), RTP()
{
    BasicInit(pTarget, 0, pType, pRtpActivated);
    mGAPIUsed = true;

    // get target port
    unsigned int tTargetPort = 0;
    RequirementTargetPort *tRequPort = (RequirementTargetPort*)pTransportRequirements->get(RequirementTargetPort::type());
    if (tRequPort != NULL)
    {
        tTargetPort = tRequPort->getPort();

    }else
    {
        LOG(LOG_WARN, "No target port given within requirement set, falling back to port 0");
        tTargetPort = 0;
    }
    mTargetPort = tTargetPort;

    // get target host
    mTargetHost = pTarget;

    // get transport type
    mStreamedTransport = pTransportRequirements->contains(pTransportRequirements->contains(RequirementTransmitStream::type()));
    enum TransportType tTransportType = (mStreamedTransport ? SOCKET_TCP : (pTransportRequirements->contains(RequirementTransmitBitErrors::type()) ? SOCKET_UDP_LITE : SOCKET_UDP));
    if (mStreamedTransport)
    	mStreamFragmentCopyBuffer = (char*)malloc(MEDIA_SOURCE_MEM_FRAGMENT_BUFFER_SIZE);

    // call GAPI
    if (mTargetHost != "")
    {
        LOG(LOG_VERBOSE, "Remote media sink at: %s<%d>%s", mTargetHost.c_str(), tTargetPort, mRtpActivated ? "(RTP)" : "");

        // finally associate to the target server/service
        Name tName(pTarget);
        mGAPIDataSocket = GAPI.connect(&tName, pTransportRequirements); //new Socket(IS_IPV6_ADDRESS(pTargetHost) ? SOCKET_IPv6 : SOCKET_IPv4, pSocketType);
    }

    mMediaId = CreateId(mTargetHost, toString(mTargetPort), tTransportType, pRtpActivated);
    AssignStreamName("NET-OUT: " + mMediaId);
}
///////////////////////////////////////////////////////////////////////////////
//HINT: lossless transmission is not implemented by using TCP but by rely on a reaction by the network
SocketBinding::SocketBinding(std::string pLocalName, Requirements *pRequirements)
{
    bool tFoundTransport = false;
    unsigned int tLocalPort = 0;
    //TODO: parse pLocalName and bind to a defined local IP address
    RequirementTargetPort *tRequPort = (RequirementTargetPort*)pRequirements->get(RequirementTargetPort::type());
    if (tRequPort != NULL)
    {
        tLocalPort = tRequPort->getPort();

    }else
    {
        LOG(LOG_WARN, "No target port given within requirement set, falling back to port 0");
        tLocalPort = 0;
    }
    mIsClosed = true;
    mConnection = NULL;


    /* network requirements */
    bool tIPv6 = IS_IPV6_ADDRESS(pLocalName);

    /* transport requirements */
    if ((pRequirements->contains(RequirementTransmitChunks::type())) && (pRequirements->contains(RequirementTransmitStream::type())))
    {
        LOG(LOG_ERROR, "Detected requirement conflict between \"Req:Chunks\" and \"Req:Stream\"");
    }

    bool tTcp = (((!pRequirements->contains(RequirementTransmitChunks::type())) &&
                (pRequirements->contains(RequirementTransmitStream::type()))));

    bool tUdp = ((pRequirements->contains(RequirementTransmitChunks::type())) &&
                (!pRequirements->contains(RequirementTransmitStream::type())));

    bool tUdpLite = ((pRequirements->contains(RequirementTransmitChunks::type())) &&
                    (!pRequirements->contains(RequirementTransmitStream::type())) &&
                    (pRequirements->contains(RequirementTransmitBitErrors::type())));

    if (tTcp)
    {
        mSocket = Socket::CreateServerSocket(tIPv6 ? SOCKET_IPv6 : SOCKET_IPv4, SOCKET_TCP, tLocalPort);
        tFoundTransport = true;
    }


    if (tUdp)
    {
        if(!tFoundTransport)
        {
            mSocket = Socket::CreateServerSocket(tIPv6 ? SOCKET_IPv6 : SOCKET_IPv4, tUdpLite ? SOCKET_UDP_LITE : SOCKET_UDP, tLocalPort);
            tFoundTransport = true;
        }else
        {
            LOG(LOG_ERROR, "Ambiguous requirements");
        }
    }

    if(tFoundTransport)
    {
        if (mSocket != NULL)
        {
            // per default we set receive/send buffer of 2 MB
            mSocket->SetReceiveBufferSize(2 * 1024 * 1024);
            mSocket->SetSendBufferSize(2 * 1024 * 1024);

            mIsClosed = false;

            /* QoS requirements and additional transport requirements */
            changeRequirements(pRequirements);

            LOG(LOG_VERBOSE, "New IP binding at %s and requirements %s created", getName()->toString().c_str(), mRequirements.getDescription().c_str());
        }else
            LOG(LOG_ERROR, "Returned Berkeley socket is invalid");
    }else
    {
        LOG(LOG_ERROR, "Haven't found correct mapping from application requirements to transport protocol");
    }
}
ChannelConnection::ChannelConnection(Scenario *pScenario, std::string pTarget, Requirements *pRequirements)
{
    if (pScenario == NULL)
        LOG(LOG_ERROR, "Scenario is invalid");

    bool tFoundTransport = false;
    mCep = NULL;

    mBlockingMode = true;
    mPeerNode = pTarget;
    RequirementTargetPort *tRequPort = (RequirementTargetPort*)pRequirements->get(RequirementTargetPort::type());
    if (tRequPort != NULL)
    {
        mPeerPort = tRequPort->getPort();

    }else
    {
        LOG(LOG_WARN, "No target port given within requirement set, falling back to port 0");
        mPeerPort = 0;
    }
    mIsClosed = true;

    /* transport requirements */
    if ((pRequirements->contains(RequirementTransmitChunks::type())) && (pRequirements->contains(RequirementTransmitStream::type())))
    {
        LOG(LOG_ERROR, "Detected requirement conflict between \"Req:Chunks\" and \"Req:Waterfall\"");
    }

    bool tTcp = (((!pRequirements->contains(RequirementTransmitChunks::type())) &&
                (pRequirements->contains(RequirementTransmitStream::type()))));

    bool tUdp = ((pRequirements->contains(RequirementTransmitChunks::type())) &&
                (!pRequirements->contains(RequirementTransmitStream::type())));

    bool tUdpLite = ((pRequirements->contains(RequirementTransmitChunks::type())) &&
                    (!pRequirements->contains(RequirementTransmitStream::type())) &&
                    (pRequirements->contains(RequirementTransmitBitErrors::type())));

    if (tTcp)
    {
        mCep = pScenario->AddClientCep(SOCKET_TCP, Name(mPeerNode), mPeerPort);
        tFoundTransport = true;
    }

    if (tUdp)
    {
        if(!tFoundTransport)
        {
            mCep = pScenario->AddClientCep(tUdpLite ? SOCKET_UDP_LITE : SOCKET_UDP, Name(mPeerNode), mPeerPort);
            tFoundTransport = true;
        }else
            LOG(LOG_ERROR, "Ambiguous requirements");
    }

    if (mCep != NULL)
        mIsClosed = false;
    else
        LOG(LOG_ERROR, "CEP object invalid");

    if(!tFoundTransport)
    {
        LOG(LOG_ERROR, "Haven't found correct mapping from application requirements to transport protocol");
    }

    /* QoS requirements and additional transport requirements */
    changeRequirements(pRequirements);

    if (mCep != NULL)
        LOG(LOG_VERBOSE, "New simulation association with target %s and requirements %s created", getRemoteName()->toString().c_str(), mRequirements.getDescription().c_str());
}