/*-------------------------------------------------------------------------*\ * Send with timeout * On windows, if you try to send 10MB, the OS will buffer EVERYTHING * this can take an awful lot of time and we will end up blocked. * Therefore, whoever calls this function should not pass a huge buffer. \*-------------------------------------------------------------------------*/ int socket_send(p_socket ps, const char *data, size_t count, size_t *sent, p_timeout tm) { int err; *sent = 0; /* avoid making system calls on closed sockets */ if (*ps == SOCKET_INVALID) return IO_CLOSED; /* loop until we send something or we give up on error */ for ( ;; ) { /* try to send something */ int put = send(*ps, data, (int) count, 0); /* if we sent something, we are done */ if (put > 0) { *sent = put; return IO_DONE; } /* deal with failure */ err = WSAGetLastError(); /* we can only proceed if there was no serious error */ if (err != WSAEWOULDBLOCK) return err; /* avoid busy wait */ if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; } /* can't reach here */ return IO_UNKNOWN; }
/*-------------------------------------------------------------------------*\ * Connects or returns error message \*-------------------------------------------------------------------------*/ int socket_connect(p_socket ps, SA *addr, socklen_t len, p_timeout tm) { int err; /* don't call on closed socket */ if (*ps == SOCKET_INVALID) return IO_CLOSED; /* ask system to connect */ if (connect(*ps, addr, len) == 0) return IO_DONE; /* make sure the system is trying to connect */ err = WSAGetLastError(); if (err != WSAEWOULDBLOCK && err != WSAEINPROGRESS) return err; /* zero timeout case optimization */ if (timeout_iszero(tm)) return IO_TIMEOUT; /* we wait until something happens */ err = socket_waitfd(ps, WAITFD_C, tm); if (err == IO_CLOSED) { int len = sizeof(err); /* give windows time to set the error (yes, disgusting) */ Sleep(10); /* find out why we failed */ getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *)&err, &len); /* we KNOW there was an error. if 'why' is 0, we will return * "unknown error", but it's not really our fault */ return err > 0? err: IO_UNKNOWN; } else return err; }
/*-------------------------------------------------------------------------*\ * Send with timeout \*-------------------------------------------------------------------------*/ int socket_send(p_socket ps, const char *data, size_t count, size_t *sent, p_timeout tm) { int err; *sent = 0; /* avoid making system calls on closed sockets */ if (*ps == SOCKET_INVALID) return IO_CLOSED; /* loop until we send something or we give up on error */ for ( ;; ) { long put = (long) send(*ps, data, count, 0); /* if we sent anything, we are done */ if (put > 0) { *sent = put; return IO_DONE; } err = peusock_errno; /* send can't really return 0, but EPIPE means the connection was closed */ if (put == 0 || err == peusock_EPIPE) return IO_CLOSED; /* we call was interrupted, just try again */ if (err == peusock_EINTR) continue; /* if failed fatal reason, report error */ if (err != peusock_EAGAIN) return err; /* wait until we can send something or we timeout */ if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; } /* can't reach here */ return IO_UNKNOWN; }
/*-------------------------------------------------------------------------*\ * Recvfrom with timeout \*-------------------------------------------------------------------------*/ int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got, SA *addr, socklen_t *len, p_timeout tm) { int err, prev = IO_DONE; *got = 0; if (*ps == SOCKET_INVALID) return IO_CLOSED; for ( ;; ) { int taken = recvfrom(*ps, data, (int) count, 0, addr, len); if (taken > 0) { *got = taken; return IO_DONE; } if (taken == 0) return IO_CLOSED; err = WSAGetLastError(); /* On UDP, a connreset simply means the previous send failed. * So we try again. * On TCP, it means our socket is now useless, so the error passes. * (We will loop again, exiting because the same error will happen) */ if (err != WSAEWOULDBLOCK) { if (err != WSAECONNRESET || prev == WSAECONNRESET) return err; prev = err; } if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; } }
/** * Receive data */ static int ssl_recv(void *ctx, char *data, size_t count, size_t *got, p_timeout tm) { int err; p_ssl ssl = (p_ssl) ctx; if (ssl->state == ST_SSL_CLOSED) return IO_CLOSED; *got = 0; for ( ; ; ) { ERR_clear_error(); err = SSL_read(ssl->ssl, data, (int) count); ssl->error = SSL_get_error(ssl->ssl, err); switch(ssl->error) { case SSL_ERROR_NONE: *got = err; return IO_DONE; case SSL_ERROR_ZERO_RETURN: *got = err; return IO_CLOSED; case SSL_ERROR_WANT_READ: err = socket_waitfd(&ssl->sock, WAITFD_R, tm); if (err == IO_TIMEOUT) return IO_SSL; if (err != IO_DONE) return err; break; case SSL_ERROR_WANT_WRITE: err = socket_waitfd(&ssl->sock, WAITFD_W, tm); if (err == IO_TIMEOUT) return IO_SSL; if (err != IO_DONE) return err; break; case SSL_ERROR_SYSCALL: if (ERR_peek_error()) { ssl->error = SSL_ERROR_SSL; return IO_SSL; } if (err == 0) return IO_CLOSED; return socket_error(); default: return IO_SSL; } } return IO_UNKNOWN; }
/** * Send data */ static int ssl_send(void *ctx, const char *data, size_t count, size_t *sent, p_timeout tm) { int err; p_ssl ssl = (p_ssl)ctx; if (ssl->state != LSEC_STATE_CONNECTED) return IO_CLOSED; *sent = 0; for ( ; ; ) { ERR_clear_error(); err = SSL_write(ssl->ssl, data, (int)count); ssl->error = SSL_get_error(ssl->ssl, err); switch (ssl->error) { case SSL_ERROR_NONE: *sent = err; return IO_DONE; case SSL_ERROR_WANT_READ: err = socket_waitfd(&ssl->sock, WAITFD_R, tm); if (err == IO_TIMEOUT) return LSEC_IO_SSL; if (err != IO_DONE) return err; break; case SSL_ERROR_WANT_WRITE: err = socket_waitfd(&ssl->sock, WAITFD_W, tm); if (err == IO_TIMEOUT) return LSEC_IO_SSL; if (err != IO_DONE) return err; break; case SSL_ERROR_SYSCALL: if (ERR_peek_error()) { ssl->error = SSL_ERROR_SSL; return LSEC_IO_SSL; } if (err == 0) return IO_CLOSED; return lsec_socket_error(); default: return LSEC_IO_SSL; } } return IO_UNKNOWN; }
/*-------------------------------------------------------------------------*\ * Accept with timeout \*-------------------------------------------------------------------------*/ int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len, p_timeout tm) { if (*ps == SOCKET_INVALID) return IO_CLOSED; for ( ;; ) { int err; if ((*pa = accept(*ps, addr, len)) != SOCKET_INVALID) return IO_DONE; err = errno; if (err == EINTR) continue; if (err != EAGAIN && err != ECONNABORTED) return err; if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; } /* can't reach here */ return IO_UNKNOWN; }
/** * Perform the TLS/SSL handshake */ static int handshake(p_ssl ssl) { int err; p_timeout tm = timeout_markstart(&ssl->tm); if (ssl->state == ST_SSL_CLOSED) return IO_CLOSED; for ( ; ; ) { ERR_clear_error(); err = SSL_do_handshake(ssl->ssl); ssl->error = SSL_get_error(ssl->ssl, err); switch(ssl->error) { case SSL_ERROR_NONE: ssl->state = ST_SSL_CONNECTED; return IO_DONE; case SSL_ERROR_WANT_READ: err = socket_waitfd(&ssl->sock, WAITFD_R, tm); if (err == IO_TIMEOUT) return IO_SSL; if (err != IO_DONE) return err; break; case SSL_ERROR_WANT_WRITE: err = socket_waitfd(&ssl->sock, WAITFD_W, tm); if (err == IO_TIMEOUT) return IO_SSL; if (err != IO_DONE) return err; break; case SSL_ERROR_SYSCALL: if (ERR_peek_error()) { ssl->error = SSL_ERROR_SSL; return IO_SSL; } if (err == 0) return IO_CLOSED; return socket_error(); default: return IO_SSL; } } return IO_UNKNOWN; }
int socket_recv(SOCKET socket, char *data, size_t count, int flags) { int err; for ( ;; ) { int taken = recv(socket, data, (int) count, 0); if (taken > 0) { return taken; } if (taken == 0) return IO_CLOSED; err = socket_errno; if (err != SOCKET_EWOULDBLOCK) return -1; if ((err = socket_waitfd(socket, WAITFD_R)) != IO_DONE) return -1; } return IO_UNKNOWN; }
int socket_recv(SOCKET socket, char *data, size_t count, int flags) { int err; for ( ;; ) { long taken = (long) recv(socket, data, count, 0); if (taken > 0) { return taken; } err = errno; if (taken == 0) return -1; if (err == EINTR) continue; if (err != EAGAIN) return -1; if ((err = socket_waitfd(socket, WAITFD_R)) != IO_DONE) return -1; } return IO_UNKNOWN; }
/*-------------------------------------------------------------------------*\ * Accept with timeout \*-------------------------------------------------------------------------*/ int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len, p_timeout tm) { if (*ps == SOCKET_INVALID) return IO_CLOSED; for ( ;; ) { int err; /* try to get client socket */ if ((*pa = accept(*ps, addr, len)) != SOCKET_INVALID) return IO_DONE; /* find out why we failed */ err = WSAGetLastError(); /* if we failed because there was no connectoin, keep trying */ if (err != WSAEWOULDBLOCK && err != WSAECONNABORTED) return err; /* call select to avoid busy wait */ if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; } }
/*-------------------------------------------------------------------------*\ * Receive with timeout \*-------------------------------------------------------------------------*/ int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm) { int err; *got = 0; if (*ps == SOCKET_INVALID) return IO_CLOSED; for ( ;; ) { int taken = recv(*ps, data, (int) count, 0); if (taken > 0) { *got = taken; return IO_DONE; } if (taken == 0) return IO_CLOSED; err = WSAGetLastError(); if (err != WSAEWOULDBLOCK) return err; if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; } }
/*-------------------------------------------------------------------------*\ * Sendto with timeout \*-------------------------------------------------------------------------*/ int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent, SA *addr, socklen_t len, p_timeout tm) { int err; *sent = 0; if (*ps == SOCKET_INVALID) return IO_CLOSED; for ( ;; ) { int put = sendto(*ps, data, (int) count, 0, addr, len); if (put > 0) { *sent = put; return IO_DONE; } err = WSAGetLastError(); if (err != WSAEWOULDBLOCK) return err; if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; } }
/*-------------------------------------------------------------------------*\ * Connects or returns error message \*-------------------------------------------------------------------------*/ int socket_connect(p_socket ps, SA *addr, socklen_t len, p_timeout tm) { int err; /* avoid calling on closed sockets */ if (*ps == SOCKET_INVALID) return IO_CLOSED; /* call connect until done or failed without being interrupted */ do if (connect(*ps, addr, len) == 0) return IO_DONE; while ((err = peusock_errno) == peusock_EINTR); /* if connection failed immediately, return error code */ if (err != peusock_EINPROGRESS && err != peusock_EAGAIN) return err; /* zero timeout case optimization */ if (timeout_iszero(tm)) return IO_TIMEOUT; /* wait until we have the result of the connection attempt or timeout */ err = socket_waitfd(ps, WAITFD_C, tm); if (err == IO_CLOSED) { if (recv(*ps, (char *) &err, 0, 0) == 0) return IO_DONE; else return peusock_errno; } else return err; }
/*-------------------------------------------------------------------------*\ * Receive with timeout \*-------------------------------------------------------------------------*/ int socket_recv(p_socket ps, char *data, size_t count, size_t *got, int flags, p_timeout tm) { int err; *got = 0; if (*ps == SOCKET_INVALID) return IO_CLOSED; for ( ;; ) { long taken = (long) recv(*ps, data, count, flags); if (taken > 0) { *got = taken; return IO_DONE; } err = errno; if (taken == 0) return IO_CLOSED; if (err == EINTR) continue; if (err != EAGAIN) return err; if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; } return IO_UNKNOWN; }
/*-------------------------------------------------------------------------*\ * Recvfrom with timeout \*-------------------------------------------------------------------------*/ int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got, SA *addr, socklen_t *len, p_timeout tm) { int err; *got = 0; if (*ps == SOCKET_INVALID) return IO_CLOSED; for ( ;; ) { long taken = (long) recvfrom(*ps, data, count, 0, addr, len); if (taken > 0) { *got = taken; return IO_DONE; } err = peusock_errno; if (taken == 0) return IO_CLOSED; if (err == peusock_EINTR) continue; if (err != peusock_EAGAIN) return err; if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; } return IO_UNKNOWN; }
/*-------------------------------------------------------------------------*\ * Sendto with timeout \*-------------------------------------------------------------------------*/ int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent, SA *addr, socklen_t len, p_timeout tm) { int err; *sent = 0; if (*ps == SOCKET_INVALID) return IO_CLOSED; for ( ;; ) { long put = (long) sendto(*ps, data, count, 0, addr, len); if (put > 0) { *sent = put; return IO_DONE; } err = peusock_errno; if (put == 0 || err == peusock_EPIPE) return IO_CLOSED; if (err == peusock_EINTR) continue; if (err != peusock_EAGAIN) return err; if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; } return IO_UNKNOWN; }
int socket_send(SOCKET socket, const char *data, size_t count, int flags) { int err; /* loop until we send something or we give up on error */ for ( ;; ) { /* try to send something */ int put = send(socket, data, (int) count, 0); /* if we sent something, we are done */ if (put > 0) { return put; } /* deal with failure */ err = socket_errno; /* we can only proceed if there was no serious error */ if (err != SOCKET_EWOULDBLOCK) return -1; /* avoid busy wait */ if ((err = socket_waitfd(socket, WAITFD_W)) != IO_DONE) return -1; } /* can't reach here */ return IO_UNKNOWN; }
/*-------------------------------------------------------------------------*\ * Accept with timeout \*-------------------------------------------------------------------------*/ int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len, p_timeout tm) { SA daddr; socklen_t dlen = sizeof(daddr); if (*ps == SOCKET_INVALID) return IO_CLOSED; if (!addr) addr = &daddr; if (!len) len = &dlen; for ( ;; ) { int err; if ((*pa = peusock_accept(*ps, addr, len)) >= 0) { printf("LuaSocket(C++ core): socket_accept(): accept succeeded\n"); return IO_DONE; } err = peusock_errno; if (err == peusock_EINTR) continue; if (err != peusock_EAGAIN && err != peusock_ECONNABORTED) return err; if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; } /* can't reach here */ return IO_UNKNOWN; }
int socket_send(SOCKET socket, const char *data, size_t count, int flags) { int err; /* loop until we send something or we give up on error */ for ( ;; ) { long put = (long) send(socket, data, count, 0); /* if we sent anything, we are done */ if (put > 0) { return put; } err = errno; /* send can't really return 0, but EPIPE means the connection was closed */ if (put == 0 || err == EPIPE) return -1; /* we call was interrupted, just try again */ if (err == EINTR) continue; /* if failed fatal reason, report error */ if (err != EAGAIN) return -1; /* wait until we can send something or we timeout */ if ((err = socket_waitfd(socket, WAITFD_W)) != IO_DONE) return -1; } /* can't reach here */ return IO_UNKNOWN; }