doc: fully RDoc all methods and classes
[kgio.git] / ext / kgio / connect.c
blob15458530f02f90dbfda457b92c8a3fa46a9632e2
1 #include "kgio.h"
2 #include "sock_for_fd.h"
4 static void close_fail(int fd, const char *msg)
6 int saved_errno = errno;
7 (void)close(fd);
8 errno = saved_errno;
9 rb_sys_fail(msg);
12 #ifdef SOCK_NONBLOCK
13 # define MY_SOCK_STREAM (SOCK_STREAM|SOCK_NONBLOCK)
14 #else
15 # define MY_SOCK_STREAM SOCK_STREAM
16 #endif /* ! SOCK_NONBLOCK */
18 static VALUE
19 my_connect(VALUE klass, int io_wait, int domain, void *addr, socklen_t addrlen)
21 int fd = socket(domain, MY_SOCK_STREAM, 0);
23 if (fd == -1) {
24 switch (errno) {
25 case EMFILE:
26 case ENFILE:
27 #ifdef ENOBUFS
28 case ENOBUFS:
29 #endif /* ENOBUFS */
30 errno = 0;
31 rb_gc();
32 fd = socket(domain, MY_SOCK_STREAM, 0);
34 if (fd == -1)
35 rb_sys_fail("socket");
38 #ifndef SOCK_NONBLOCK
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);
47 if (io_wait) {
48 errno = EAGAIN;
49 (void)kgio_call_wait_writable(io);
51 return 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;
62 int rc;
63 struct addrinfo *res;
64 VALUE sock;
65 const char *ipname = StringValuePtr(ip);
66 char ipport[6];
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);
79 if (rc != 0)
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);
87 freeaddrinfo(res);
89 return my_connect(klass, io_wait, hints.ai_family,
90 &addr, hints.ai_addrlen);
94 * call-seq:
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);
113 * call-seq:
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
121 * or Errno::EAGAIN.
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 };
135 long len;
137 StringValue(path);
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));
151 * call-seq:
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);
166 * call-seq:
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
174 * or Errno::EAGAIN.
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)
183 int domain;
184 socklen_t addrlen;
185 struct sockaddr *sockaddr;
187 if (TYPE(addr) == T_STRING) {
188 sockaddr = (struct sockaddr *)(RSTRING_PTR(addr));
189 addrlen = (socklen_t)RSTRING_LEN(addr);
190 } else {
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;
197 default:
198 rb_raise(rb_eArgError, "invalid address family");
201 return my_connect(klass, io_wait, domain, sockaddr, addrlen);
204 /* call-seq:
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);
222 /* call-seq:
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
234 * or Errno::EAGAIN.
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
253 * stream socket.
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);
283 init_sock_for_fd();