Exemple #1
0
int TCPSocket::send(const char* data, std::size_t len, const net::Address& /* peerAddress */, int /* flags */) 
{
    //assert(len <= net::MAX_TCP_PACKET_SIZE); // libuv handles this for us
    
    TraceS(this) << "Send: " << len << endl;    
    assert(Thread::currentID() == tid());
    
#if 0
    if (len < 300)
        TraceS(this) << "Send: " << len << ": " << std::string(data, len) << endl;
    else {
        std::string str(data, len);
        TraceS(this) << "Send: START: " << len << ": " << str.substr(0, 100) << endl;
        TraceS(this) << "Send: END: " << len << ": " << str.substr(str.length() - 100, str.length()) << endl;
    }
#endif

    if (!Stream::write(data, len)) {
        WarnL << "Send error" << endl;    
        return -1;
    }

    // R is -1 on error, otherwise return len
    // TODO: Return native error code?
    return len;
}
Exemple #2
0
bool AudioEncoder::encode(/*const */ std::uint8_t* samples,
                          const int numSamples, const std::int64_t pts)
{
    TraceS(this) << "Encoding audio packet: " << numSamples << endl;

    // Resample input data or add it to the buffer directly
    if (resampler) {
        if (!resampler->resample((std::uint8_t**)&samples, numSamples)) {
            // The resampler may buffer frames
            TraceS(this) << "Samples buffered by resampler" << endl;
            return false;
        }

        TraceS(this) << "Resampled audio packet: " << numSamples << " <=> "
                     << resampler->outNumSamples << endl;

        // Add the converted input samples to the FIFO buffer.
        fifo.write((void**)resampler->outSamples, resampler->outNumSamples);
    } else {
        // Add the input samples to the FIFO buffer.
        fifo.write((void**)&samples, numSamples);
    }

    // Set a timestamp value on the frame to be encoded if given.
    if (pts != AV_NOPTS_VALUE) {
        frame->pts = pts;
    }

    return flushBuffer(this) > 0;
}
void ClientConnection::onSocketConnect()
{
    TraceS(this) << "On connect" << endl;

    // Set the connection to active
    _active = true;

    // Emit the connect signal so raw connections like
    // websockets can kick off the data flow
    Connect.emit(this);

    // Start the outgoing send stream if there are
    // any queued packets or adapters attached
    // startInputStream();
    // startOutputStream();

    // Flush queued packets
    if (!_outgoingBuffer.empty()) {
        for (const auto & packet : _outgoingBuffer) {
            Outgoing.write(packet.c_str(), packet.length());
        }
        _outgoingBuffer.clear();
    }

    // Send the outgoing HTTP header if it hasn't already been sent.
    // Note the first call to socket().send() will flush headers.
    // Note if there are stream adapters we wait for the stream to push
    // through any custom headers. See ChunkedAdapter::emitHeader
    if (Outgoing.numAdapters() == 0) {
        TraceS(this) << "On connect: Send header" << endl;
        sendHeader();
    }
}
Exemple #4
0
void SSLSocket::onConnect(uv_connect_t* handle, int status)
{
    TraceS(this) << "On connect" << endl;
    if (status) {
        setUVError("SSL connect error", status);
        return;
    }
    else
        readStart();

    SSL* ssl = SSL_new(_context->sslContext());

    // TODO: Automatic SSL session handling.
    // Maybe add a stored session to the network manager.
    if (_session)
        SSL_set_session(ssl, _session->sslSession());

    SSL_set_connect_state(ssl);
    SSL_do_handshake(ssl);

    _sslAdapter.init(ssl);
    _sslAdapter.flush();

    //emitConnect();
    onSocketConnect();
    TraceS(this) << "On connect: OK" << endl;
}
bool DeviceManager::getAudioDevices(bool input, std::vector<Device>& devs)
{
    devs.clear();

#if defined(ANDROID)
    // Under Android, we don't access the device file directly.
    // Arbitrary use 0 for the mic and 1 for the output.
    // These ids are used in MediaEngine::SetSoundDevices(in, out);
    // The strings are for human consumption.
    if (input) {
        devs.push_back(Device("audioin", "audiorecord", 0));
    } else {
        devs.push_back(Device("audioout", "audiotrack", 1));
    }
    return true;
#elif defined(HAVE_RTAUDIO)

    // Since we are using RtAudio for audio capture it's best to
    // use RtAudio to enumerate devices to ensure indexes match.
    RtAudio audio;

    // Determine the number of devices available
    auto ndevices = audio.getDeviceCount();
    TraceS(this) << "Get audio devices: " << ndevices << endl;

    // Scan through devices for various capabilities
    RtAudio::DeviceInfo info;
    for (unsigned i = 0; i <= ndevices; i++) {
        try {
            info = audio.getDeviceInfo(i);    // may throw RtAudioError

            TraceS(this) << "Device:"
                << "\n\tName: " << info.name
                << "\n\tOutput Channels: " << info.outputChannels
                << "\n\tInput Channels: " << info.inputChannels
                << "\n\tDuplex Channels: " << info.duplexChannels
                << "\n\tDefault Output: " << info.isDefaultOutput
                << "\n\tDefault Input: " << info.isDefaultInput
                << "\n\tProbed: " << info.probed
                << endl;

            if (info.probed == true && (
                (input && info.inputChannels > 0) ||
                (!input && info.outputChannels > 0))) {

                TraceS(this) << "Adding device: " << info.name << endl;
                Device dev((input ? "audioin" : "audioout"), i, info.name, "",
                    (input ? info.isDefaultInput : info.isDefaultOutput));
                devs.push_back(dev);
            }
        }
        catch (RtAudioError& e) {
            ErrorS(this) << "Cannot probe audio device: " << e.getMessage() << endl;
        }
    }

    return filterDevices(devs, kFilteredAudioDevicesName);
#endif
}
Exemple #6
0
SSLAdapter::~SSLAdapter()
{
    TraceS(this) << "Destroy" << endl;
    if (_ssl) {
        SSL_free(_ssl);
        _ssl = nullptr;
    }
    TraceS(this) << "Destroy: OK" << endl;
}
Exemple #7
0
void TCPConnectionPair::onPeerDataReceived(net::Socket&,
                                           const MutableBuffer& buffer,
                                           const net::Address& peerAddress)
{
    TraceS(this) << "Peer => Client: " << buffer.size() << endl;
    // assert(pkt.buffer.position() == 0);
    // if (pkt.buffer.available() < 300)
    //    TraceS(this) << "Peer => Client: " << pkt.buffer << endl;
    // auto socket = reinterpret_cast<net::Socket*>(sender);
    // char* buf = bufferCast<char*>(buf);

    // Buffer& buf = pkt.buffer;
    const char* buf = bufferCast<const char*>(buffer);
    std::size_t len = buffer.size();
    if (client) {

        allocation.updateUsage(len);
        if (allocation.deleted())
            return;

        // assert(buf.position() == 0);
        client->send(buf, len);
    }

    // Flash policy requests
    // TODO: Handle elsewhere? Bloody flash...
    else if (len == 23 && (strcmp(buf, "<policy-file-request/>") == 0)) {
        TraceS(this) << "Handle flash policy" << endl;
        std::string policy(
            "<?xml version=\"1.0\"?><cross-domain-policy><allow-access-from "
            "domain=\"*\" to-ports=\"*\" /></cross-domain-policy>");
        // assert(peer->get() == pkt.info->socket);
        peer->send(policy.c_str(), policy.length() + 1);
        peer->close();
    }

    // Buffer early media
    // TODO: Make buffer size server option
    else {
        std::size_t maxSize =
            allocation.server().options().earlyMediaBufferSize;
        DebugS(this) << "Buffering early data: " << len << endl;
        //#ifdef _DEBUG
        //        DebugS(this) << "Printing early data: " << std::string(buf,
        //        len) << endl;
        //#endif
        if (len > maxSize)
            WarnL << "Dropping early media: Oversize packet: " << len << endl;
        if (earlyPeerData.size() > maxSize)
            WarnL << "Dropping early media: Buffer at capacity >= " << maxSize
                  << endl;

        // earlyPeerData.append(static_cast<const char*>(pkt.data()), len);
        earlyPeerData.insert(earlyPeerData.end(), buf, buf + len);
    }
}
Exemple #8
0
void Thread::join()
{
    TraceS(this) << "Joining" << std::endl;
    assert(this->tid() != Thread::currentID());
    //assert(this->cancelled()); // probably should be cancelled, but depends on impl
    uv_thread_join(&_handle);    
    assert(!this->running());
    assert(!this->started());
    TraceS(this) << "Joining: OK" << std::endl;
}
Exemple #9
0
void PacketStream::resume()
{
    TraceS(this) << "Resume" << endl;
    if (!stateEquals(PacketStreamState::Paused)) {
        TraceS(this) << "Resume: Not paused" << endl;
        return;
    }

    setState(this, PacketStreamState::Active);
}
Connection::~Connection()
{
    TraceS(this) << "Destroy" << endl;
    replaceAdapter(nullptr);
    //assert(_closed);
    close(); // don't want pure virtual on onClose.
             // the shared pointer is being destroyed,
             // no need for close() anyway
    TraceS(this) << "Destroy: OK" << endl;
}
void Client::removeConnection(ClientConnection* conn)
{
    TraceS(this) << "Removing connection: " << conn << endl;
    for (auto it = _connections.begin(); it != _connections.end(); ++it) {
        if (conn == it->get()) {
            TraceS(this) << "Removed connection: " << conn << endl;
            _connections.erase(it);
            return;
        }
    }
    assert(0 && "unknown connection");
}
void Client::shutdown()
{
    TraceS(this) << "Shutdown" << endl;

    //_timer.stop();
    Shutdown.emit(this);

    //_connections.clear();
    auto conns = _connections;
    for (auto conn : conns) {
        TraceS(this) << "Shutdown: " << conn << endl;
        conn->close(); // close and remove via callback
    }
    assert(_connections.empty());
}
Exemple #13
0
void Roster::update(const json::Value& data, bool whiny)
{
    if (data.isObject() &&
        data.isMember("id") &&
        data.isMember("user") &&
        data.isMember("name") //&&
        //data.isMember("type")
        ) {
        TraceS(this) << "Updating: " << json::stringify(data, true) << endl;
        std::string id = data["id"].asString();
        Peer* peer = get(id, false);
        if (!peer) {
            peer = new Peer(data);
            add(id, peer);
        } else
            static_cast<json::Value&>(*peer) = data;
    }
    else if (data.isArray()) {
        for (auto it = data.begin(); it != data.end(); it++) {
            update(*it, whiny);
        }
    }
    else {
        std::string error("Bad presence data: " + json::stringify(data));
        ErrorS(this) << error << endl;
        if (whiny)
            throw std::runtime_error(error);
    }
}
Exemple #14
0
void Connection::onSocketError(const scy::Error& error) 
{
    TraceS(this) << "On socket error" << endl;

    // Handle the socket error locally
    setError(error);
}
void Client::addConnection(ClientConnection::Ptr conn)
{
    TraceS(this) << "Adding connection: " << conn << endl;

    conn->Close += sdelegate(this, &Client::onConnectionClose, -1); // lowest priority
    _connections.push_back(conn);
}
UDPSocket::UDPSocket(uv::Loop* loop) :
    uv::Handle(loop), 
    _buffer(65536)
{
    TraceS(this) << "Create" << endl;
    init();
}
void ClientConnection::onHeaders()
{
    TraceS(this) << "On headers" << endl;
    IncomingProgress.total = _response.getContentLength();

    Headers.emit(this, _response);
}
Exemple #18
0
void TCPSocket::listen(int backlog) 
{
    TraceS(this) << "Listening" << endl;
    init();
    int r = uv_listen(ptr<uv_stream_t>(), backlog, internal::onAcceptConnection);
    if (r) setAndThrowError("TCP listen failed", r);
}
int ConnectionAdapter::send(const char* data, std::size_t len, int flags)
{
    TraceS(this) << "Send: " << len << endl;

    try {
        // Send headers on initial send
        if (_connection.shouldSendHeader()) {
            int res = _connection.sendHeader();

            // The initial packet may be empty to push the headers through
            if (len == 0)
                return res;
        }

        // Other packets should not be empty
        assert(len > 0);

        // Send body / chunk
        return SocketAdapter::send(data, len, flags);
    }
    catch (std::exception& exc) {
        ErrorS(this) << "Send error: " << exc.what() << endl;

        // Swallow the exception, the socket error will
        // cause the connection to close on next iteration.
    }

    return -1;
}
void Connection::onSocketClose()
{
    TraceS(this) << "On socket close" << endl;

    // Close the connection when the socket closes
    close();
}
void Connection::onClose()
{
    TraceS(this) << "On close" << endl;

        // assert(0);
    Close.emit(this);
}
void AsyncPacketQueue::onStreamStateChange(const PacketStreamState& state)
{
    TraceS(this) << "Stream state: " << state << endl;
    
    switch (state.id()) {
    case PacketStreamState::Active:
        break;
        
    case PacketStreamState::Stopped:
        break;

    case PacketStreamState::Error:
    case PacketStreamState::Closed:
        // Flush queued items, some protocols can't afford dropped packets
        flush();    
        assert(empty());
        cancel();
        _thread.join();
        break;

    //case PacketStreamState::Resetting:
    //case PacketStreamState::None:
    //case PacketStreamState::Stopping:
    }
}
Client::Client()
{
    TraceS(this) << "Create" << endl;

    //_timer.Timeout += sdelegate(this, &Client::onConnectionTimer);
    //_timer.start(5000);
}
Exemple #24
0
void PacketStream::close()
{

    if (stateEquals(PacketStreamState::None) ||
        stateEquals(PacketStreamState::Closed)) {
        // TraceS(this) << "Already closed" << endl;
        // assert(0);
        return;
    }

    // Stop the stream gracefully (if running)
    if (!stateEquals(PacketStreamState::Stopped) &&
        !stateEquals(PacketStreamState::Stopping))
        stop();

    TraceS(this) << "Closing" << endl;

    // Queue the Closed state
    setState(this, PacketStreamState::Closed);

    {
        // Lock the processor mutex to synchronize multi source streams
        std::lock_guard<std::mutex> guard(_procMutex);

        // Teardown the adapter delegate chain
        teardown();

        // Synchronize any pending states
        // This should be safe since the adapters won't be receiving
        // any more incoming packets after teardown.
        // This call is essential when using the event loop otherwise
        // failing to close some handles could result in deadlock.
        // See SyncQueue::cancel()
        synchronizeStates();

        // Clear and delete managed adapters
        // Note: Can't call this because if closeOnCleanup is true
        // we may be inside a queue loop which will be destroyed by
        // the call to reset()
        // reset();
    }

    // Send the Closed signal
    Close.emit(*this);

    TraceS(this) << "Close: OK" << endl;
}
Exemple #25
0
PacketStream::PacketStream(const std::string& name)
    : opaque(nullptr)
    , _name(name)
    , _autoStart(false)
    , _closeOnError(true)
{
    TraceS(this) << "Create" << endl;
}
Exemple #26
0
SSLAdapter::SSLAdapter(net::SSLSocket* socket)
    : _socket(socket)
    , _ssl(nullptr)
    , _readBIO(nullptr)
    , _writeBIO(nullptr)
{
    TraceS(this) << "Create" << endl;
}
Exemple #27
0
void SSLSocket::onRead(const char* data, std::size_t len)
{
    TraceS(this) << "On SSL read: " << len << endl;

    // SSL encrypted data is sent to the SSL conetext
    _sslAdapter.addIncomingData(data, len);
    _sslAdapter.flush();
}
void ConnectionAdapter::onParserChunk(const char* buf, std::size_t len)
{
    TraceS(this) << "On parser chunk: " << len << endl;

    // Dispatch the payload
    net::SocketAdapter::onSocketRecv(mutableBuffer(const_cast<char*>(buf), len),
        _connection.socket()->peerAddress());
}
void Connection::onSocketRecv(const MutableBuffer& buffer, const net::Address& peerAddress)
{
    TraceS(this) << "On socket recv" << endl;
    //_timeout.stop();

    // Handle payload data
    onPayload(buffer); //mutableBuffer(bufferCast<const char*>(buf)
}
Exemple #30
0
SSLSocket::SSLSocket(SSLContext::Ptr context, SSLSession::Ptr session, uv::Loop* loop) :
    TCPSocket(loop),
    _context(context),
    _session(session),
    _sslAdapter(this)
{
    TraceS(this) << "Create" << endl;
}