int GSocket::Write(const char *buffer, int size) { int ret; assert(this); GSocket_Debug(( "GSocket_Write #1, size %d\n", size )); if (m_fd == INVALID_SOCKET || m_server) { m_error = GSOCK_INVSOCK; return -1; } GSocket_Debug(( "GSocket_Write #2, size %d\n", size )); /* If the socket is blocking, wait for writability (with a timeout) */ if (Output_Timeout() == GSOCK_TIMEDOUT) return -1; GSocket_Debug(( "GSocket_Write #3, size %d\n", size )); /* Write the data */ if (m_stream) ret = Send_Stream(buffer, size); else ret = Send_Dgram(buffer, size); GSocket_Debug(( "GSocket_Write #4, size %d\n", size )); if (ret == -1) { if ((errno == EWOULDBLOCK) || (errno == EAGAIN)) { m_error = GSOCK_WOULDBLOCK; GSocket_Debug(( "GSocket_Write error WOULDBLOCK\n" )); } else { m_error = GSOCK_IOERR; GSocket_Debug(( "GSocket_Write error IOERR\n" )); } /* Only reenable OUTPUT events after an error (just like WSAAsyncSelect * in MSW). Once the first OUTPUT event is received, users can assume * that the socket is writable until a read operation fails. Only then * will further OUTPUT events be posted. */ Enable(GSOCK_OUTPUT); return -1; } GSocket_Debug(( "GSocket_Write #5, size %d ret %d\n", size, ret )); return ret; }
int GSocket::Write(const char *buffer, int size) { int ret; assert(this); if (m_fd == INVALID_SOCKET || m_server) { m_error = GSOCK_INVSOCK; return -1; } /* If the socket is blocking, wait for writability (with a timeout) */ if (Output_Timeout() == GSOCK_TIMEDOUT) return -1; /* Write the data */ if (m_stream) ret = Send_Stream(buffer, size); else ret = Send_Dgram(buffer, size); if (ret == SOCKET_ERROR) { if (WSAGetLastError() != WSAEWOULDBLOCK) m_error = GSOCK_IOERR; else m_error = GSOCK_WOULDBLOCK; /* Only reenable OUTPUT events after an error (just like WSAAsyncSelect * does). Once the first OUTPUT event is received, users can assume * that the socket is writable until a read operation fails. Only then * will further OUTPUT events be posted. */ m_detected &= ~GSOCK_OUTPUT_FLAG; return -1; } return ret; }
/* GSocket_Connect: * For stream (connection oriented) sockets, GSocket_Connect() tries * to establish a client connection to a server using the peer address * as established with GSocket_SetPeer(). Returns GSOCK_NOERROR if the * connection has been successfully established, or one of the error * codes listed below. Note that for nonblocking sockets, a return * value of GSOCK_WOULDBLOCK doesn't mean a failure. The connection * request can be completed later; you should use GSocket_Select() * to poll for GSOCK_CONNECTION | GSOCK_LOST, or wait for the * corresponding asynchronous events. * * For datagram (non connection oriented) sockets, GSocket_Connect() * just sets the peer address established with GSocket_SetPeer() as * default destination. * * Error codes: * GSOCK_INVSOCK - the socket is in use or not valid. * GSOCK_INVADDR - the peer address has not been established. * GSOCK_TIMEDOUT - timeout, the connection failed. * GSOCK_WOULDBLOCK - connection in progress (nonblocking sockets only) * GSOCK_MEMERR - couldn't allocate memory. * GSOCK_IOERR - low-level error. */ GSocketError GSocket::Connect(GSocketStream stream) { int err, ret; int arg = 1; assert(this); /* Enable CONNECTION events (needed for nonblocking connections) */ Enable(GSOCK_CONNECTION); if (m_fd != INVALID_SOCKET) { m_error = GSOCK_INVSOCK; return GSOCK_INVSOCK; } if (!m_peer) { m_error = GSOCK_INVADDR; return GSOCK_INVADDR; } /* Streamed or dgram socket? */ m_stream = (stream == GSOCK_STREAMED); m_server = false; m_establishing = false; /* Create the socket */ m_fd = socket(m_peer->m_realfamily, m_stream? SOCK_STREAM : SOCK_DGRAM, 0); if (m_fd == INVALID_SOCKET) { m_error = GSOCK_IOERR; return GSOCK_IOERR; } /* FreeBSD variants can't use MSG_NOSIGNAL, and instead use a socket option */ #ifdef SO_NOSIGPIPE setsockopt(m_fd, SOL_SOCKET, SO_NOSIGPIPE, (const char*)&arg, sizeof(u_long)); #endif #if defined(__EMX__) || defined(__VISAGECPP__) ioctl(m_fd, FIONBIO, (char*)&arg, sizeof(arg)); #else ioctl(m_fd, FIONBIO, &arg); #endif /* Connect it to the peer address, with a timeout (see below) */ ret = connect(m_fd, m_peer->m_addr, m_peer->m_len); /* We only call Enable_Events if we know e aren't shutting down the socket */ if (m_non_blocking) { gs_gui_functions->Enable_Events(this); } if (ret == -1) { err = errno; /* If connect failed with EINPROGRESS and the GSocket object * is in blocking mode, we select() for the specified timeout * checking for writability to see if the connection request * completes. */ if ((err == EINPROGRESS) && (!m_non_blocking)) { if (Output_Timeout() == GSOCK_TIMEDOUT) { Close(); /* m_error is set in _GSocket_Output_Timeout */ return GSOCK_TIMEDOUT; } else { int error; SOCKOPTLEN_T len = sizeof(error); getsockopt(m_fd, SOL_SOCKET, SO_ERROR, (char*) &error, &len); gs_gui_functions->Enable_Events(this); if (!error) return GSOCK_NOERROR; } } /* If connect failed with EINPROGRESS and the GSocket object * is set to nonblocking, we set m_error to GSOCK_WOULDBLOCK * (and return GSOCK_WOULDBLOCK) but we don't close the socket; * this way if the connection completes, a GSOCK_CONNECTION * event will be generated, if enabled. */ if ((err == EINPROGRESS) && (m_non_blocking)) { m_establishing = true; m_error = GSOCK_WOULDBLOCK; return GSOCK_WOULDBLOCK; } /* If connect failed with an error other than EINPROGRESS, * then the call to GSocket_Connect has failed. */ Close(); m_error = GSOCK_IOERR; return GSOCK_IOERR; } return GSOCK_NOERROR; }