Esempio n. 1
0
static int tcp_bind_finalize(uv_handle_t *handle)
{
	/* TCP_FASTOPEN enables 1 RTT connection resumptions. */
#ifdef TCP_FASTOPEN
# ifdef __linux__
	(void) set_tcp_option(handle, TCP_FASTOPEN, 16); /* Accepts queue length hint */
# else
	(void) set_tcp_option(handle, TCP_FASTOPEN, 1);  /* Accepts on/off */
# endif
#endif

	handle->data = NULL;
	return 0;
}
Esempio n. 2
0
static int _tcp_bind(uv_tcp_t *handle, struct sockaddr *addr, uv_connection_cb connection)
{
	unsigned flags = 0;
	if (addr->sa_family == AF_INET6) {
		flags |= UV_TCP_IPV6ONLY;
	}

	int ret = uv_tcp_bind(handle, addr, flags);
	if (ret != 0) {
		return ret;
	}

	/* TCP_DEFER_ACCEPT delays accepting connections until there is readable data. */
#ifdef TCP_DEFER_ACCEPT
	if (set_tcp_option((uv_handle_t *)handle, TCP_DEFER_ACCEPT, KR_CONN_RTT_MAX/1000) != 0) {
		kr_log_info("[ io ] tcp_bind (defer_accept): %s\n", strerror(errno));
	}
#endif

	ret = uv_listen((uv_stream_t *)handle, 16, connection);
	if (ret != 0) {
		return ret;
	}

	return tcp_bind_finalize((uv_handle_t *)handle);
}
Esempio n. 3
0
void eStreamClient::notifier(int what)
{
	if (!(what & eSocketNotifier::Read))
		return;

	ePtr<eStreamClient> ref = this;
	char buf[512];
	int len;
	if ((len = singleRead(streamFd, buf, sizeof(buf))) <= 0)
	{
		rsn->stop();
		stop();
		parent->connectionLost(this);
		return;
	}
	request.append(buf, len);
	if (running || (request.find('\n') == std::string::npos))
		return;

	if (request.substr(0, 5) == "GET /")
	{
		size_t pos;
		size_t posdur;
		if (eConfigManager::getConfigBoolValue("config.streaming.authentication"))
		{
			bool authenticated = false;
			if ((pos = request.find("Authorization: Basic ")) != std::string::npos)
			{
				std::string authentication, username, password;
				std::string hash = request.substr(pos + 21);
				pos = hash.find('\r');
				hash = hash.substr(0, pos);
				authentication = base64decode(hash);
				pos = authentication.find(':');
				if (pos != std::string::npos)
				{
					char *buffer = (char*)malloc(4096);
					if (buffer)
					{
						struct passwd pwd;
						struct passwd *pwdresult = NULL;
						std::string crypt;
						username = authentication.substr(0, pos);
						password = authentication.substr(pos + 1);
						getpwnam_r(username.c_str(), &pwd, buffer, 4096, &pwdresult);
						if (pwdresult)
						{
							struct crypt_data cryptdata;
							char *cryptresult = NULL;
							cryptdata.initialized = 0;
							crypt = pwd.pw_passwd;
							if (crypt == "*" || crypt == "x")
							{
								struct spwd spwd;
								struct spwd *spwdresult = NULL;
								getspnam_r(username.c_str(), &spwd, buffer, 4096, &spwdresult);
								if (spwdresult)
								{
									crypt = spwd.sp_pwdp;
								}
							}
							cryptresult = crypt_r(password.c_str(), crypt.c_str(), &cryptdata);
							authenticated = cryptresult && cryptresult == crypt;
						}
						free(buffer);
					}
				}
			}
			if (!authenticated)
			{
				const char *reply = "HTTP/1.0 401 Authorization Required\r\nWWW-Authenticate: Basic realm=\"streamserver\"\r\n\r\n";
				writeAll(streamFd, reply, strlen(reply));
				rsn->stop();
				parent->connectionLost(this);
				return;
			}
		}
		pos = request.find(' ', 5);
		if (pos != std::string::npos)
		{
			std::string serviceref = urlDecode(request.substr(5, pos - 5));
			if (!serviceref.empty())
			{
				const char *reply = "HTTP/1.0 200 OK\r\nConnection: Close\r\nContent-Type: video/mpeg\r\nServer: streamserver\r\n\r\n";
				writeAll(streamFd, reply, strlen(reply));
				/* We don't expect any incoming data, so set a tiny buffer */
				set_socket_option(streamFd, SO_RCVBUF, 1 * 1024);
				 /* We like 188k packets, so set the TCP window size to that */
				set_socket_option(streamFd, SO_SNDBUF, 188 * 1024);
				/* activate keepalive */
				set_socket_option(streamFd, SO_KEEPALIVE, 1);
				/* configure keepalive */
				set_tcp_option(streamFd, TCP_KEEPINTVL, 10); // every 10 seconds
				set_tcp_option(streamFd, TCP_KEEPIDLE, 1);	// after 1 second of idle
				set_tcp_option(streamFd, TCP_KEEPCNT, 2);	// drop connection after second miss
				/* also set 10 seconds data push timeout */
				set_tcp_option(streamFd, TCP_USER_TIMEOUT, 10 * 1000);

				if (serviceref.substr(0, 10) == "file?file=") /* convert openwebif stream reqeust back to serviceref */
					serviceref = "1:0:1:0:0:0:0:0:0:0:" + serviceref.substr(10);
				/* Strip session ID from URL if it exists, PLi streaming can not handle it */
				pos = serviceref.find("&sessionid=");
				if (pos != std::string::npos) {
					serviceref.erase(pos, std::string::npos);
				}
				pos = serviceref.find("?sessionid=");
				if (pos != std::string::npos) {
					serviceref.erase(pos, std::string::npos);
				}
				pos = serviceref.find('?');
				if (pos == std::string::npos)
				{
					eDebug("[eDVBServiceStream] stream ref: %s", serviceref.c_str());
					if (eDVBServiceStream::start(serviceref.c_str(), streamFd) >= 0)
					{
						running = true;
						m_serviceref = serviceref;
						m_useencoder = false;
					}
				}
				else
				{
					request = serviceref.substr(pos);
					serviceref = serviceref.substr(0, pos);
					pos = request.find("?bitrate=");
					posdur = request.find("?duration=");
					eDebug("[eDVBServiceStream] stream ref: %s", serviceref.c_str());
					if (posdur != std::string::npos)
					{
						if (eDVBServiceStream::start(serviceref.c_str(), streamFd) >= 0)
						{
							running = true;
							m_serviceref = serviceref;
							m_useencoder = false;
						}
						int timeout = 0;
						sscanf(request.substr(posdur).c_str(), "?duration=%d", &timeout);
						eDebug("[eDVBServiceStream] duration: %d seconds", timeout);
						if (timeout)
						{
							m_timeout->startLongTimer(timeout);
						}
					}
					else if (pos != std::string::npos)
					{
						/* we need to stream transcoded data */
						int bitrate = 1024 * 1024;
						int width = 720;
						int height = 576;
						int framerate = 25000;
						int interlaced = 0;
						int aspectratio = 0;
						sscanf(request.substr(pos).c_str(), "?bitrate=%d", &bitrate);
						pos = request.find("?width=");
						if (pos != std::string::npos)
							sscanf(request.substr(pos).c_str(), "?width=%d", &width);
						pos = request.find("?height=");
						if (pos != std::string::npos)
							sscanf(request.substr(pos).c_str(), "?height=%d", &height);
						pos = request.find("?framerate=");
						if (pos != std::string::npos)
							sscanf(request.substr(pos).c_str(), "?framerate=%d", &framerate);
						pos = request.find("?interlaced=");
						if (pos != std::string::npos)
							sscanf(request.substr(pos).c_str(), "?interlaced=%d", &interlaced);
						pos = request.find("?aspectratio=");
						if (pos != std::string::npos)
							sscanf(request.substr(pos).c_str(), "?aspectratio=%d", &aspectratio);
						encoderFd = -1;
						if (eEncoder::getInstance())
							encoderFd = eEncoder::getInstance()->allocateEncoder(serviceref, bitrate, width, height, framerate, !!interlaced, aspectratio);
						if (encoderFd >= 0)
						{
							running = true;
							streamThread = new eDVBRecordStreamThread(188);
							if (streamThread)
							{
								streamThread->setTargetFD(streamFd);
								streamThread->start(encoderFd);
							}
							m_serviceref = serviceref;
							m_useencoder = true;
						}
					}
				}
			}
		}
	}
	if (!running)
	{
		const char *reply = "HTTP/1.0 400 Bad Request\r\n\r\n";
		writeAll(streamFd, reply, strlen(reply));
		rsn->stop();
		parent->connectionLost(this);
		return;
	}
	request.clear();
}