bool CSocket::DoPulse() { // Make sure the socket exists before taking action if (m_pSocket != ERR_INVALID_SOCKET) { // Wait for connect to complete before proceeding if (!m_bConnected) { struct timeval tv = { 0, 0 }; fd_set wfds; FD_ZERO(&wfds); FD_SET(m_pSocket, &wfds); // See if socket it writable int ret = select(m_pSocket+1, NULL, &wfds, NULL, &tv); if (ret == 0) return true; // Not writable yet if (ret == -1) return false; // select error } // Create a buffer for catching received data // (1 byte larger than receive limit, because another character has to be added) char chBuffer[SOCK_RECV_LIMIT + 1]; // Receive the data int iLength = recv(m_pSocket, chBuffer, SOCK_RECV_LIMIT, 0); // Check if there were any errors int iError = GetLastSocketError(); // Check if the socket just connected. If connection failed, return false if (!m_bConnected && (HandleConnection(iError) == ERR_CONNECT_FAILURE)) return false; // If connected, handle data processing if (m_bConnected) { // Process data if there is any if (iLength > 0) { // Add a NULL at the end of the data, or the data will appear corrupted chBuffer[iLength] = '\0'; TriggerEvent("onSockData",chBuffer); } else if (iError != ERR_NO_ERROR && iError != ERR_WOULD_BLOCK) { // An error has occured, so time to kill the socket m_bConnected = false; return false; } } } else // If the socket doesn't exist, well, error? return false; // If the call makes it up till here, it has been a huge success! Cake and true as a reward! return true; }
// if timeout occurs, nbytes=-1, nresult=1 // if socket error, nbyte=-1, nresult=-1 // if the other side has disconnected in either block mode or nonblock mode, nbytes=0, nresult=-1 void SocketRecv(HSocket hs, char* ptr, int nbytes, transresult_t& rt) { rt.nbytes = 0; rt.nresult = 0; if(!ptr|| nbytes<1) { return; } rt.nbytes = recv(hs, ptr, nbytes, BLOCKREADWRITE); if(rt.nbytes>0) { return; } else if(rt.nbytes==0) { rt.nresult=-1; } else { rt.nresult = GetLastSocketError(); rt.nresult = ETRYAGAIN(rt.nresult)? 1:-1; } }
// // if timeout occurs, nbytes=-1, nresult=1 // if socket error, nbyte=-1, nresult=-1 // if the other side has disconnected in either block mode or nonblock mode, nbytes=0, nresult=-1 // otherwise nbytes= the count of bytes sent , nresult=0 void SocketSend(HSocket hs, const char* ptr, int nbytes, transresult_t& rt) { rt.nbytes = 0; rt.nresult = 0; if(!ptr|| nbytes<1) { return; } //Linux: flag can be MSG_DONTWAIT, MSG_WAITALL, 使用MSG_WAITALL的时候, socket 必须是处于阻塞模式下,否则WAITALL不能起作用 rt.nbytes = send(hs, ptr, nbytes, BLOCKREADWRITE|SENDNOSIGNAL); if(rt.nbytes>0) { rt.nresult = (rt.nbytes == nbytes)?0:1; } else if(rt.nbytes==0) { rt.nresult=-1; } else { rt.nresult = GetLastSocketError(); rt.nresult = ETRYAGAIN(rt.nresult)? 1:-1; } }
void SocketTrySend(HSocket hs, const char* ptr, int nbytes, int milliseconds, transresult_t& rt) { rt.nbytes = 0; rt.nresult = 0; if(!ptr|| nbytes<1) { return; } int n; CMyTimeSpan start; while(1) { n = send(hs, ptr+rt.nbytes, nbytes, NONBLOCKREADWRITE|SENDNOSIGNAL); if(n>0) { rt.nbytes += n; nbytes -= n; if(rt.nbytes >= nbytes) { rt.nresult = 0; break; } } else if( n==0) { rt.nresult= -2; break; } else { n = GetLastSocketError(); if(ETRYAGAIN(n)) { // CLightThread::DiscardTimeSlice(); int dwSleep=20; std::this_thread::sleep_for(std::chrono::milliseconds(dwSleep*1000)); } else { rt.nresult = -1; break; } } if(start.GetSpaninMilliseconds() > (unsigned int)milliseconds) { rt.nresult= 1; break; } } }
bool ServerSocket::Connect( unsigned long a_nIpAddress, int a_nPort, int a_nTimeout ) { Disconnect(); struct sockaddr_in server; server.sin_family = AF_INET; server.sin_port = htons((short)a_nPort); server.sin_addr.s_addr = a_nIpAddress; SOCKET s = socket(AF_INET, SOCK_STREAM, 0); if (s == INVALID_SOCKET) return false; try { // non-blocking for connect u_long value = 1; int rc = ioctlsocket(s, FIONBIO, &value); if (rc != 0) throw rc; rc = connect(s, (struct sockaddr *) &server, sizeof(server)); if (rc != 0) { if (rc != SOCKET_ERROR || GetLastSocketError() != EWOULDBLOCK) throw rc; // non-blocking wait struct timeval timeout; timeout.tv_sec = a_nTimeout / 1000; timeout.tv_usec = (a_nTimeout % 1000) * 1000; fd_set wr; FD_ZERO(&wr); FD_SET(s, &wr); fd_set ex; FD_ZERO(&ex); FD_SET(s, &ex); rc = select(0, NULL, &wr, &ex, &timeout); if (rc == 0 || rc == SOCKET_ERROR || FD_ISSET(s, &ex)) throw rc; } // blocking value = 0; rc = ioctlsocket(s, FIONBIO, &value); if (rc != 0) throw rc; rc = setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (const char*) &a_nTimeout, sizeof(a_nTimeout)); if (rc != 0) throw rc; rc = setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (const char*) &a_nTimeout, sizeof(a_nTimeout)); if (rc != 0) throw rc; mSocket = s; return true; } catch (int) { closesocket(s); return false; } }
// if timeout occurs, nbytes=-1, nresult=1 // if socket error, nbyte=-1, nresult=-1 // if the other side has disconnected in either block mode or nonblock mode, nbytes=0, nresult=-1 void SocketTryRecv(HSocket hs, char* ptr, int nbytes, int milliseconds, transresult_t& rt) { rt.nbytes = 0; rt.nresult = 0; if(!ptr|| nbytes<1) { return; } if(milliseconds>2) { CMyTimeSpan start; while(1) { rt.nbytes = recv(hs, ptr, nbytes, NONBLOCKREADWRITE); if(rt.nbytes>0) { break; } else if(rt.nbytes==0) { rt.nresult = -1; break; } else { rt.nresult = GetLastSocketError(); if( ETRYAGAIN(rt.nresult)) { if(start.GetSpaninMilliseconds() > (unsigned int)milliseconds) { rt.nresult= 1; break; } //CLightThread::DiscardTimeSlice(); int dwSleep=20; std::this_thread::sleep_for(std::chrono::milliseconds(dwSleep*1000)); } else { rt.nresult = -1; break; } } } } else { SocketRecv(hs, ptr, nbytes, rt); } }
// // UDPsocket // int UDPsocket (void) { int s; // allocate a socket s = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); if ( !IsValidSocket( s ) ) { int err = GetLastSocketError(); I_Error( "can't create socket, error %d", err ); } return s; }
CSocket::CSocket(lua_State *luaVM, const string& strHost, const unsigned short& usPort) { // Prepare variables m_bConnected = false; m_strHost = strHost; m_usPort = usPort; m_pLuaVM = luaVM; m_pUserdata = NULL; m_pSocket = ERR_INVALID_SOCKET; // Prepare data for connection (cancel on failure) if (!ProcessTargetLocation(strHost, usPort)) return; // Create the socket, and put it in non-blocking mode m_pSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // Exit if the socket failed to create if (m_pSocket == ERR_INVALID_SOCKET) return; ms_iTotalOpenSocketCount++; // Set the socket to non-blocking mode SetNonBlocking(); // Make the socket connect if (connect(m_pSocket, (sockaddr*)&m_sSockAddr, sizeof(m_sSockAddr)) != ERR_CONNECT_SUCCESS) { // If the connection failed, check why int iError = GetLastSocketError(); // If the error is ERR_WOULD_BLOCK (meaning it's in progress) then ignore if (iError != ERR_CONNECT_IN_PROGRESS) { // Error, so unload the socket and exit the function CloseSocket(); return; } } // Create userdata, for identification m_pUserdata = lua_newuserdata(luaVM, 128); }
int EHSConnection::TrySend ( const char * ipMessage, size_t inLength, int inFlags ) { int iWouldBlockCount = 0; lp1: { int iCount = 0; UpdateLastActivity ( ); while( !m_poNetworkAbstraction->IsWritable(1000) && !m_poNetworkAbstraction->IsAtError(0) ) { iCount++; if ( iCount == 10 ) { break; } } } int ret = m_poNetworkAbstraction->Send ( ipMessage, inLength, inFlags ); if ( ret == SOCKET_ERROR ) { int err = GetLastSocketError (); if ( err == E_WOULDBLOCK ) { Sleep(20); iWouldBlockCount++; if ( iWouldBlockCount < 2 ) goto lp1; m_poNetworkAbstraction->Close(); } } else if ( ret != inLength ) { ipMessage += ret; inLength -= ret; Sleep(1); goto lp1; } return ret; }
// if timeout occurs, nbytes=-1, nresult=1 // if socket error, nbyte=-1, nresult=-1 // if the other side has disconnected in either block mode or nonblock mode, nbytes=0, nresult=-1 void SocketTryRecv(HSocket hs, char *ptr, int nbytes, int milliseconds, transresult_t &rt) { rt.nbytes = 0; rt.nresult = 0; if(!ptr|| nbytes<1) return; if(milliseconds>2) { CMyTimeSpan start; while(1) { rt.nbytes = recv(hs, ptr, nbytes, NONBLOCKREADWRITE); if(rt.nbytes>0) { break; } else if(rt.nbytes==0) { rt.nresult = -1; break; } else { rt.nresult = GetLastSocketError(); if( ETRYAGAIN(rt.nresult)) { if(start.GetSpaninMilliseconds()>milliseconds) { rt.nresult= 1; break;} CLightThread::DiscardTimeSlice(); } else { rt.nresult = -1; break; } } } } else { SocketRecv(hs, ptr, nbytes, rt); } }
// nbytes= the count of bytes sent // if timeout occurs, nresult=1 // if socket error, nresult=-1, // if the other side has disconnected in either block mode or nonblock mode, nresult=-2 void SocketTrySend(HSocket hs, const char *ptr, int nbytes, int milliseconds, transresult_t &rt) { rt.nbytes = 0; rt.nresult = 0; if(!ptr|| nbytes<1) return; int n; CMyTimeSpan start; while(1) { n = send(hs, ptr+rt.nbytes, nbytes, NONBLOCKREADWRITE|SENDNOSIGNAL); if(n>0) { rt.nbytes += n; nbytes -= n; if(rt.nbytes >= nbytes) { rt.nresult = 0; break; } } else if( n==0) { rt.nresult= -2; break; } else { n = GetLastSocketError(); if(ETRYAGAIN(n)) { CLightThread::DiscardTimeSlice(); } else { rt.nresult = -1; break; } } if(start.GetSpaninMilliseconds()>milliseconds) { rt.nresult= 1; break;} } }
int TcpSocketClient::WaitOnSocket(int32_t timeout, bool rd) { int ready = 0; int lastError = 0; fd_set fds; do { struct timeval tv = { 0 }; tv.tv_sec = timeout; FD_ZERO(&fds); FD_SET(socketHandle, &fds); fd_set* readFds = 0; fd_set* writeFds = 0; if (rd) readFds = &fds; else writeFds = &fds; ready = select(static_cast<int>((socketHandle) + 1), readFds, writeFds, NULL, (timeout == 0 ? NULL : &tv)); if (ready == SOCKET_ERROR) lastError = GetLastSocketError(); } while (ready == SOCKET_ERROR && IsSocketOperationInterrupted(lastError)); if (ready == SOCKET_ERROR) return -lastError; if (ready == 0) return WaitResult::TIMEOUT; return WaitResult::SUCCESS; }
void EHSServer::CheckClientSockets ( ) { MUTEX_LOCK ( m_oMutex ); // go through all the sockets from which we're still reading for ( EHSConnectionList::iterator i = m_oEHSConnectionList.begin ( ); i != m_oEHSConnectionList.end ( ); i++ ) { if ( m_oReadFds.IsSet( (*i)->GetNetworkAbstraction()->GetFd(), POLLIN ) ) { if ( MUTEX_TRY_LOCK ( (*i)->m_oConnectionMutex ) == false ) continue; EHS_TRACE ( "$$$$$ Got data on client connection\n" ); // prepare a buffer for the read static const int BYTES_TO_READ_AT_A_TIME = 10240; char psReadBuffer [ BYTES_TO_READ_AT_A_TIME + 1 ]; memset ( psReadBuffer, 0, BYTES_TO_READ_AT_A_TIME + 1 ); // do the actual read int nBytesReceived = (*i)->GetNetworkAbstraction ( )->Read ( psReadBuffer, BYTES_TO_READ_AT_A_TIME ); if ( nBytesReceived == SOCKET_ERROR ) { int err = GetLastSocketError (); if ( err == E_WOULDBLOCK ) { MUTEX_UNLOCK ( (*i)->m_oConnectionMutex ); continue; } } // if we received a disconnect if ( nBytesReceived <= 0 ) { // we're done reading and we received a disconnect (*i)->DoneReading ( true ); } // otherwise we got data else { // take the data we got and append to the connection's buffer EHSConnection::AddBufferResult nAddBufferResult = (*i)->AddBuffer ( psReadBuffer, nBytesReceived ); // if add buffer failed, don't read from this connection anymore if ( nAddBufferResult == EHSConnection::ADDBUFFER_INVALIDREQUEST || nAddBufferResult == EHSConnection::ADDBUFFER_TOOBIG ) { // done reading but did not receieve disconnect EHS_TRACE ( "Done reading because we got a bad request\n" ); (*i)->DoneReading ( false ); } // end error with AddBuffer } // end nBytesReceived MUTEX_UNLOCK ( (*i)->m_oConnectionMutex ); } // FD_ISSET } // for loop through connections MUTEX_UNLOCK ( m_oMutex ); }
// Fills the 'buffer' with maximum of 'count' bytes, explicitly from the remote QRBG Service. // Actual number of bytes copied into the buffer is returned. // Upon failure, exceptions are thrown. // Returns: count of bytes (received) copied into the supplied buffer. size_t QRBG::AcquireBytesFromService(byte* buffer, size_t count) throw(ConnectError, CommunicationError, ServiceDenied) { // connect to the service server, // propagate exception to the caller Connect(); // // prepare and send the request // // NOTE: we're using plain authentication. /* Client first (and last) packet: Size [B] Content -------------- -------------------------------------------------------- 1 operation, from OperationCodes enum if operation == GET_DATA_AUTH_PLAIN, then: 2 content size (= 1 + username_len + 1 + password_len + 4) 1 username_len (must be > 0 and <= 100) username_len username (NOT zero padded!) 1 password_len (must be > 0 and <= 100) password_len password in plain 8-bit ascii text (NOT zero padded!) 4 bytes of data requested Server first (and last) packet: Size [B] Content -------------- -------------------------------------------------------- 1 response, from ServerResponseCodes enum 1 response details - reason, from RefusalReasonCodes 4 data_len, bytes of data that follow data_len data */ // header structure looks like this: // struct tClientHeader { // uint8 eOperation; // MUST BE eOperation == GET_DATA_AUTH_PLAIN for struct remainder to hold // uint16 cbContentSize; // uint8 cbUsername; // char szUsername[cbUsername]; // uint8 cbPassword; // char szPassword[cbPassword]; // uint32 cbRequested; // }; // however, two issues obstruct direct structure usage: // 1) we don't know username/password length apriori // 2) we must convert all numeric values to network order (big endian) // so, we'll fill output buffer byte-by-byte... uint8 eOperation = GET_DATA_AUTH_PLAIN; uint8 cbUsername = static_cast<uint8>( strlen(szUsername) ); uint8 cbPassword = static_cast<uint8>( strlen(szPassword) ); uint32 cbRequested = static_cast<uint32>( count ); uint16 cbContentSize = sizeof(cbUsername) + cbUsername + sizeof(cbPassword) + cbPassword + sizeof(cbRequested); uint32 bytesToSend = sizeof(eOperation) + sizeof(cbContentSize) + cbContentSize; ASSERT(outBufferSize >= bytesToSend); byte* pRequestBuffer = outBuffer; *(uint8*)pRequestBuffer = eOperation, pRequestBuffer += sizeof(eOperation); *(uint16*)pRequestBuffer = htons(cbContentSize), pRequestBuffer += sizeof(cbContentSize); *(uint8*)pRequestBuffer = cbUsername, pRequestBuffer += sizeof(cbUsername); memcpy(pRequestBuffer, szUsername, cbUsername), pRequestBuffer += cbUsername; *(uint8*)pRequestBuffer = cbPassword, pRequestBuffer += sizeof(cbPassword); memcpy(pRequestBuffer, szPassword, cbPassword), pRequestBuffer += cbPassword; *(uint32*)pRequestBuffer = htonl(cbRequested), pRequestBuffer += sizeof(cbRequested); int ret = send(hSocket, (const char*)outBuffer, bytesToSend, 0); if (ret == -1) { // failed to send data request to the server Close(); throw CommunicationError(); } if (ret != bytesToSend) { // failed to send complete data request to the server Close(); throw CommunicationError(); } // // receive header (assuming GET_DATA_AUTH_PLAIN, as we requested) // // server response header structure looks like this: // struct tServerHeader { // uint8 response; // actually from enum ServerResponseCodes // uint8 reason; // actually from enum RefusalReasonCodes // uint32 cbDataLen; // should be equal to cbRequested, but we should not count on it! // }; // however, to avoid packing and memory aligning portability issues, // we'll read input buffer byte-by-byte... ServerResponseCodes eResponse; RefusalReasonCodes eReason; uint32 cbDataLen = 0; const uint32 bytesHeader = sizeof(uint8) + sizeof(uint8) + sizeof(uint32); byte header[bytesHeader]; uint32 bytesReceived = 0; uint32 bytesToReceiveTotal = bytesHeader; uint32 bytesToReceiveNow = 0; // receive header while ( (bytesToReceiveNow = bytesToReceiveTotal - bytesReceived) > 0 ) { int ret = recv(hSocket, (char*)(header + bytesReceived), bytesToReceiveNow, 0); if (ret != -1) { if (ret > 0) { // data received bytesReceived += ret; // parse the server response if (bytesReceived >= 2*sizeof(uint8)) { eResponse = (ServerResponseCodes) header[0]; eReason = (RefusalReasonCodes) header[1]; // process server response... if (eResponse != OK) { Close(); throw ServiceDenied(eResponse, eReason); } if (bytesReceived >= bytesToReceiveTotal) { cbDataLen = ntohl( *((u_long*)(header + 2*sizeof(uint8))) ); } } } else { // recv() returns 0 if connection was closed by server Close(); throw CommunicationError(); } } else { int nErr = GetLastSocketError(); if (nErr == EAGAIN) { // wait a little bit, and try again } else { // some socket(network) error occurred; // it doesn't matter what it is, declare failure! Close(); throw CommunicationError(); } } } // // receive data // bytesReceived = 0; bytesToReceiveTotal = cbDataLen; while ( (bytesToReceiveNow = bytesToReceiveTotal - bytesReceived) > 0 ) { // limit to maximal socket buffer size used bytesToReceiveNow = bytesToReceiveNow < INTERNAL_SOCKET_MAX_BUFFER ? bytesToReceiveNow : INTERNAL_SOCKET_MAX_BUFFER; int ret = recv(hSocket, (char*)(buffer + bytesReceived), bytesToReceiveNow, 0); if (ret != -1) { if (ret > 0) { // data received bytesReceived += ret; } else { // recv() returns 0 if connection was closed by server Close(); throw CommunicationError(); } } else { int nErr = GetLastSocketError(); if (nErr == EAGAIN) { // wait a little bit, and try again } else { // some socket(network) error occurred; // it doesn't matter what it is, declare failure! Close(); throw CommunicationError(); } } } Close(); // we succeeded. return bytesReceived; }