void UnixStreamSocket::SendBinary(const uint8_t* ns_payload, size_t ns_payload_len) { if (this->closed) return; size_t ns_num_len; size_t ns_len; if (ns_payload_len > MESSAGE_MAX_SIZE) { MS_ERROR_STD("mesage too big"); return; } if (ns_payload_len == 0) { ns_num_len = 1; UnixStreamSocket::writeBuffer[0] = '0'; UnixStreamSocket::writeBuffer[1] = ':'; UnixStreamSocket::writeBuffer[2] = ','; } else { ns_num_len = (size_t)std::ceil(std::log10((double)ns_payload_len + 1)); std::sprintf((char*)UnixStreamSocket::writeBuffer, "%zu:", ns_payload_len); std::memcpy(UnixStreamSocket::writeBuffer + ns_num_len + 1, ns_payload, ns_payload_len); UnixStreamSocket::writeBuffer[ns_num_len + ns_payload_len + 1] = ','; } ns_len = ns_num_len + ns_payload_len + 2; Write(UnixStreamSocket::writeBuffer, ns_len); }
void Loop::onChannelUnixStreamSocketRemotelyClosed(Channel::UnixStreamSocket* socket) { MS_TRACE_STD(); // When mediasoup Node process ends it sends a SIGTERM to us so we close this // pipe and then exit. // If the pipe is remotely closed it means that mediasoup Node process // abruptly died (SIGKILL?) so we must die. MS_ERROR_STD("Channel remotely closed, killing myself"); this->channel = nullptr; Close(); }
void UnixStreamSocket::Send(Json::Value &msg) { if (this->closed) return; // MS_TRACE_STD(); std::ostringstream stream; std::string ns_payload; size_t ns_payload_len; size_t ns_num_len; size_t ns_len; this->jsonWriter->write(msg, &stream); ns_payload = stream.str(); ns_payload_len = ns_payload.length(); if (ns_payload_len > MESSAGE_MAX_SIZE) { MS_ERROR_STD("mesage too big"); return; } if (ns_payload_len == 0) { ns_num_len = 1; UnixStreamSocket::writeBuffer[0] = '0'; UnixStreamSocket::writeBuffer[1] = ':'; UnixStreamSocket::writeBuffer[2] = ','; } else { ns_num_len = (size_t)std::ceil(std::log10((double)ns_payload_len + 1)); std::sprintf((char*)UnixStreamSocket::writeBuffer, "%zu:", ns_payload_len); std::memcpy(UnixStreamSocket::writeBuffer + ns_num_len + 1, ns_payload.c_str(), ns_payload_len); UnixStreamSocket::writeBuffer[ns_num_len + ns_payload_len + 1] = ','; } ns_len = ns_num_len + ns_payload_len + 2; Write(UnixStreamSocket::writeBuffer, ns_len); }
void UnixStreamSocket::userOnUnixStreamRead() { MS_TRACE_STD(); // Be ready to parse more than a single message in a single TCP chunk. while (true) { if (IsClosing()) return; size_t read_len = this->bufferDataLen - this->msgStart; char* json_start = nullptr; size_t json_len; int ns_ret = netstring_read((char*)(this->buffer + this->msgStart), read_len, &json_start, &json_len); if (ns_ret != 0) { switch (ns_ret) { case NETSTRING_ERROR_TOO_SHORT: // MS_DEBUG_STD("received netstring is too short, need more data"); // Check if the buffer is full. if (this->bufferDataLen == this->bufferSize) { // First case: the incomplete message does not begin at position 0 of // the buffer, so move the incomplete message to the position 0. if (this->msgStart != 0) { // MS_DEBUG_STD("no more space in the buffer, moving parsed bytes to the beginning of the buffer and waiting for more data"); std::memmove(this->buffer, this->buffer + this->msgStart, read_len); this->msgStart = 0; this->bufferDataLen = read_len; } // Second case: the incomplete message begins at position 0 of the buffer. // The message is too big, so discard it. else { MS_ERROR_STD("no more space in the buffer for the unfinished message being parsed, discarding it"); this->msgStart = 0; this->bufferDataLen = 0; } } // Otherwise the buffer is not full, just wait. // Exit the parsing loop. return; case NETSTRING_ERROR_TOO_LONG: MS_ERROR_STD("NETSTRING_ERROR_TOO_LONG"); break; case NETSTRING_ERROR_NO_COLON: MS_ERROR_STD("NETSTRING_ERROR_NO_COLON"); break; case NETSTRING_ERROR_NO_COMMA: MS_ERROR_STD("NETSTRING_ERROR_NO_COMMA"); break; case NETSTRING_ERROR_LEADING_ZERO: MS_ERROR_STD("NETSTRING_ERROR_LEADING_ZERO"); break; case NETSTRING_ERROR_NO_LENGTH: MS_ERROR_STD("NETSTRING_ERROR_NO_LENGTH"); break; } // Error, so reset and exit the parsing loop. this->msgStart = 0; this->bufferDataLen = 0; return; } // If here it means that json_start points to the beginning of a JSON string // with json_len bytes length, so recalculate read_len. read_len = (const uint8_t*)json_start - (this->buffer + this->msgStart) + json_len + 1; Json::Value json; std::string json_parse_error; if (this->jsonReader->parse((const char*)json_start, (const char*)json_start + json_len, &json, &json_parse_error)) { Channel::Request* request = nullptr; try { request = new Channel::Request(this, json); } catch (const MediaSoupError &error) { MS_ERROR_STD("discarding wrong Channel request"); } if (request) { // Notify the listener. this->listener->onChannelRequest(this, request); // Delete the Request. delete request; } } else { MS_ERROR_STD("JSON parsing error: %s", json_parse_error.c_str()); } // If there is no more space available in the buffer and that is because // the latest parsed message filled it, then empty the full buffer. if ((this->msgStart + read_len) == this->bufferSize) { // MS_DEBUG_STD("no more space in the buffer, emptying the buffer data"); this->msgStart = 0; this->bufferDataLen = 0; } // If there is still space in the buffer, set the beginning of the next // parsing to the next position after the parsed message. else { this->msgStart += read_len; } // If there is more data in the buffer after the parsed message // then parse again. Otherwise break here and wait for more data. if (this->bufferDataLen > this->msgStart) { // MS_DEBUG_STD("there is more data after the parsed message, continue parsing"); continue; } else { break; } } }
int main(int argc, char* argv[]) { // Ensure we are called by our Node library. if (argc == 1 || !std::getenv("MEDIASOUP_CHANNEL_FD")) { std::cerr << "ERROR: you don't seem to be my real father" << std::endl; std::_Exit(EXIT_FAILURE); } std::string id = std::string(argv[1]); int channelFd = std::stoi(std::getenv("MEDIASOUP_CHANNEL_FD")); // Initialize libuv stuff (we need it for the Channel). DepLibUV::ClassInit(); // Set the Channel socket (this will be handled and deleted by the Loop). Channel::UnixStreamSocket* channel = new Channel::UnixStreamSocket(channelFd); // Initialize the Logger. Logger::Init(id, channel); // Setup the configuration. try { Settings::SetConfiguration(argc, argv); } catch (const MediaSoupError &error) { MS_ERROR("configuration error: %s", error.what()); exitWithError(); } // Print the effective configuration. Settings::PrintConfiguration(); MS_DEBUG("starting " MS_PROCESS_NAME " [pid:%ld]", (long)getpid()); #if defined(MS_LITTLE_ENDIAN) MS_DEBUG("detected Little-Endian CPU"); #elif defined(MS_BIG_ENDIAN) MS_DEBUG("detected Big-Endian CPU"); #endif #if defined(INTPTR_MAX) && defined(INT32_MAX) && (INTPTR_MAX == INT32_MAX) MS_DEBUG("detected 32 bits architecture"); #elif defined(INTPTR_MAX) && defined(INT64_MAX) && (INTPTR_MAX == INT64_MAX) MS_DEBUG("detected 64 bits architecture"); #else MS_WARN("cannot determine whether the architecture is 32 or 64 bits"); #endif try { init(); // Run the Loop. Loop loop(channel); destroy(); MS_DEBUG_STD("success exit"); exitSuccess(); } catch (const MediaSoupError &error) { destroy(); MS_ERROR_STD("failure exit: %s", error.what()); exitWithError(); } }