Feature #9330 » 0001-socket-avoid-redundant-fcntl-fd-F_GETFD-with-SOCK_CL.patch
ext/socket/init.c | ||
---|---|---|
return rb_assoc_new(str, addr);
|
||
}
|
||
/* returns true if SOCK_CLOEXEC is supported */
|
||
int rsock_detect_cloexec(int fd)
|
||
{
|
||
#ifdef SOCK_CLOEXEC
|
||
int flags = fcntl(fd, F_GETFD);
|
||
if (flags == -1)
|
||
rb_bug("rsock_detect_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
|
||
if (flags & FD_CLOEXEC)
|
||
return 1;
|
||
#endif
|
||
return 0;
|
||
}
|
||
static int
|
||
rsock_socket0(int domain, int type, int proto)
|
||
{
|
||
int ret;
|
||
#ifdef SOCK_CLOEXEC
|
||
static int try_sock_cloexec = 1;
|
||
if (try_sock_cloexec) {
|
||
static int cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
|
||
if (cloexec_state > 0) { /* common path, if SOCK_CLOEXEC is defined */
|
||
ret = socket(domain, type|SOCK_CLOEXEC, proto);
|
||
if (ret >= 0 && ret <= 2)
|
||
rb_maygvl_fd_fix_cloexec(ret);
|
||
return ret;
|
||
}
|
||
else if (cloexec_state < 0) { /* usually runs once only for detection */
|
||
ret = socket(domain, type|SOCK_CLOEXEC, proto);
|
||
if (ret == -1 && errno == EINVAL) {
|
||
if (ret >= 0) {
|
||
cloexec_state = rsock_detect_cloexec(ret);
|
||
if (cloexec_state == 0 || ret <= 2)
|
||
rb_maygvl_fd_fix_cloexec(ret);
|
||
return ret;
|
||
}
|
||
else if (ret == -1 && errno == EINVAL) {
|
||
/* SOCK_CLOEXEC is available since Linux 2.6.27. Linux 2.6.18 fails with EINVAL */
|
||
ret = socket(domain, type, proto);
|
||
if (ret != -1) {
|
||
try_sock_cloexec = 0;
|
||
cloexec_state = 0;
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
else { /* cloexec_state == 0 */
|
||
ret = socket(domain, type, proto);
|
||
}
|
||
#else
|
||
... | ... | |
if (ret == -1)
|
||
return -1;
|
||
rb_fd_fix_cloexec(ret);
|
||
rb_maygvl_fd_fix_cloexec(ret);
|
||
return ret;
|
||
ext/socket/rubysocket.h | ||
---|---|---|
#endif
|
||
int rsock_socket(int domain, int type, int proto);
|
||
int rsock_detect_cloexec(int fd);
|
||
VALUE rsock_init_sock(VALUE sock, int fd);
|
||
VALUE rsock_sock_s_socketpair(int argc, VALUE *argv, VALUE klass);
|
||
VALUE rsock_init_inetsock(VALUE sock, VALUE remote_host, VALUE remote_serv, VALUE local_host, VALUE local_serv, int type);
|
ext/socket/socket.c | ||
---|---|---|
int ret;
|
||
#ifdef SOCK_CLOEXEC
|
||
static int try_sock_cloexec = 1;
|
||
if (try_sock_cloexec) {
|
||
static int cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
|
||
if (cloexec_state > 0) { /* common path, if SOCK_CLOEXEC is defined */
|
||
ret = socketpair(domain, type|SOCK_CLOEXEC, protocol, sv);
|
||
if (ret == 0 && (sv[0] <= 2 || sv[1] <= 2)) {
|
||
goto fix_cloexec; /* highly unlikely */
|
||
}
|
||
return ret;
|
||
}
|
||
else if (cloexec_state < 0) { /* usually runs once only for detection */
|
||
ret = socketpair(domain, type|SOCK_CLOEXEC, protocol, sv);
|
||
if (ret == -1 && errno == EINVAL) {
|
||
if (ret == 0) {
|
||
cloexec_state = rsock_detect_cloexec(sv[0]);
|
||
if ((cloexec_state == 0) || (sv[0] <= 2 || sv[1] <= 2))
|
||
goto fix_cloexec;
|
||
return ret;
|
||
}
|
||
else if (ret == -1 && errno == EINVAL) {
|
||
/* SOCK_CLOEXEC is available since Linux 2.6.27. Linux 2.6.18 fails with EINVAL */
|
||
ret = socketpair(domain, type, protocol, sv);
|
||
if (ret != -1) {
|
||
... | ... | |
* So disable SOCK_CLOEXEC only if socketpair() succeeds without SOCK_CLOEXEC.
|
||
* Ex. Socket.pair(:UNIX, 0xff) fails with EINVAL.
|
||
*/
|
||
try_sock_cloexec = 0;
|
||
cloexec_state = 0;
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
else { /* cloexec_state == 0 */
|
||
ret = socketpair(domain, type, protocol, sv);
|
||
}
|
||
#else
|
||
... | ... | |
return -1;
|
||
}
|
||
rb_fd_fix_cloexec(sv[0]);
|
||
rb_fd_fix_cloexec(sv[1]);
|
||
fix_cloexec:
|
||
rb_maygvl_fd_fix_cloexec(sv[0]);
|
||
rb_maygvl_fd_fix_cloexec(sv[1]);
|
||
return ret;
|
||
}
|
||
... | ... | |
if (ret < 0) {
|
||
rb_sys_fail("socketpair(2)");
|
||
}
|
||
rb_fd_fix_cloexec(sp[0]);
|
||
rb_fd_fix_cloexec(sp[1]);
|
||
s1 = rsock_init_sock(rb_obj_alloc(klass), sp[0]);
|
||
s2 = rsock_init_sock(rb_obj_alloc(klass), sp[1]);
|