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);
	}
Beispiel #2
0
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;
			}
		}
	}
Beispiel #5
0
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();
	}
}