2 #include "sock_for_fd.h"
4 static void close_fail(int fd
, const char *msg
)
6 int saved_errno
= errno
;
13 # define MY_SOCK_STREAM (SOCK_STREAM|SOCK_NONBLOCK)
15 # define MY_SOCK_STREAM SOCK_STREAM
16 #endif /* ! SOCK_NONBLOCK */
19 my_connect(VALUE klass
, int io_wait
, int domain
, void *addr
, socklen_t addrlen
)
21 int fd
= socket(domain
, MY_SOCK_STREAM
, 0);
32 fd
= socket(domain
, MY_SOCK_STREAM
, 0);
35 rb_sys_fail("socket");
39 if (fcntl(fd
, F_SETFL
, O_RDWR
| O_NONBLOCK
) == -1)
40 close_fail(fd
, "fcntl(F_SETFL, O_RDWR | O_NONBLOCK)");
41 #endif /* SOCK_NONBLOCK */
43 if (connect(fd
, addr
, addrlen
) == -1) {
44 if (errno
== EINPROGRESS
) {
45 VALUE io
= sock_for_fd(klass
, fd
);
49 (void)kgio_call_wait_writable(io
);
53 close_fail(fd
, "connect");
55 return sock_for_fd(klass
, fd
);
58 static VALUE
tcp_connect(VALUE klass
, VALUE ip
, VALUE port
, int io_wait
)
60 struct addrinfo hints
;
61 struct sockaddr_storage addr
;
65 const char *ipname
= StringValuePtr(ip
);
67 unsigned uport
= FIX2UINT(port
);
69 rc
= snprintf(ipport
, sizeof(ipport
), "%u", uport
);
70 if (rc
>= (int)sizeof(ipport
) || rc
<= 0)
71 rb_raise(rb_eArgError
, "invalid TCP port: %u", uport
);
72 hints
.ai_family
= AF_UNSPEC
;
73 hints
.ai_socktype
= SOCK_STREAM
;
74 hints
.ai_protocol
= IPPROTO_TCP
;
75 /* disallow non-deterministic DNS lookups */
76 hints
.ai_flags
= AI_NUMERICHOST
| AI_NUMERICSERV
;
78 rc
= getaddrinfo(ipname
, ipport
, &hints
, &res
);
80 rb_raise(rb_eArgError
, "getaddrinfo(%s:%s): %s",
81 ipname
, ipport
, gai_strerror(rc
));
83 /* copy needed data and free ASAP to avoid needing rb_ensure */
84 hints
.ai_family
= res
->ai_family
;
85 hints
.ai_addrlen
= res
->ai_addrlen
;
86 memcpy(&addr
, res
->ai_addr
, res
->ai_addrlen
);
89 return my_connect(klass
, io_wait
, hints
.ai_family
,
90 &addr
, hints
.ai_addrlen
);
96 * Kgio::TCPSocket.new('127.0.0.1', 80) -> socket
98 * Creates a new Kgio::TCPSocket object and initiates a
99 * non-blocking connection.
101 * This may block and call any method defined to kgio_wait_writable.
103 * Unlike the TCPSocket.new in Ruby, this does NOT perform DNS
104 * lookups (which is subject to a different set of timeouts and
105 * best handled elsewhere).
107 static VALUE
kgio_tcp_connect(VALUE klass
, VALUE ip
, VALUE port
)
109 return tcp_connect(klass
, ip
, port
, 1);
115 * Kgio::TCPSocket.start('127.0.0.1', 80) -> socket
117 * Creates a new Kgio::TCPSocket object and initiates a
118 * non-blocking connection. The caller should select/poll
119 * on the socket for writability before attempting to write
120 * or optimistically attempt a write and handle :wait_writable
123 * Unlike the TCPSocket.new in Ruby, this does NOT perform DNS
124 * lookups (which is subject to a different set of timeouts and
125 * best handled elsewhere).
127 static VALUE
kgio_tcp_start(VALUE klass
, VALUE ip
, VALUE port
)
129 return tcp_connect(klass
, ip
, port
, 0);
132 static VALUE
unix_connect(VALUE klass
, VALUE path
, int io_wait
)
134 struct sockaddr_un addr
= { 0 };
138 len
= RSTRING_LEN(path
);
139 if ((long)sizeof(addr
.sun_path
) <= len
)
140 rb_raise(rb_eArgError
,
141 "too long unix socket path (max: %dbytes)",
142 (int)sizeof(addr
.sun_path
)-1);
144 memcpy(addr
.sun_path
, RSTRING_PTR(path
), len
);
145 addr
.sun_family
= AF_UNIX
;
147 return my_connect(klass
, io_wait
, PF_UNIX
, &addr
, sizeof(addr
));
153 * Kgio::UNIXSocket.new("/path/to/unix/socket") -> socket
155 * Creates a new Kgio::UNIXSocket object and initiates a
156 * non-blocking connection.
158 * This may block and call any method defined to kgio_wait_writable.
160 static VALUE
kgio_unix_connect(VALUE klass
, VALUE path
)
162 return unix_connect(klass
, path
, 1);
168 * Kgio::UNIXSocket.start("/path/to/unix/socket") -> socket
170 * Creates a new Kgio::UNIXSocket object and initiates a
171 * non-blocking connection. The caller should select/poll
172 * on the socket for writability before attempting to write
173 * or optimistically attempt a write and handle :wait_writable
176 static VALUE
kgio_unix_start(VALUE klass
, VALUE path
)
178 return unix_connect(klass
, path
, 0);
181 static VALUE
stream_connect(VALUE klass
, VALUE addr
, int io_wait
)
185 struct sockaddr
*sockaddr
;
187 if (TYPE(addr
) == T_STRING
) {
188 sockaddr
= (struct sockaddr
*)(RSTRING_PTR(addr
));
189 addrlen
= (socklen_t
)RSTRING_LEN(addr
);
191 rb_raise(rb_eTypeError
, "invalid address");
193 switch (((struct sockaddr_storage
*)(sockaddr
))->ss_family
) {
194 case AF_UNIX
: domain
= PF_UNIX
; break;
195 case AF_INET
: domain
= PF_INET
; break;
196 case AF_INET6
: domain
= PF_INET6
; break;
198 rb_raise(rb_eArgError
, "invalid address family");
201 return my_connect(klass
, io_wait
, domain
, sockaddr
, addrlen
);
206 * addr = Socket.pack_sockaddr_in(80, 'example.com')
207 * Kgio::Socket.connect(addr) -> socket
209 * addr = Socket.pack_sockaddr_un("/path/to/unix/socket")
210 * Kgio::Socket.connect(addr) -> socket
212 * Creates a generic Kgio::Socket object and initiates a
213 * non-blocking connection.
215 * This may block and call any method assigned to kgio_wait_writable.
217 static VALUE
kgio_connect(VALUE klass
, VALUE addr
)
219 return stream_connect(klass
, addr
, 1);
224 * addr = Socket.pack_sockaddr_in(80, 'example.com')
225 * Kgio::Socket.start(addr) -> socket
227 * addr = Socket.pack_sockaddr_un("/path/to/unix/socket")
228 * Kgio::Socket.start(addr) -> socket
230 * Creates a generic Kgio::Socket object and initiates a
231 * non-blocking connection. The caller should select/poll
232 * on the socket for writability before attempting to write
233 * or optimistically attempt a write and handle :wait_writable
236 static VALUE
kgio_start(VALUE klass
, VALUE addr
)
238 return stream_connect(klass
, addr
, 0);
241 void init_kgio_connect(void)
243 VALUE mKgio
= rb_define_module("Kgio");
244 VALUE cSocket
= rb_const_get(rb_cObject
, rb_intern("Socket"));
245 VALUE mSocketMethods
= rb_const_get(mKgio
, rb_intern("SocketMethods"));
246 VALUE cKgio_Socket
, cTCPSocket
, cUNIXSocket
;
249 * Document-class: Kgio::Socket
251 * A generic socket class with Kgio::SocketMethods included.
252 * This is returned by all Kgio methods that accept(2) a connected
255 cKgio_Socket
= rb_define_class_under(mKgio
, "Socket", cSocket
);
256 rb_include_module(cKgio_Socket
, mSocketMethods
);
257 rb_define_singleton_method(cKgio_Socket
, "new", kgio_connect
, 1);
258 rb_define_singleton_method(cKgio_Socket
, "start", kgio_start
, 1);
261 * Document-class: Kgio::TCPSocket
263 * Kgio::TCPSocket should be used in place of the plain TCPSocket
264 * when kgio_* methods are needed.
266 cTCPSocket
= rb_const_get(rb_cObject
, rb_intern("TCPSocket"));
267 cTCPSocket
= rb_define_class_under(mKgio
, "TCPSocket", cTCPSocket
);
268 rb_include_module(cTCPSocket
, mSocketMethods
);
269 rb_define_singleton_method(cTCPSocket
, "new", kgio_tcp_connect
, 2);
270 rb_define_singleton_method(cTCPSocket
, "start", kgio_tcp_start
, 2);
273 * Document-class: Kgio::UNIXSocket
275 * Kgio::UNIXSocket should be used in place of the plain UNIXSocket
276 * when kgio_* methods are needed.
278 cUNIXSocket
= rb_const_get(rb_cObject
, rb_intern("UNIXSocket"));
279 cUNIXSocket
= rb_define_class_under(mKgio
, "UNIXSocket", cUNIXSocket
);
280 rb_include_module(cUNIXSocket
, mSocketMethods
);
281 rb_define_singleton_method(cUNIXSocket
, "new", kgio_unix_connect
, 1);
282 rb_define_singleton_method(cUNIXSocket
, "start", kgio_unix_start
, 1);