diff --git a/qse/include/qse/cmn/sck.h b/qse/include/qse/cmn/sck.h index c375880f..56da2fbc 100644 --- a/qse/include/qse/cmn/sck.h +++ b/qse/include/qse/cmn/sck.h @@ -30,6 +30,7 @@ #include #include +#include #if defined(_WIN32) typedef qse_uintptr_t qse_sck_hnd_t; @@ -87,6 +88,20 @@ QSE_EXPORT void qse_shutsckhnd ( qse_shutsckhnd_how_t how ); +QSE_EXPORT int qse_setscknonblock ( + qse_sck_hnd_t handle, + int enabled +); + +QSE_EXPORT int qse_initsckconn ( + qse_sck_hnd_t handle, + const qse_nwad_t* nwad +); + +QSE_EXPORT int qse_finisckconn ( + qse_sck_hnd_t handle +); + #if defined(__cplusplus) } #endif diff --git a/qse/lib/cmn/sck.c b/qse/lib/cmn/sck.c index 0fd0d005..98ee25d6 100644 --- a/qse/lib/cmn/sck.c +++ b/qse/lib/cmn/sck.c @@ -148,6 +148,123 @@ QSE_INLINE void qse_shutsckhnd (qse_sck_hnd_t handle, qse_shutsckhnd_how_t how) #endif } +int qse_setscknonblock (qse_sck_hnd_t handle, int enabled) +{ +#if defined(_WIN32) + if (ioctlsocket (handle, FIONBIO, &enabled) == SOCKET_ERROR) return -1; + return 0; + +#elif defined(__OS2__) + + if (ioctl (handle, FIONBIO, (char*)&enabled, sizeof(enabled)) <= -1) return -1; + return 0; + +#elif defined(__DOS__) + + if (ioctlsocket (handle, FIONBIO, (char*)&enabled) == SOCKET_ERROR) return -1; + return 0; + +#elif defined(O_NONBLOCK) + + int flag = fcntl (handle, F_GETFL); + if (flag >= 0) flag = fcntl (handle, F_SETFL, (enabled? (flag | O_NONBLOCK): (flag & ~O_NONBLOCK))); + if (flag <= -1) return -1; + return 0; + +#else + + return -1; +#endif +} + +int qse_initsckconn (qse_sck_hnd_t handle, const qse_nwad_t* nwad) +{ + int n; +#if defined(_WIN32) + unsigned long cmd; +#else + int saved = 0; +#endif + qse_skad_t skad; + int skadlen; + + skadlen = qse_nwadtoskad (nwad, &skad); + if (skadlen <= -1) return -1; + +#if defined(_WIN32) + /* switch to the non-blocking mode */ + cmd = 1; + if (ioctlsocket(handle, FIONBIO, &cmd) == SOCKET_ERROR) + { + /* error code in WSAGetLastError() */ + return -1; + } + + /* attempt to connet */ + n = connect (handle, (struct sockaddr*)&skad, skadlen); + if (n == -1 && WSAGetLastError() != WSAEWOULDBLOCK) + { + /* attemp to restore to the blocking mode upon failure. + * there is no guarantee that this was the previous mode. */ + cmd = 0; + ioctlsocket (handle, FIONBIO, &cmd); + return -1; + } +#else + /* switch to the non-blocking mode */ + saved = fcntl (handle, F_GETFL, 0); + if (saved == -1) return -1; + if (fcntl (handle, F_SETFL, saved | O_NONBLOCK) == -1) return -1; + + /* attempt to connet */ + do + { + n = connect (handle, (struct sockaddr*)&skad, skadlen); + } + while (n == -1 && errno == EINTR); + + if (n == -1 && errno != EINPROGRESS) + { + fcntl (handle, F_SETFL, saved); /* restore the flags upon failure */ + return -1; + } +#endif + + /* the socket still remains in the non-blocking mode */ + return (n == 0)? 1: 0; /* 1: connected, 0: in progress */ +} + +int qse_finisckconn (qse_sck_hnd_t handle) +{ + int ret; + qse_sck_len_t len; + + len = (qse_sck_len_t)QSE_SIZEOF (ret); + if (getsockopt (handle, SOL_SOCKET, SO_ERROR, (char*)&ret, &len) == -1) return -1; + +#ifdef _WIN32 + if (ret == WSAETIMEDOUT) +#else + if (ret == ETIMEDOUT) +#endif + { + return -1; /* failure - timed out */ + } +#ifdef _WIN32 + else if (ret == WSAEWOULDBLOCK) +#else + else if (ret == EINPROGRESS) +#endif + { + return 0; /* in preogress */ + } + else if (ret != 0) + { + return -1; /* failure */ + } + + return 1; /* connected */ +} #if 0 qse_sck_hnd_t diff --git a/qse/lib/http/httpd-std.c b/qse/lib/http/httpd-std.c index 6c5d47e0..64e622b9 100644 --- a/qse/lib/http/httpd-std.c +++ b/qse/lib/http/httpd-std.c @@ -797,54 +797,6 @@ void* qse_httpd_getxtnstd (qse_httpd_t* httpd) /* ------------------------------------------------------------------- */ -static int set_socket_nonblock (qse_httpd_t* httpd, qse_sck_hnd_t fd, int enabled) -{ -#if defined(_WIN32) - if (ioctlsocket (fd, FIONBIO, &enabled) == SOCKET_ERROR) - { - qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); - return -1; - } - - return 0; - -#elif defined(__OS2__) - - if (ioctl (fd, FIONBIO, (char*)&enabled, sizeof(enabled)) <= -1) - { - qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); - return -1; - } - return 0; - -#elif defined(__DOS__) - - if (ioctlsocket (fd, FIONBIO, (char*)&enabled) == SOCKET_ERROR) - { - qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); - return -1; - } - - return 0; - -#elif defined(O_NONBLOCK) - - int flag = fcntl (fd, F_GETFL); - if (flag >= 0) flag = fcntl (fd, F_SETFL, (enabled? (flag | O_NONBLOCK): (flag & ~O_NONBLOCK))); - if (flag <= -1) - { - qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); - return -1; - } - return 0; -#else - - qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); - return -1; -#endif - -} - static qse_sck_hnd_t open_client_socket (qse_httpd_t* httpd, int domain, int type, int proto) { qse_sck_hnd_t fd; @@ -892,7 +844,11 @@ static qse_sck_hnd_t open_client_socket (qse_httpd_t* httpd, int domain, int typ #endif */ - if (set_socket_nonblock (httpd, fd, 1) <= -1) goto oops; + if (qse_setscknonblock (fd, 1) <= -1) + { + qse_httpd_seterrnum (httpd, QSE_HTTPD_ESYSERR); + goto oops; + } #if defined(IPPROTO_SCTP) if (proto == IPPROTO_SCTP) @@ -906,14 +862,22 @@ static qse_sck_hnd_t open_client_socket (qse_httpd_t* httpd, int domain, int typ im.sinit_max_instreams = 1; im.sinit_max_attempts = 1; - if (setsockopt (fd, SOL_SCTP, SCTP_INITMSG, &im, QSE_SIZEOF(im)) <= -1) goto oops; + if (setsockopt (fd, SOL_SCTP, SCTP_INITMSG, &im, QSE_SIZEOF(im)) <= -1) + { + qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); + goto oops; + } QSE_MEMSET (&hb, 0, QSE_SIZEOF(hb)); hb.spp_flags = SPP_HB_ENABLE; hb.spp_hbinterval = 5000; hb.spp_pathmaxrxt = 1; - if (setsockopt (fd, SOL_SCTP, SCTP_PEER_ADDR_PARAMS, &hb, QSE_SIZEOF(hb)) <= -1) goto oops; + if (setsockopt (fd, SOL_SCTP, SCTP_PEER_ADDR_PARAMS, &hb, QSE_SIZEOF(hb)) <= -1) + { + qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); + goto oops; + } #endif } #endif @@ -1086,7 +1050,11 @@ bind_ok: goto oops; } - if (set_socket_nonblock (httpd, fd, 1) <= -1) goto oops; + if (qse_setscknonblock (fd, 1) <= -1) + { + qse_httpd_seterrnum (httpd, QSE_HTTPD_ESYSERR); + goto oops; + } server->handle = fd; return 0; @@ -1132,7 +1100,11 @@ static int server_accept ( if (flag >= 0) fcntl (fd, F_SETFD, flag | FD_CLOEXEC); #endif - if (set_socket_nonblock (httpd, fd, 1) <= -1) goto oops; + if (qse_setscknonblock (fd, 1) <= -1) + { + qse_httpd_seterrnum (httpd, QSE_HTTPD_ESYSERR); + goto oops; + } if (qse_skadtonwad (&addr, &client->remote_addr) <= -1) { @@ -1456,7 +1428,11 @@ static int peer_open (qse_httpd_t* httpd, qse_httpd_peer_t* peer) if (flag >= 0) fcntl (fd, F_SETFD, flag | FD_CLOEXEC); #endif - if (set_socket_nonblock (httpd, fd, 1) <= -1) goto oops; + if (qse_setscknonblock (fd, 1) <= -1) + { + qse_httpd_seterrnum (httpd, QSE_HTTPD_ESYSERR); + goto oops; + } if (peer->flags & QSE_HTTPD_PEER_SECURE) {