Пример #1
0
void TSockSys::OnAccept(uv_stream_t* ServerSockHnd, int Status) {
	// get socket handle
	uv_tcp_t* SockHnd = (uv_tcp_t*)ServerSockHnd;
	IAssert(SockSys.IsSockHnd((uint64)SockHnd));
	// get socket id
	const uint64 SockId = SockSys.SockHndToIdH.GetDat((uint64)SockHnd);
	IAssert(SockSys.IsSock(SockId));
	// get socket event
	const uint64 SockEventId = SockSys.SockHndToEventIdH.GetDat((uint64)SockHnd);
	PSockEvent SockEvent;
	if (SockSys.IsSockEvent(SockEventId)) {
		SockEvent = SockSys.GetSockEvent(SockEventId);
	} else {
		SaveToErrLog("SockSys.OnAccept: Socket without SockEvent");
		return;
	}
	// check for success status
	if (Status == 0) {
		// create a new socket for client connection
		PSock ClientSock = TSock::New(SockEvent);
		// get client socket handle
		uv_tcp_t* ClientSockHnd = SockSys.SockIdToHndH.GetDat(ClientSock->GetSockId());
		// accept request
		const int AcceptResCd = uv_accept(ServerSockHnd, (uv_stream_t*)ClientSockHnd);
		// start listening for incoming data
		if (AcceptResCd == 0) {
			int ReadStartResCd = uv_read_start((uv_stream_t*)ClientSockHnd, TSockSys::OnAlloc, TSockSys::OnRead);
			// execute callback
			if (ReadStartResCd == 0) {
				SockEvent->OnAccept(ClientSock->GetSockId(), ClientSock);
			} else {
				TStr ErrMsg = (Status == -1) ? 
					"SockSys.OnAccept: Error starting read " + SockSys.GetLastErr() : 
					"SockSys.OnAccept: Error starting read";
				SockEvent->OnError(SockId, ReadStartResCd, ErrMsg);
			}
		} else {
			// handle errors
			TStr ErrMsg = (Status == -1) ? 
				"SockSys.OnAccept: Error accepting new connection " + SockSys.GetLastErr() : 
				"SockSys.OnAccept: Error accepting new connection";
			SockEvent->OnError(SockId, AcceptResCd, ErrMsg);
		}
	} else {
		TStr ErrMsg = (Status == -1) ? 
			"SockSys.OnAccept: Error connecting" + SockSys.GetLastErr() : 
			"SockSys.OnAccept: Error connecting";
		SockEvent->OnError(SockId, Status, ErrMsg);
	}
}
Пример #2
0
void TSockSys::OnTimeOut(uv_timer_t* TimerHnd, int Status) {
	// check we have timer
	IAssert(SockSys.IsTimer((uint64)TimerHnd));
	// get socket id
	const uint64 SockId = SockSys.TimerHndToSockIdH.GetDat((uint64)TimerHnd);
	IAssert(SockSys.IsSock(SockId));
	// get socket event
	const uint64 SockHnd = (uint64)SockSys.SockIdToHndH.GetDat(SockId);
	const uint64 SockEventId = SockSys.SockHndToEventIdH.GetDat((uint64)SockHnd);
	PSockEvent SockEvent;
	if (SockSys.IsSockEvent(SockEventId)) {
		SockEvent = SockSys.GetSockEvent(SockEventId);
		// execute callback
		if (Status == 0) {
			SockEvent->OnTimeOut(SockId);
		} else {
			TStr ErrMsg = (Status == -1) ? 
				"SockSys.OnTimeOut: " + SockSys.GetLastErr() : 
				"SockSys.OnTimeOut: Error in socket timeout";
			SockEvent->OnError(SockId, Status, ErrMsg);
		}
	} else {
		SaveToErrLog("SockSys.OnTimeOut: Socket without SockEvent");
	}
	// cleanup
	uv_close((uv_handle_t*)TimerHnd, NULL);
	// remove shortcuts
	SockSys.SockIdToTimerHndH.DelKey(SockId);
	SockSys.TimerHndToSockIdH.DelKey((uint64)TimerHnd);
}
Пример #3
0
void TSockSys::Connect(const uint64& SockId, const PSockHost& SockHost, const int& PortN) {
	// make sure it's a valid socket
	IAssert(IsSock(SockId));
	uv_tcp_t* SockHnd = SockIdToHndH.GetDat(SockId);
	// make sure we got a valid socket host
	IAssert(SockHost->IsOk());
	// get connection handle
	uv_connect_t* ConnectHnd = (uv_connect_t*)malloc(sizeof(uv_connect_t));
	// special handling for v4 and v6
	int ResCd = 0;
	if (SockHost->IsIpv4()) {
		// get address
		struct sockaddr_in Addr = uv_ip4_addr(SockHost->GetIpNum().CStr(), PortN);
		// establish connection
		ResCd = uv_tcp_connect(ConnectHnd, SockHnd, Addr, TSockSys::OnConnect);
	} else if (SockHost->IsIpv6()) {
		// get address
		struct sockaddr_in6 Addr = uv_ip6_addr(SockHost->GetIpNum().CStr(), PortN);
		// establish connection
		ResCd = uv_tcp_connect6(ConnectHnd, SockHnd, Addr, TSockSys::OnConnect);
	}
	// check for errors
	if (ResCd != 0) {
		// cleanup first
		free(SockHnd);
		// and throw exception
		throw TExcept::New("SockSys.Connect: Error establishing socket connection: " + SockSys.GetLastErr());
	}
}
Пример #4
0
void TSockSys::OnWrite(uv_write_t *WriteHnd, int Status) {
	// cast to our write request object to get access to buffer
	uv_write_req_t* _WriteHnd = (uv_write_req_t*)WriteHnd;
	// get socket handle
	uv_tcp_t* SockHnd = (uv_tcp_t*)WriteHnd->handle;
	IAssert(SockSys.IsSockHnd((uint64)SockHnd));
	// free buffer and write handle
	free(_WriteHnd->Buffer.base);
	free(_WriteHnd);
	// get socket id
	const uint64 SockId = SockSys.SockHndToIdH.GetDat((uint64)SockHnd);
	IAssert(SockSys.IsSock(SockId));
	// get socket event
	const uint64 SockEventId = SockSys.SockHndToEventIdH.GetDat((uint64)SockHnd);
	PSockEvent SockEvent;
	if (SockSys.IsSockEvent(SockEventId)) {
		SockEvent = SockSys.GetSockEvent(SockEventId);
	} else {
		SaveToErrLog("SockSys.OnWrite: Socket without SockEvent");
		return;
	}
	// execute callback
	if (Status == 0) {
		SockEvent->OnWrite(SockId);
	} else {
		TStr ErrMsg = (Status == -1) ? 
			"SockSys.OnWrite: " + SockSys.GetLastErr() : 
			"SockSys.OnWrite: Error writing to socket";
		SockEvent->OnError(SockId, Status, ErrMsg);
	}
}
Пример #5
0
void TSockSys::OnGetHost(uv_getaddrinfo_t* RequestHnd, int Status, struct addrinfo* AddrInfo) {
	// get SockHost
	PSockHost SockHost;
	if (SockSys.HndToSockHostH.IsKey((uint64)RequestHnd)) {
		SockHost = SockSys.HndToSockHostH.GetDat((uint64)RequestHnd);
		SockSys.HndToSockHostH.DelKey((uint64)RequestHnd);
	} else {
		free(RequestHnd); uv_freeaddrinfo(AddrInfo);
		SaveToErrLog("SockSys.OnGetHost: unkown RequestId");
		return;
	}
	// get SockEvent
	PSockEvent SockEvent;
	if (SockHost->IsSockEvent()) {
		SockEvent = SockHost->GetSockEvent();
	} else {
		free(RequestHnd); uv_freeaddrinfo(AddrInfo);
		SaveToErrLog("SockSys.OnGetHost: SockHost without SockEvent");
		return;
	}
	// parse results
	if (Status == 0) {
		SockHost->Status = shsOk;
		// temporary buffer for storing IPs
		char _addr[64] = {'\0'}; 
		// iterate over all the resolved IPs
		struct addrinfo* AddrInfoIter = AddrInfo;
		while (AddrInfoIter != NULL) {
			//if (AddrInfoIter->ai_family 
			//AF_INET6
			// get IP as string
			if (AddrInfoIter->ai_family == AF_INET) {
				uv_ip4_name((struct sockaddr_in*)AddrInfoIter->ai_addr, _addr, sizeof(_addr));
			} else if (AddrInfoIter->ai_family == AF_INET6) {
				uv_ip6_name((struct sockaddr_in6*)AddrInfoIter->ai_addr, _addr, sizeof(_addr));
			}
			TStr IpNum(_addr);
			// add to SockHost
			SockHost->AddIpNum(IpNum);
			// go to the next IP on the list
			AddrInfoIter = AddrInfoIter->ai_next;
		}
	} else if (Status == -1) {
		// something went wrong
		SockHost->Status = shsError;
		SockHost->ErrMsg = "SockSys.OnGetHost: " + SockSys.GetLastErr();
	} else {
		// unkown status
		SockHost->Status = shsError;
		SockHost->ErrMsg = TStr::Fmt("SockSys.OnGetHost: unkown status %d", Status);
	}
	// clean up
	free(RequestHnd); uv_freeaddrinfo(AddrInfo);
	// callback
	SockEvent->OnGetHost(SockHost);
}
Пример #6
0
void TSockSys::OnConnect(uv_connect_t* ConnectHnd, int Status) {
	// get socket handle
	uv_tcp_t* SockHnd = (uv_tcp_t*)ConnectHnd->handle;
	IAssert(SockSys.IsSockHnd((uint64)SockHnd));
	// cleanup
	free(ConnectHnd);
	// get socket id
	const uint64 SockId = SockSys.SockHndToIdH.GetDat((uint64)SockHnd);
	IAssert(SockSys.IsSock(SockId));
	// get socket event
	const uint64 SockEventId = SockSys.SockHndToEventIdH.GetDat((uint64)SockHnd);
	PSockEvent SockEvent;
	if (SockSys.IsSockEvent(SockEventId)) {
		SockEvent = SockSys.GetSockEvent(SockEventId);
	} else {
		SaveToErrLog("SockSys.OnConnect: Socket without SockEvent");
		return;
	}
	// execute callback
	if (Status == 0) {
		SockEvent->OnConnect(SockId);
	} else {
		TStr ErrMsg = (Status == -1) ? 
			"SockSys.OnConnect: " + SockSys.GetLastErr() : 
			"SockSys.OnConnect: Error connecting";
		SockEvent->OnError(SockId, Status, ErrMsg);
		return;
	}
	// start listening for incoming data
	int ResCd = uv_read_start((uv_stream_t*)SockHnd, TSockSys::OnAlloc, TSockSys::OnRead);
	// check for errors
	if (ResCd != 0) {
		TStr ErrMsg = (Status == -1) ? 
			"SockSys.OnConnect: " + SockSys.GetLastErr() : 
			"SockSys.OnConnect: Error establishing read callbacks";
		SockEvent->OnError(SockId, ResCd, ErrMsg);
	}
}
Пример #7
0
void TSockSys::Listen(const uint64& SockId, const int& PortN, const bool& IPv6P) {
	// make sure it's a valid socket
	IAssert(IsSock(SockId));
	uv_tcp_t* SockHnd = SockIdToHndH.GetDat(SockId);
	// special handling for v4 and v6 when binding
	if (!IPv6P) {
		// get address
		struct sockaddr_in Addr = uv_ip4_addr("0.0.0.0", PortN);
		// bind socket to port
		const int BindResCd = uv_tcp_bind(SockHnd, Addr);
		EAssertR(BindResCd == 0, "SockSys.Listen: Error bidning socket to port: " + SockSys.GetLastErr());
	} else {
		// get address
		struct sockaddr_in6 Addr = uv_ip6_addr("::", PortN);
		// bind socket to port
		const int BindResCd = uv_tcp_bind6(SockHnd, Addr);
		EAssertR(BindResCd == 0, "SockSys.Listen: Error bidning socket to port: " + SockSys.GetLastErr());
	}
	// make sure we have backlog of at least 128
	const int BacklogQueue = (SOMAXCONN < 128) ? 128 : SOMAXCONN;
	// enable callbacks
	const int ListenResCd = uv_listen((uv_stream_t*)SockHnd, BacklogQueue, TSockSys::OnAccept);
	EAssertR(ListenResCd == 0, "SockSys.Listen: Error setting listener on socket: " + SockSys.GetLastErr());
}
Пример #8
0
void TSockSys::OnRead(uv_stream_t* SockHnd, ssize_t BufferLen, uv_buf_t Buffer) {
	//TODO: check if we need to close _SockHnd
	//uv_tcp_t* _SockHnd = (uv_tcp_t*)SockHnd;
	// get socket handle
	IAssert(SockSys.IsSockHnd((uint64)SockHnd));
	// get socket id
	const uint64 SockId = SockSys.SockHndToIdH.GetDat((uint64)SockHnd);
	IAssert(SockSys.IsSock(SockId));
	// get socket event
	const uint64 SockEventId = SockSys.SockHndToEventIdH.GetDat((uint64)SockHnd);
	PSockEvent SockEvent;
	if (SockSys.IsSockEvent(SockEventId)) {
		SockEvent = SockSys.GetSockEvent(SockEventId);
	} else {
		// cleanup (using delete as it was created in OnAlloc with new)
		delete[] Buffer.base;
		SaveToErrLog("SockSys.OnRead: Socket without SockEvent");
		return;
	}
	// execute callback
	if (BufferLen > 0) {
		// we got data, move the ownership of buffer to TMIn
		PSIn SIn = TMIn::New(Buffer.base, (int)BufferLen, true);
		// send
		SockEvent->OnRead(SockId, SIn);		
	} else {
		uv_err_code Status = uv_last_error(SockSys.Loop).code;
		// no data, might be error or end of stream
		if (Status == UV_EOF) {
			// no more data, close the socket handle
			SockEvent->OnReadEof(SockId);
			SockSys.DelIfSockTimer(SockId);
		} else if (Status == UV_EAGAIN) {
     		// we'll wait
        } else {
			// error
			TStr ErrMsg = "SockSys.OnRead: " + SockSys.GetLastErr();
			SockEvent->OnError(SockId, Status, ErrMsg);
		}
		// cleanup (using delete as it was created in OnAlloc with new)
		delete[] Buffer.base;
	}
}
Пример #9
0
TStr TSockSys::GetLocalIpNum(const uint64& SockId) {
	// make sure it's a valid socket
	IAssert(IsSock(SockId));
	uv_tcp_t* SockHnd = SockIdToHndH.GetDat(SockId);
	// get peer IP
	struct sockaddr SockName;
	int NameLen = sizeof(SockName);
	const int ResCd = uv_tcp_getsockname(SockHnd, &SockName, &NameLen);
	EAssertR(ResCd == 0, "SockSys.GetLocalIpNum: " + SockSys.GetLastErr());
	// decode IP
	char SockIpNum[64];
	if (SockName.sa_family == AF_INET) {
		uv_ip4_name((sockaddr_in*)&SockName, SockIpNum, sizeof(SockIpNum));
	} else if (SockName.sa_family == AF_INET6) {
		uv_ip6_name((sockaddr_in6*)&SockName, SockIpNum, sizeof(SockIpNum));
	} else {
		throw TExcept::New("SockSys.GetLocalIpNum: unkown address family");
	}
	// return
	return TStr(SockIpNum);
}
Пример #10
0
void TSockSys::Send(const uint64& SockId, const PSIn& SIn) {
	// make sure it's a valid socket
	IAssert(IsSock(SockId));
	uv_tcp_t* SockHnd = SockIdToHndH.GetDat(SockId);
	// create write request
	uv_write_req_t* WriteHnd = (uv_write_req_t*)malloc(sizeof(uv_write_req_t));
	// copy the data in the buffer
	WriteHnd->Buffer.len = SIn->Len(); //TODO: handle cases when SIn doesn't have known Len()
	WriteHnd->Buffer.base = (char*)malloc(WriteHnd->Buffer.len);
	SIn->GetBf(WriteHnd->Buffer.base, WriteHnd->Buffer.len);
	// execute the request
	int ResCd = uv_write((uv_write_t*)WriteHnd, (uv_stream_t*)SockHnd, &WriteHnd->Buffer, 1, OnWrite);
	// check for errors
	if (ResCd != 0) {
		// cleanup first
		free(WriteHnd->Buffer.base);
		free(WriteHnd);
		// and throw exception
		throw TExcept::New("SockSys.Send: Error sending data: " + SockSys.GetLastErr());
	}
}