void AudioCapture::attach(const PacketDelegateBase& delegate) { PacketSignal::attach(delegate); TraceLS(this) << "Added Delegate: " << refCount() << endl; if (refCount() == 1) start(); }
void TCPConnectionPair::onPeerConnectError(void* sender, const Error& error) { TraceLS(this) << "Peer Connect request error: " << error.message << endl; assert(sender == &peer); allocation.sendPeerConnectResponse(this, false); // The TCPConnectionPair will be deleted on next call to onConnectionClosed }
SSLSocket::SSLSocket(SSLContext::Ptr context, SSLSession::Ptr session, uv::Loop* loop) : TCPSocket(loop), _context(context), _session(session), _sslAdapter(this) { TraceLS(this) << "Create" << endl; }
SSLAdapter::~SSLAdapter() { TraceLS(this) << "Destroy" << endl; if (_ssl) { SSL_free(_ssl); _ssl = nullptr; } }
void WebSocketAdapter::handleClientResponse(const MutableBuffer& buffer) { TraceLS(this) << "Client response: " << buffer.size() << endl; http::Parser parser(&_response); if (!parser.parse(bufferCast<char *>(buffer), buffer.size())) { throw std::runtime_error("WebSocket error: Cannot parse response: Incomplete HTTP message"); } // TODO: Handle resending request for authentication // Should we implement some king of callback for this? // Parse and check the response if (framer.checkHandshakeResponse(_response)) { TraceLS(this) << "Handshake success" << endl; SocketAdapter::onSocketConnect(); } }
void AudioCapture::close() { TraceLS(this) << "Closing" << endl; try { Mutex::ScopedLock lock(_mutex); _opened = false; if (_audio.isStreamOpen()) _audio.closeStream(); TraceLS(this) << "Closing: OK" << endl; } catch (RtAudioError& e) { setError("Cannot close audio capture: " + e.getMessage()); } catch (...) { setError("Cannot close audio capture."); } }
WebSocketAdapter::WebSocketAdapter(const net::Socket::Ptr& socket, ws::Mode mode, http::Request& request, http::Response& response) : SocketAdapter(socket.get()), socket(socket), framer(mode), _request(request), _response(response) { TraceLS(this) << "Create" << endl; //setSendAdapter(socket.get()); socket->addReceiver(this); }
void SSLSocket::onRead(const char* data, std::size_t len) { TraceLS(this) << "On SSL read: " << len << endl; // SSL encrypted data is sent to the SSL conetext _sslAdapter.addIncomingData(data, len); _sslAdapter.flush(); }
SSLAdapter::SSLAdapter(net::SSLSocket* socket) : _socket(socket), _ssl(nullptr), _readBIO(nullptr), _writeBIO(nullptr) { TraceLS(this) << "Create" << endl; }
TCPConnectionPair::TCPConnectionPair(TCPAllocation& allocation) : allocation(allocation), client(nullptr), peer(nullptr), earlyPeerData(0), connectionID(util::randomNumber()), isDataConnection(false) { while (!allocation.pairs().add(connectionID, this, false)) { connectionID = util::randomNumber(); } TraceLS(this) << "Create: " << connectionID << endl; }
void TCPSocket::connect(const net::Address& peerAddress) { TraceLS(this) << "Connecting to " << peerAddress << endl; init(); auto req = new uv_connect_t; req->data = this; int r = uv_tcp_connect(req, ptr<uv_tcp_t>(), peerAddress.addr(), internal::onConnect); if (r) setAndThrowError("TCP connect failed", r); }
std::size_t WebSocketFramer::writeFrame(const char* data, std::size_t len, int flags, BitWriter& frame) { assert(flags == ws::SendFlags::Text || flags == ws::SendFlags::Binary); assert(frame.position() == 0); //assert(frame.limit() >= std::size_t(len + MAX_HEADER_LENGTH)); frame.putU8(static_cast<UInt8>(flags)); UInt8 lenByte(0); if (_maskPayload) { lenByte |= FRAME_FLAG_MASK; } if (len < 126) { lenByte |= static_cast<UInt8>(len); frame.putU8(lenByte); } else if (len < 65536) { lenByte |= 126; frame.putU8(lenByte); frame.putU16(static_cast<UInt16>(len)); } else { lenByte |= 127; frame.putU8(lenByte); frame.putU64(static_cast<UInt16>(len)); } if (_maskPayload) { auto mask = _rnd.next(); auto m = reinterpret_cast<const char*>(&mask); auto b = reinterpret_cast<const char*>(data); frame.put(m, 4); //auto p = frame.current(); for (unsigned i = 0; i < len; i++) { //p[i] = b[i] ^ m[i % 4]; frame.putU8(b[i] ^ m[i % 4]); } } else { //memcpy(frame.current(), data, len); // offset? frame.put(data, len); } // Update frame length to include payload plus header //frame.skip(len); #if 0 TraceLS(this) << "Write frame: " << "\n\tinputLength: " << len << "\n\tframePosition: " << frame.position() << "\n\tframeLimit: " << frame.limit() << "\n\tframeAvailable: " << frame.available() << endl; #endif return frame.position(); }
void TCPSocket::onRead(const char* data, std::size_t len) { TraceLS(this) << "On read: " << len << endl; // Note: The const_cast here is relatively safe since the given // data pointer is the underlying _buffer.data() pointer, but // a better way should be devised. onRecv(mutableBuffer(const_cast<char*>(data), len)); }
void TCPSocket::onAcceptConnection(uv_stream_t*, int status) { if (status == 0) { TraceLS(this) << "On accept connection" << endl; acceptConnection(); } else ErrorLS(this) << "Accept connection failed" << endl; }
SSLSocket::SSLSocket(uv::Loop* loop) : TCPSocket(loop), // TODO: Using client context, should assert no bind()/listen() on this socket _context(SSLManager::instance().defaultClientContext()), _session(nullptr), _sslAdapter(this) { TraceLS(this) << "Create" << endl; }
void WebSocketAdapter::onSocketConnect() { TraceLS(this) << "On connect" << endl; // Send the WS handshake request // The Connect signal will be sent after the // handshake is complete sendClientRequest(); }
void SSLAdapter::init(SSL* ssl) { TraceLS(this) << "Init: " << ssl << endl; assert(_socket); //assert(_socket->initialized()); _ssl = ssl; _readBIO = BIO_new(BIO_s_mem()); _writeBIO = BIO_new(BIO_s_mem()); SSL_set_bio(_ssl, _readBIO, _writeBIO); }
void AudioCapture::stop() { TraceLS(this) << "Stopping" << endl; if (running()) { try { Mutex::ScopedLock lock(_mutex); TraceLS(this) << "Stopping: Before" << endl; _audio.stopStream(); TraceLS(this) << "Stopping: OK" << endl; } catch (RtAudioError& e) { setError("Cannot stop audio capture: " + e.getMessage()); } catch (...) { setError("Cannot stop audio capture."); } } }
void AudioCapture::start() { TraceLS(this) << "Starting" << endl; if (!running()) { try { Mutex::ScopedLock lock(_mutex); _audio.startStream(); _error = ""; TraceLS(this) << "Starting: OK" << endl; } catch (RtAudioError& e) { setError("Cannot start audio capture: " + e.getMessage()); } catch (...) { setError("Cannot start audio capture."); } } }
bool SSLSocket::shutdown() { TraceLS(this) << "Shutdown" << endl; try { // Try to gracefully shutdown the SSL connection _sslAdapter.shutdown(); } catch (...) {} return TCPSocket::shutdown(); }
void TCPConnectionPair::setClientSocket(const net::TCPSocket::Ptr& socket) { TraceLS(this) << "Set client socket: " << connectionID << ": " << socket->peerAddress() << endl; //<< ": " << socket./*base().*/refCount() assert(client == nullptr); //assert(socket./*base().*/refCount() == 2); client = socket; client->Close += sdelegate(this, &TCPConnectionPair::onConnectionClosed); net::setServerSocketBufSize<uv_tcp_t>(*socket.get(), SERVER_SOCK_BUF_SIZE); // TODO: make option }
void TCPSocket::acceptConnection() { // Create the shared socket pointer; // if it is not handled it will be destroyed. // TODO: Allow accepted sockets to use different event loops. auto socket = net::makeSocket<net::TCPSocket>(loop()); //std::make_shared<net::TCPSocket>(this->loop()); TraceLS(this) << "Accept connection: " << socket->ptr() << endl; uv_accept(ptr<uv_stream_t>(), socket->ptr<uv_stream_t>()); // uv_accept should always work socket->readStart(); AcceptConnection.emit(Socket::self(), socket); }
int AudioCapture::audioCallback(void* /* outputBuffer */, void* inputBuffer, unsigned int nBufferFrames, double streamTime, RtAudioStreamStatus status, void* data) { AudioCapture* self = (AudioCapture*)data; AudioPacket packet; if (status) ErrorL << "Stream over/underflow detected" << endl; assert(inputBuffer); if (inputBuffer == nullptr) { ErrorL << "Input buffer is nullptr." << endl; return 2; } { Mutex::ScopedLock lock(self->_mutex); int size = 2; RtAudioFormat format = self->_format; // 8-bit signed integer. if (format == RTAUDIO_SINT8) size = 1; // 16-bit signed integer. else if (format == RTAUDIO_SINT16) size = 2; // Lower 3 bytes of 32-bit signed integer. else if (format == RTAUDIO_SINT24) size = 4; // 32-bit signed integer. else if (format == RTAUDIO_SINT32) size = 4; // Normalized between plus/minus 1.0. else if (format == RTAUDIO_FLOAT32) size = 4; // Normalized between plus/minus 1.0. else if (format == RTAUDIO_FLOAT64) size = 8; else assert(0 && "unknown audio capture format"); packet.setData((char*)inputBuffer, nBufferFrames * self->_channels * size); packet.time = streamTime; } // TraceL << "Captured audio packet: " // << "\n\tPacket Ptr: " << inputBuffer // << "\n\tPacket Size: " << packet.size() // << "\n\tStream Time: " << packet.time // << endl; TraceLS(self) << "Emitting: " << packet.time << std::endl; self->emit(packet); return 0; }
void WebSocketAdapter::sendClientRequest() { framer.createHandshakeRequest(_request); std::ostringstream oss; _request.write(oss); TraceLS(this) << "Client request: " << oss.str() << endl; assert(socket); /*socket->*/SocketAdapter::send(oss.str().c_str(), oss.str().length()); }
void SSLAdapter::shutdown() { TraceLS(this) << "Shutdown" << endl; if (_ssl) { TraceLS(this) << "Shutdown SSL" << endl; // Don't shut down the socket more than once. int shutdownState = SSL_get_shutdown(_ssl); bool shutdownSent = (shutdownState & SSL_SENT_SHUTDOWN) == SSL_SENT_SHUTDOWN; if (!shutdownSent) { // A proper clean shutdown would require us to // retry the shutdown if we get a zero return // value, until SSL_shutdown() returns 1. // However, this will lead to problems with // most web browsers, so we just set the shutdown // flag by calling SSL_shutdown() once and be // done with it. int rc = SSL_shutdown(_ssl); if (rc < 0) handleError(rc); } } }
void TCPSocket::init() { if (ptr()) return; TraceLS(this) << "Init" << endl; auto tcp = new uv_tcp_t; tcp->data = this; _ptr = reinterpret_cast<uv_handle_t*>(tcp); _closed = false; _error.reset(); int r = uv_tcp_init(loop(), tcp); if (r) setUVError("Cannot initialize TCP socket", r); }
bool TCPConnectionPair::makeDataConnection() { TraceLS(this) << "Make data connection: " << connectionID << endl; if (!peer || !client) return false; peer->Recv += sdelegate(this, &TCPConnectionPair::onPeerDataReceived); client->Recv += sdelegate(this, &TCPConnectionPair::onClientDataReceived); // Relase and unbind the client socket from the server. // The client socket instance, events and data will be // managed by the TCPConnectionPair from now on. allocation.server().releaseTCPSocket(client.get()); // Send early data from peer to client if (earlyPeerData.size()) { TraceLS(this) << "Flushing early media: " << earlyPeerData.size() << endl; client->send(earlyPeerData.data(), earlyPeerData.size()); earlyPeerData.clear(); } return (isDataConnection = true); }
void TCPConnectionPair::onClientDataReceived(void*, const MutableBuffer& buffer, const net::Address& peerAddress) { TraceLS(this) << "Client => Peer: " << buffer.size() << endl; //assert(packet.buffer.position() == 0); //if (packet.size() < 300) // TraceLS(this) << "Client => Peer: " << packet.buffer << endl; if (peer) { allocation.updateUsage(buffer.size()); if (allocation.deleted()) return; peer->send(bufferCast<char*>(buffer), buffer.size()); } }
void TCPSocket::onConnect(uv_connect_t* handle, int status) { TraceLS(this) << "On connect" << endl; // Error handled by static callback proxy if (status == 0) { if (readStart()) onSocketConnect(); } else { setUVError("Connection failed", status); //ErrorLS(this) << "Connection failed: " << error().message << endl; } delete handle; }
void TCPConnectionPair::setPeerSocket(const net::TCPSocket::Ptr& socket) { TraceLS(this) << "Set peer socket: " << connectionID << ": " << socket->peerAddress() << endl; //<< ": " << socket./*base().*/refCount() assert(peer == nullptr); //assert(socket./*base().*/refCount() == 1); peer = socket; peer->Close += sdelegate(this, &TCPConnectionPair::onConnectionClosed); // Receive and buffer early media from peer peer->Recv += sdelegate(this, &TCPConnectionPair::onPeerDataReceived); net::setServerSocketBufSize<uv_tcp_t>(*socket.get(), SERVER_SOCK_BUF_SIZE); // TODO: make option }