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); } }
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); }
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()); } }
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); } }
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); }
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); } }
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()); }
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; } }
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); }
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()); } }