unsigned long CIpSocket::Send( const void *x_pData, unsigned long x_uSize, unsigned long *x_puSent, unsigned long x_uFlags ) { // Initialize bytes sent if ( x_puSent ) *x_puSent = 0; // Must have a socket handle if ( !IsSocket() ) return 0; // Attempt to send the data setWouldBlock( 0 ); int nRet = v_send( (SOCKET)m_hSocket, x_pData, (int)x_uSize, (int)x_uFlags ); // Get the last error code m_uLastError = WSAGetLastError(); if ( WSAEWOULDBLOCK == m_uLastError ) m_uLastError = 0; m_uWrites++; m_lActivity++; // Check for error if ( SOCKET_ERROR == nRet || 0 > nRet ) { // Is the socket blocking? if ( !getWouldBlock() && m_uLastError ) { m_uConnectState |= eCsError; return 0; } // end if // Not an error m_uConnectState &= ~eCsError; // Number of bytes sent if ( x_puSent ) *x_puSent = 0; // no bytes sent return 0; } // end if // Save the number of bytes sent if ( x_puSent ) *x_puSent = nRet; return nRet; }
ssize_t ConnectedDescriptor::Send(const uint8_t *buffer, unsigned int size) { if (!ValidWriteDescriptor()) return 0; ssize_t bytes_sent; #ifdef _WIN32 if (WriteDescriptor().m_type == PIPE_DESCRIPTOR) { DWORD bytes_written = 0; if (!WriteFile(ToHandle(WriteDescriptor()), buffer, size, &bytes_written, NULL)) { OLA_WARN << "WriteFile() failed with " << GetLastError(); bytes_sent = -1; } else { bytes_sent = bytes_written; } } else if (WriteDescriptor().m_type == SOCKET_DESCRIPTOR) { bytes_sent = send(ToFD(WriteDescriptor()), reinterpret_cast<const char*>(buffer), size, 0); } else { OLA_WARN << "Send() called on unsupported descriptor type"; return 0; } #else // BSD Sockets #if HAVE_DECL_MSG_NOSIGNAL if (IsSocket()) { bytes_sent = send(WriteDescriptor(), buffer, size, MSG_NOSIGNAL); } else { #endif bytes_sent = write(WriteDescriptor(), buffer, size); #if HAVE_DECL_MSG_NOSIGNAL } #endif #endif if (bytes_sent < 0 || static_cast<unsigned int>(bytes_sent) != size) { OLA_INFO << "Failed to send on " << WriteDescriptor() << ": " << strerror(errno); } return bytes_sent; }
int CIpSocket::Accept( CIpSocket &x_is ) { // Punt if no socket if ( !IsSocket() ) return 0; // Lose any current connection there might be x_is.Destroy(); // Accept the connection sockaddr saAddr; socklen_t iAddr = sizeof( saAddr ); // Accept and encapsulate the socket int bSuccess = x_is.Attach( (t_SOCKET)tcULongToPtr( accept( tcPtrToULong( m_hSocket ), &saAddr, &iAddr ) ) ); if ( !bSuccess ) { m_uLastError = errno; if ( EAGAIN != m_uLastError ) m_uEventState |= eCloseEvent; else m_uEventState = 0; return 0; } // end if else m_uLastError = 0; // Grab the address CIpSocket_GetAddressInfo( &m_addrPeer, &saAddr ); // Capture all events x_is.EventSelect(); // Accepted m_uAccepts++; m_lActivity++; // Child is connecting x_is.m_uConnectState |= eCsConnecting; return 1; }
int CIpSocket::EventSelect( long x_lEvents ) { #if defined( HTM_NOSOCKET2 ) return 0; #else // Punt if no socket if ( !IsSocket() ) return 0; // Must have event handle if ( !IsEventHandle() ) CreateEventHandle(); return ( WSAEventSelect( (SOCKET)m_hSocket, (WSAEVENT)m_hSocketEvent, x_lEvents ) == 0 ); #endif }
int CIpSocket::Connect( const CIpAddress &x_rIpAddress ) { // Punt if not initialized if ( !IsInitialized() ) return 0; // Ensure we were passed a valid address if ( !x_rIpAddress.ValidateAddress() ) { Destroy(); return 0; } // Create socket if there is none if ( !IsSocket() && !Create() ) { m_uConnectState |= eCsError; Destroy(); return 0; } // end if // Save the address m_addrPeer = x_rIpAddress; SOCKADDR_IN si; memset( &si, 0, sizeof( si ) ); si.sin_family = m_uSocketFamily; CIpSocket_SetAddressInfo( &m_addrPeer, &si ); // Attempt to connect int nRet = connect( (SOCKET)m_hSocket, (PSOCKADDR)&si, sizeof( si ) ); // Save the last error code m_uLastError = WSAGetLastError(); if ( WSAEWOULDBLOCK == m_uLastError ) m_uLastError = 0, nRet = 0; // Check for error if ( nRet ) { m_uConnectState |= eCsError; return 0; } // end if // We're trying to connect m_lActivity++; m_uConnectState |= eCsConnecting; // Return the result return 1; }
int CIpSocket::Connect( const CIpAddress &x_rIpAddress ) { // Punt if not initialized if ( !IsInitialized() ) return 0; // Ensure we were passed a valid address if ( !x_rIpAddress.ValidateAddress() ) { Destroy(); return 0; } // Create socket if there is none if ( !IsSocket() && !Create() ) { m_uConnectState |= eCsError; Destroy(); return 0; } // end if // Save the address m_addrPeer = x_rIpAddress; sockaddr_in si; memset( &si, 0, sizeof( si ) ); si.sin_family = m_uSocketFamily; CIpSocket_SetAddressInfo( &m_addrPeer, &si ); // Attempt to connect int nRet = connect( tcPtrToULong( m_hSocket ), (sockaddr*)&si, sizeof( si ) ); m_uLastError = errno; // Check result if ( -1 == nRet && EINPROGRESS != m_uLastError ) { m_uConnectState |= eCsError; m_uLastError = errno; return 0; } // end if m_uLastError = 0; // We're trying to connect m_lActivity++; m_uConnectState |= eCsConnecting; return 1; }
int CIpSocket::Attach( t_SOCKET x_hSocket, int x_bFree ) { // Lose the old socket Destroy(); // Save socket handle m_hSocket = x_hSocket; // Should we free the socket? m_bFree = x_bFree; // Call on attach if ( !OnAttach() ) Destroy(); // How'd it go? return IsSocket(); }
BOOL CWinSocket::Listen(UINT uMaxConnections) {_STT(); // Punt if not initialized if ( !IsInitialized() ) { TRACE( "CWinSocket: Error - Call InitSockets()" ); return FALSE; } // Must have socket if ( !IsSocket() ) return FALSE; // Valid number of connections? if ( uMaxConnections == 0 ) return FALSE; // Start the socket listening int nRet = listen( m_hSocket, (int)uMaxConnections ); // Save the last error code m_uLastError = WSAGetLastError(); return nRet; }
bool ConnectedDescriptor::SetNoSigPipe(DescriptorHandle fd) { if (!IsSocket()) return true; #if HAVE_DECL_SO_NOSIGPIPE int sig_pipe_flag = 1; int ok = setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &sig_pipe_flag, sizeof(sig_pipe_flag)); if (ok == -1) { OLA_INFO << "Failed to disable SIGPIPE on " << fd << ": " << strerror(errno); return false; } #else (void) fd; #endif return true; }
int CIpSocket::EventSelect( long x_lEvents ) { #if defined( HTM_NOEPOLL ) return 0; #else // Punt if no socket if ( !IsSocket() ) return 0; // Enable non-blocking mode int flags = fcntl( tcPtrToULong( m_hSocket ), F_GETFL, 0 ); fcntl( tcPtrToULong( m_hSocket ), F_SETFL, flags | O_NONBLOCK ); // Must have event handle if ( !IsEventHandle() || !m_pEventObject ) CreateEventHandle(); // Clear events m_uEventState = 0; epoll_event ev; memset( &ev, 0, sizeof( ev ) ); ev.data.fd = tcPtrToULong( m_hSocket ); ev.events = EPOLLERR | FlagWinToNix( x_lEvents ); // Set the event masks int nRes = epoll_ctl( tcPtrToULong( m_hSocketEvent ), m_bEventsHooked ? EPOLL_CTL_MOD : EPOLL_CTL_ADD, tcPtrToULong( m_hSocket ), &ev ); if ( -1 == nRes ) { m_uLastError = errno; return 0; } // end if m_bEventsHooked = 1; return 1; #endif }
int CIpSocket::Listen( unsigned int x_uMaxConnections ) { // Punt if not initialized if ( !IsInitialized() ) return 0; // Must have socket if ( !IsSocket() ) { m_uConnectState |= eCsError; return 0; } // end if // Valid number of connections? if ( x_uMaxConnections == 0 ) x_uMaxConnections = 16; // x_uMaxConnections = SOMAXCONN; // Start the socket listening int nRet = listen( (SOCKET)m_hSocket, (int)( x_uMaxConnections ? x_uMaxConnections : SOMAXCONN ) ); // Save the last error code m_uLastError = WSAGetLastError(); if ( WSAEWOULDBLOCK == m_uLastError ) m_uLastError = 0, nRet = 0; // Error? if ( c_SocketError == (t_SOCKET)nRet ) { m_uConnectState |= eCsError; return 0; } // end if // We're trying to connect m_lActivity++; m_uConnectState |= eCsConnecting; // Return the result return 1; }
BOOL CWinSocket::Create( int af, int type, int protocol ) {_STT(); // Punt if not initialized if ( !IsInitialized() ) { TRACE( "CWinSocket: Error - Call InitSockets()" ); return FALSE; } // Close any open socket Destroy(); // Create a scocket m_hSocket = socket( af, type, protocol ); // Save the last error code m_uLastError = WSAGetLastError(); // Create the event handle CreateEventHandle(); // Capture all events EventSelect(); return IsSocket(); }
int CIpSocket::Accept( CIpSocket &x_is ) { // Punt if no socket if ( !IsSocket() ) return 0; // Lose any current connection there might be x_is.Destroy(); // Accept the connection SOCKADDR saAddr; int iAddr = sizeof( saAddr ); // Accept and encapsulate the socket BOOL bSuccess = x_is.Attach( (t_SOCKET)accept( (SOCKET)m_hSocket, &saAddr, &iAddr ) ); // Check for error if ( !bSuccess ) { m_uLastError = WSAGetLastError(); return 0; } // end if // Grab the address CIpSocket_GetAddressInfo( &m_addrPeer, &saAddr ); // Capture all events x_is.EventSelect(); m_uAccepts++; m_lActivity++; // Child is connecting x_is.m_lActivity++; x_is.m_uConnectState |= eCsConnecting; return 1; }
int CIpSocket::Bind( unsigned int x_uPort ) { // Punt if not initialized if ( !IsInitialized() ) return 0; // Create socket if there is none if ( !IsSocket() && !Create() ) { Destroy(); m_uConnectState |= eCsError; return 0; } // end if sockaddr_in sai; ZeroMemory( &sai, sizeof( sai ) ); sai.sin_family = PF_INET; sai.sin_port = htons( (WORD)x_uPort ); // Attempt to bind the socket int nRet = bind( (SOCKET)m_hSocket, (sockaddr*)&sai, sizeof( sockaddr_in ) ); // Save the last error code m_uLastError = WSAGetLastError(); if ( WSAEWOULDBLOCK == m_uLastError ) m_uLastError = 0, nRet = 0; // Grab the address CIpSocket_GetAddressInfo( &m_addrLocal, &sai ); if ( nRet ) { m_uConnectState |= eCsError; return 0; } // end if return 1; }
UINT CWinSocket::Recv(LPVOID pData, UINT uSize, UINT *puRead, UINT uFlags) { // Initialize bytes read if ( puRead ) *puRead = 0; // Must have a socket handle if ( !IsSocket() ) return FALSE; // Receive data from socket int nRet = recv( m_hSocket, (LPSTR)pData, (int)uSize, (int)uFlags ); // Get the last error code m_uLastError = WSAGetLastError(); // Check for closed socket if ( !nRet ) return SOCKET_ERROR; // Check for socket error if ( SOCKET_ERROR == nRet ) { // Is the socket blocking? if ( WSAEWOULDBLOCK != m_uLastError ) return SOCKET_ERROR; // All bytes read if ( puRead ) *puRead = uSize; return uSize; } // end if // Save the number of bytes read if ( puRead ) *puRead = nRet; return nRet; }
/* * Write data to this descriptor. * @param buffer the data to write * @param size the length of the data * @return the number of bytes sent */ ssize_t ConnectedDescriptor::Send(const uint8_t *buffer, unsigned int size) { if (!ValidWriteDescriptor()) return 0; ssize_t bytes_sent; #if HAVE_DECL_MSG_NOSIGNAL if (IsSocket()) bytes_sent = send(WriteDescriptor(), buffer, size, MSG_NOSIGNAL); else #endif #ifdef _WIN32 if (WriteDescriptor().m_type == HANDLE_DESCRIPTOR) { DWORD bytes_written = 0; if (!WriteFile(WriteDescriptor().m_handle.m_handle, buffer, size, &bytes_written, NULL)) { OLA_WARN << "WriteFile() failed with " << GetLastError(); bytes_sent = -1; } else { bytes_sent = bytes_written; } } else { bytes_sent = write(WriteDescriptor().m_handle.m_fd, buffer, size); } #else bytes_sent = write(WriteDescriptor(), buffer, size); #endif if (bytes_sent < 0 || static_cast<unsigned int>(bytes_sent) != size) OLA_INFO << "Failed to send on " << WriteDescriptor() << ": " << strerror(errno); return bytes_sent; }
BOOL CWinSocket::Bind(UINT uPort) {_STT(); // Punt if not initialized if ( !IsInitialized() ) { TRACE( "CWinSocket: Error - Call InitSockets()" ); return FALSE; } // Create socket if there is none if ( !IsSocket() && !Create() ) { Destroy(); return FALSE; } sockaddr_in sai; ZeroMemory( &sai, sizeof( sai ) ); sai.sin_family = PF_INET; sai.sin_port = htons( (WORD)uPort ); // Attempt to bind the socket int nRet = bind( m_hSocket, (sockaddr*)&sai, sizeof( sockaddr_in ) ); // Save the last error code m_uLastError = WSAGetLastError(); return !nRet; }
ssize_t ConnectedDescriptor::Send(IOQueue *ioqueue) { if (!ValidWriteDescriptor()) return 0; int iocnt; const struct IOVec *iov = ioqueue->AsIOVec(&iocnt); ssize_t bytes_sent = 0; #ifdef _WIN32 /* There is no scatter/gather functionality for generic descriptors on * Windows, so this is implemented as a write loop. Derived classes should * re-implement Send() using scatter/gather I/O where available. */ int bytes_written = 0; for (int io = 0; io < iocnt; ++io) { bytes_written = Send(reinterpret_cast<const uint8_t*>(iov[io].iov_base), iov[io].iov_len); if (bytes_written == 0) { OLA_INFO << "Failed to send on " << WriteDescriptor() << ": " << strerror(errno); bytes_sent = -1; break; } bytes_sent += bytes_written; } #else #if HAVE_DECL_MSG_NOSIGNAL if (IsSocket()) { struct msghdr message; memset(&message, 0, sizeof(message)); message.msg_name = NULL; message.msg_namelen = 0; message.msg_iov = reinterpret_cast<iovec*>(const_cast<IOVec*>(iov)); message.msg_iovlen = iocnt; bytes_sent = sendmsg(WriteDescriptor(), &message, MSG_NOSIGNAL); } else { #else { #endif bytes_sent = writev(WriteDescriptor(), reinterpret_cast<const struct iovec*>(iov), iocnt); } #endif ioqueue->FreeIOVec(iov); if (bytes_sent < 0) { OLA_INFO << "Failed to send on " << WriteDescriptor() << ": " << strerror(errno); } else { ioqueue->Pop(bytes_sent); } return bytes_sent; } int ConnectedDescriptor::Receive(uint8_t *buffer, unsigned int size, unsigned int &data_read) { // NOLINT int ret; uint8_t *data = buffer; data_read = 0; if (!ValidReadDescriptor()) return -1; while (data_read < size) { #ifdef _WIN32 if (ReadDescriptor().m_type == PIPE_DESCRIPTOR) { if (!ReadDescriptor().m_async_data_size) { OLA_WARN << "No async data buffer for descriptor " << ReadDescriptor(); return -1; } // Check if data was read by the async ReadFile() call DWORD async_data_size = *ReadDescriptor().m_async_data_size; if (async_data_size > 0) { DWORD size_to_copy = std::min(static_cast<DWORD>(size), async_data_size); memcpy(buffer, ReadDescriptor().m_async_data, size_to_copy); data_read = size_to_copy; if (async_data_size > size) { memmove(ReadDescriptor().m_async_data, &(ReadDescriptor().m_async_data[size_to_copy]), async_data_size - size_to_copy); } *ReadDescriptor().m_async_data_size -= size_to_copy; } return 0; } else if (ReadDescriptor().m_type == SOCKET_DESCRIPTOR) { ret = recv(ToFD(ReadDescriptor()), reinterpret_cast<char*>(data), size - data_read, 0); if (ret < 0) { if (WSAGetLastError() == WSAEWOULDBLOCK) { return 0; } else if (WSAGetLastError() != WSAEINTR) { OLA_WARN << "read failed, " << WSAGetLastError(); return -1; } } else if (ret == 0) { return 0; } data_read += ret; data += data_read; } else { OLA_WARN << "Descriptor type not implemented for reading: " << ReadDescriptor().m_type; return -1; } } #else if ((ret = read(ReadDescriptor(), data, size - data_read)) < 0) { if (errno == EAGAIN) return 0; if (errno != EINTR) { OLA_WARN << "read failed, " << strerror(errno); return -1; } } else if (ret == 0) { return 0; } data_read += ret; data += data_read; }
/** * Send an IOQueue. * This attempts to send as much of the IOQueue data as possible. The IOQueue * may be non-empty when this completes if the descriptor buffer is full. * @returns the number of bytes sent. */ ssize_t ConnectedDescriptor::Send(IOQueue *ioqueue) { if (!ValidWriteDescriptor()) return 0; int iocnt; const struct IOVec *iov = ioqueue->AsIOVec(&iocnt); ssize_t bytes_sent = 0; #ifdef _WIN32 /* There is no scatter/gather functionality for generic descriptors on * Windows, so this is implemented as a write loop. Derived classes should * re-implement Send() using scatter/gather I/O where available. */ int bytes_written = 0; for (int io = 0; io < iocnt; ++io) { bytes_written = write(WriteDescriptor().m_handle.m_fd, iov[io].iov_base, iov[io].iov_len); if (bytes_written == -1) { OLA_INFO << "Failed to send on " << WriteDescriptor() << ": " << strerror(errno); break; } bytes_sent += bytes_written; } #else #if HAVE_DECL_MSG_NOSIGNAL if (IsSocket()) { struct msghdr message; memset(&message, 0, sizeof(message)); message.msg_name = NULL; message.msg_namelen = 0; message.msg_iov = reinterpret_cast<iovec*>(const_cast<IOVec*>(iov)); message.msg_iovlen = iocnt; bytes_sent = sendmsg(WriteDescriptor(), &message, MSG_NOSIGNAL); } else { #else { #endif bytes_sent = writev(WriteDescriptor(), reinterpret_cast<const struct iovec*>(iov), iocnt); } #endif ioqueue->FreeIOVec(iov); if (bytes_sent < 0) { OLA_INFO << "Failed to send on " << WriteDescriptor() << ": " << strerror(errno); } else { ioqueue->Pop(bytes_sent); } return bytes_sent; } /* * Read data from this descriptor. * @param buffer a pointer to the buffer to store new data in * @param size the size of the buffer * @param data_read a value result argument which returns the amount of data * copied into the buffer * @returns -1 on error, 0 on success. */ int ConnectedDescriptor::Receive(uint8_t *buffer, unsigned int size, unsigned int &data_read) { // NOLINT int ret; uint8_t *data = buffer; data_read = 0; if (!ValidReadDescriptor()) return -1; while (data_read < size) { #ifdef _WIN32 if ((ret = read(ReadDescriptor().m_handle.m_fd, data, size - data_read)) < 0) { #else if ((ret = read(ReadDescriptor(), data, size - data_read)) < 0) { #endif if (errno == EAGAIN) return 0; if (errno != EINTR) { OLA_WARN << "read failed, " << strerror(errno); return -1; } } else if (ret == 0) { return 0; } data_read += ret; data += data_read; } return 0; } /* * Check if the remote end has closed the connection. * @return true if the socket is closed, false otherwise */ bool ConnectedDescriptor::IsClosed() const { return DataRemaining() == 0; } // LoopbackDescriptor // ------------------------------------------------ /* * Setup this loopback socket */ bool LoopbackDescriptor::Init() { if (m_handle_pair[0] != INVALID_DESCRIPTOR || m_handle_pair[1] != INVALID_DESCRIPTOR) return false; if (!CreatePipe(m_handle_pair)) return false; SetReadNonBlocking(); SetNoSigPipe(WriteDescriptor()); return true; } /* * Close the loopback socket * @return true if close succeeded, false otherwise */ bool LoopbackDescriptor::Close() { if (m_handle_pair[0] != INVALID_DESCRIPTOR) { #ifdef _WIN32 CloseHandle(m_handle_pair[0].m_handle.m_handle); #else close(m_handle_pair[0]); #endif } if (m_handle_pair[1] != INVALID_DESCRIPTOR) { #ifdef _WIN32 CloseHandle(m_handle_pair[1].m_handle.m_handle); #else close(m_handle_pair[1]); #endif } m_handle_pair[0] = INVALID_DESCRIPTOR; m_handle_pair[1] = INVALID_DESCRIPTOR; return true; } /* * Close the write portion of the loopback socket * @return true if close succeeded, false otherwise */ bool LoopbackDescriptor::CloseClient() { if (m_handle_pair[1] != INVALID_DESCRIPTOR) { #ifdef _WIN32 CloseHandle(m_handle_pair[1].m_handle.m_handle); #else close(m_handle_pair[1]); #endif } m_handle_pair[1] = INVALID_DESCRIPTOR; return true; } // PipeDescriptor // ------------------------------------------------ /* * Create a new pipe socket */ bool PipeDescriptor::Init() { if (m_in_pair[0] != INVALID_DESCRIPTOR || m_out_pair[1] != INVALID_DESCRIPTOR) return false; if (!CreatePipe(m_in_pair)) return false; if (!CreatePipe(m_out_pair)) { #ifdef _WIN32 CloseHandle(m_in_pair[0].m_handle.m_handle); CloseHandle(m_in_pair[1].m_handle.m_handle); #else close(m_in_pair[0]); close(m_in_pair[1]); #endif m_in_pair[0] = m_in_pair[1] = INVALID_DESCRIPTOR; return false; } SetReadNonBlocking(); SetNoSigPipe(WriteDescriptor()); return true; } /* * Fetch the other end of the pipe socket. The caller now owns the new * PipeDescriptor. * @returns NULL if the socket wasn't initialized correctly. */ PipeDescriptor *PipeDescriptor::OppositeEnd() { if (m_in_pair[0] == INVALID_DESCRIPTOR || m_out_pair[1] == INVALID_DESCRIPTOR) return NULL; if (!m_other_end) { m_other_end = new PipeDescriptor(m_out_pair, m_in_pair, this); m_other_end->SetReadNonBlocking(); } return m_other_end; } /* * Close this PipeDescriptor */ bool PipeDescriptor::Close() { if (m_in_pair[0] != INVALID_DESCRIPTOR) { #ifdef _WIN32 CloseHandle(m_in_pair[0].m_handle.m_handle); #else close(m_in_pair[0]); #endif } if (m_out_pair[1] != INVALID_DESCRIPTOR) { #ifdef _WIN32 CloseHandle(m_out_pair[1].m_handle.m_handle); #else close(m_out_pair[1]); #endif } m_in_pair[0] = INVALID_DESCRIPTOR; m_out_pair[1] = INVALID_DESCRIPTOR; return true; } /* * Close the write portion of this PipeDescriptor */ bool PipeDescriptor::CloseClient() { if (m_out_pair[1] != INVALID_DESCRIPTOR) { #ifdef _WIN32 CloseHandle(m_out_pair[1].m_handle.m_handle); #else close(m_out_pair[1]); #endif } m_out_pair[1] = INVALID_DESCRIPTOR; return true; } // UnixSocket // ------------------------------------------------ /* * Create a new unix socket */ bool UnixSocket::Init() { #ifdef _WIN32 return false; #else int pair[2]; if ((m_handle != INVALID_DESCRIPTOR) || m_other_end) return false; if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair)) { OLA_WARN << "socketpair() failed, " << strerror(errno); return false; } m_handle = pair[0]; SetReadNonBlocking(); SetNoSigPipe(WriteDescriptor()); m_other_end = new UnixSocket(pair[1], this); m_other_end->SetReadNonBlocking(); return true; #endif } /* * Fetch the other end of the unix socket. The caller now owns the new * UnixSocket. * @returns NULL if the socket wasn't initialized correctly. */ UnixSocket *UnixSocket::OppositeEnd() { return m_other_end; } /* * Close this UnixSocket */ bool UnixSocket::Close() { #ifdef _WIN32 return true; #else if (m_handle != INVALID_DESCRIPTOR) { close(m_handle); } m_handle = INVALID_DESCRIPTOR; return true; #endif } /* * Close the write portion of this UnixSocket */ bool UnixSocket::CloseClient() { #ifndef _WIN32 if (m_handle != INVALID_DESCRIPTOR) shutdown(m_handle, SHUT_WR); #endif m_handle = INVALID_DESCRIPTOR; return true; } // DeviceDescriptor // ------------------------------------------------ DeviceDescriptor::DeviceDescriptor(int fd) { #ifdef _WIN32 m_handle.m_handle.m_fd = fd; m_handle.m_type = GENERIC_DESCRIPTOR; m_handle.m_event_handle = 0; #else m_handle = fd; #endif }
long CIpSocket::WaitEvent( long x_lEventId, long x_lTimeout ) { #if defined( HTM_NOEPOLL ) return 0; #else // Must have a socket handle if ( !IsSocket() ) return 0; // Must have event handle if ( !IsEventHandle() || !m_pEventObject ) { if ( !CreateEventHandle() ) return 0; if ( !EventSelect() ) return 0; } // end if // +++ Ensure our event is being waited on? // Grab pointer to event object epoll_event *pev = (epoll_event*)m_pEventObject; // Check for default timeout if ( 0 > x_lTimeout ) x_lTimeout = (long)m_lTimeout; // Save start time unsigned int uEnd = time( 0 ) + x_lTimeout / 1000; for( ; ; ) // forever { // What's the event state if ( 0 == ( m_uEventState & x_lEventId ) ) { // Wait only for our specific event EventSelect( x_lEventId ); // Wait for events int nRes; do { nRes = epoll_wait( tcPtrToULong( m_hSocketEvent ), pev, eMaxEvents, x_lTimeout ); } while ( -1 == nRes && EINTR == errno ); if ( -1 == nRes ) { // Log error m_uLastError = errno; // Disconnected? m_uConnectState |= eCsError; // Just ditch if they aren't waiting for the close event m_uEventState |= eCloseEvent; if ( !( x_lEventId & eCloseEvent ) ) return 0; } // end if // Process all events if ( 0 < nRes ) for ( long i = 0; i < nRes; i++ ) { // Convert to windows flags unsigned long uFlags = FlagNixToWin( pev[ i ].events ); // Save the status of all events if ( pev[ i ].data.fd == tcPtrToULong( m_hSocket ) ) { pev[ i ].events = 0; for ( unsigned long uMask = 1; uMask < eAllEvents; uMask <<= 1 ) if ( uFlags & uMask ) { // Get bit offset unsigned long uOffset = GetEventBit( uMask ); // Save the event info m_uEventState |= uMask; m_uEventStatus[ uOffset ] = 0; // Attempt to detect connect error if ( 0 != ( uMask & eConnectEvent ) ) { /* +++ Nope, doesn't always work // use getpeername() to check for errors sockaddr_in sai; memset( &sai, 0, sizeof( sai ) ); socklen_t len = sizeof( sai ); if ( -1 == getpeername( tcPtrToULong( m_hSocket ), (sockaddr*)&sai, &len ) ) { m_uLastError = errno; m_uEventStatus[ uOffset ] = errno; m_uConnectState |= eCsError; } // end if */ /* +++ gives error : Resource temporarily unavailable char buf[ 1 ]; if ( -1 == recv( tcPtrToULong( m_hSocket ), buf, 0, 0 ) ) { m_uLastError = errno; m_uEventStatus[ uOffset ] = errno; m_uConnectState |= eCsError; } // end if */ } // Handle close event if ( 0 != ( uMask & eCloseEvent ) ) m_uConnectState &= ~eCsConnected; else m_uConnectState |= eCsActivity; // +++ Signal when we get a connect message // if ( 0 != ( ( EPOLLIN | EPOLLOUT ) & uMask ) ) // m_uConnectState |= 2; } // end if } // end if } // end for // !!! Kludge around missing connect message if ( !( m_uConnectState & eCsConnected ) && ( m_uConnectState & eCsActivity ) ) { m_uConnectState |= eCsConnected; // m_uConnectState &= ~eCsError; m_uEventState |= eConnectEvent; m_uEventStatus[ eConnectBit ] = 0; } // end if } // end if // Did our event go off? if ( 0 != ( m_uEventState & x_lEventId ) ) { // Get the first event unsigned long uBit = GetEventBit( x_lEventId & m_uEventState ); unsigned long uMask = 1 << uBit; // Acknowledge this event // m_uEventState &= ~uMask; // Save the error code if ( m_uEventStatus[ uBit ] ) m_uLastError = m_uEventStatus[ uBit ]; // Something is going on m_lActivity++; // We received the event return uMask; } // end if // Have we timed out? unsigned long uTick = time( 0 ); if ( uEnd <= uTick ) return 0; // Adjust timeout x_lTimeout = ( uEnd - uTick ) * 1000; } // end if // Can't get here... return 0; #endif }
long CIpSocket::WaitEvent( long x_lEventId, long x_uTimeout ) { #if defined( HTM_NOSOCKET2 ) return 0; #else // Must have a socket handle if ( !IsSocket() ) return 0; // Must have event handle if ( !IsEventHandle() ) { if ( !CreateEventHandle() || !EventSelect() ) return 0; } // end if if ( 0 > x_uTimeout ) x_uTimeout = m_lTimeout; // Save start time UINT uEnd = GetTickCount() + x_uTimeout; for( ; ; ) { // What's the event state if ( 0 == ( m_uEventState & x_lEventId ) ) { if ( x_uTimeout ) { // Wait for event // UINT uRet = WaitForSingleObject( m_hSocketEvent, x_uTimeout ); // Check for timeout or error // if ( uRet != WAIT_OBJECT_0 ) // return 0; } // end if // Reset the network event ResetEvent( m_hSocketEvent ); // Get network events WSANETWORKEVENTS wne; memset( &wne, 0, sizeof( wne ) ); if ( SOCKET_ERROR == WSAEnumNetworkEvents( (SOCKET)m_hSocket, m_hSocketEvent, &wne ) ) { m_uLastError = WSAGetLastError(); return 0; } // end if // Save the status of all events for ( unsigned int uMask = 1; uMask && uMask <= eAllEvents; uMask <<= 1 ) if ( wne.lNetworkEvents & uMask ) { // Get bit offset unsigned int uOffset = GetEventBit( uMask ); // Save the event info m_uEventState |= uMask; m_uEventStatus[ uOffset ] = wne.iErrorCode[ uOffset ]; // Signal activity m_uConnectState |= eCsActivity; // Signal when we get a connect message if ( 0 != ( FD_CONNECT & wne.lNetworkEvents ) ) { // Set connected status if ( !m_uEventStatus[ FD_CONNECT_BIT ] ) m_uConnectState |= eCsConnected; // Handle connect error else m_uLastError = m_uEventStatus[ FD_CONNECT_BIT ], m_uConnectState &= ~( eCsConnected | eCsActivity ); // Connecting process is over m_uConnectState &= ~eCsConnecting; } // end if // Check for socket close if ( 0 != ( FD_CLOSE & wne.lNetworkEvents ) ) m_uConnectState &= ~( eCsConnected | eCsActivity | eCsConnecting ); } // end if // !!! Kludge around missing connect message // If we're accepting a connection, we don't // get a connect message. ( At least on Windows ) if ( !( m_uConnectState & 2 ) && ( m_uConnectState & 1 ) ) { m_uConnectState |= eCsConnected; m_uConnectState &= ~eCsConnecting; wne.lNetworkEvents |= FD_CONNECT; m_uEventState |= FD_CONNECT; m_uEventStatus[ FD_CONNECT_BIT ] = 0; } // end if } // end if // Did our event go off? if ( 0 != ( m_uEventState & x_lEventId ) ) { // Get the first event unsigned int uBit = GetEventBit( x_lEventId & m_uEventState ); unsigned int uMask = 1 << uBit; // Acknowledge this event m_uEventState &= ~uMask; // Save the error code m_uLastError = m_uEventStatus[ uBit ]; // Something is going on m_lActivity++; // We received the event return uMask; } // end if // Have we timed out? unsigned int uTick = GetTickCount(); if ( uEnd <= uTick ) return 0; // Adjust timeout x_uTimeout = uEnd - uTick; } // end if // Can't get here... return 0; #endif }