Merge commit '36d016afd663d34607c843d03371bedb71efa34e'
[mruby.git] / mrbgems / mruby-socket / src / socket.c
blobd819522292054f93e29f110761536c48355bbdea
1 /*
2 ** socket.c - Socket module
3 **
4 ** See Copyright Notice in mruby.h
5 */
7 #ifdef _WIN32
8 #define _WIN32_WINNT 0x0501
10 #include <winsock2.h>
11 #include <ws2tcpip.h>
12 #include <windows.h>
14 #define SHUT_RDWR SD_BOTH
15 #ifndef _SSIZE_T_DEFINED
16 typedef int ssize_t;
17 #endif
18 typedef int fsize_t;
19 #else
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <sys/un.h>
23 #include <netinet/in.h>
24 #include <netinet/tcp.h>
25 #include <arpa/inet.h>
26 #include <fcntl.h>
27 #include <netdb.h>
28 #include <unistd.h>
29 typedef size_t fsize_t;
30 #endif
32 #include <stddef.h>
33 #include <string.h>
35 #include "mruby.h"
36 #include "mruby/array.h"
37 #include "mruby/class.h"
38 #include "mruby/data.h"
39 #include "mruby/string.h"
40 #include "mruby/variable.h"
41 #include "error.h"
43 #include "mruby/ext/io.h"
45 #define E_SOCKET_ERROR (mrb_class_get(mrb, "SocketError"))
47 #if !defined(mrb_cptr)
48 #define mrb_cptr_value(m,p) mrb_voidp_value((m),(p))
49 #define mrb_cptr(o) mrb_voidp(o)
50 #define mrb_cptr_p(o) mrb_voidp_p(o)
51 #endif
53 #ifdef _WIN32
54 const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
56 if (af == AF_INET)
58 struct sockaddr_in in;
59 memset(&in, 0, sizeof(in));
60 in.sin_family = AF_INET;
61 memcpy(&in.sin_addr, src, sizeof(struct in_addr));
62 getnameinfo((struct sockaddr *)&in, sizeof(struct
63 sockaddr_in), dst, cnt, NULL, 0, NI_NUMERICHOST);
64 return dst;
66 else if (af == AF_INET6)
68 struct sockaddr_in6 in;
69 memset(&in, 0, sizeof(in));
70 in.sin6_family = AF_INET6;
71 memcpy(&in.sin6_addr, src, sizeof(struct in_addr6));
72 getnameinfo((struct sockaddr *)&in, sizeof(struct
73 sockaddr_in6), dst, cnt, NULL, 0, NI_NUMERICHOST);
74 return dst;
76 return NULL;
79 int inet_pton(int af, const char *src, void *dst)
81 struct addrinfo hints, *res, *ressave;
83 memset(&hints, 0, sizeof(struct addrinfo));
84 hints.ai_family = af;
86 if (getaddrinfo(src, NULL, &hints, &res) != 0)
88 printf("Couldn't resolve host %s\n", src);
89 return -1;
92 ressave = res;
94 while (res)
96 memcpy(dst, res->ai_addr, res->ai_addrlen);
97 res = res->ai_next;
100 freeaddrinfo(ressave);
101 return 0;
104 #endif
106 static mrb_value
107 mrb_addrinfo_getaddrinfo(mrb_state *mrb, mrb_value klass)
109 struct addrinfo hints, *res0, *res;
110 mrb_value ai, ary, family, lastai, nodename, protocol, sa, service, socktype;
111 mrb_int flags;
112 int arena_idx, error;
113 const char *hostname = NULL, *servname = NULL;
115 ary = mrb_ary_new(mrb);
116 arena_idx = mrb_gc_arena_save(mrb); /* ary must be on arena! */
118 family = socktype = protocol = mrb_nil_value();
119 flags = 0;
120 mrb_get_args(mrb, "oo|oooi", &nodename, &service, &family, &socktype, &protocol, &flags);
122 if (mrb_string_p(nodename)) {
123 hostname = mrb_str_to_cstr(mrb, nodename);
124 } else if (mrb_nil_p(nodename)) {
125 hostname = NULL;
126 } else {
127 mrb_raise(mrb, E_TYPE_ERROR, "nodename must be String or nil");
130 if (mrb_string_p(service)) {
131 servname = mrb_str_to_cstr(mrb, service);
132 } else if (mrb_fixnum_p(service)) {
133 servname = mrb_str_to_cstr(mrb, mrb_funcall(mrb, service, "to_s", 0));
134 } else if (mrb_nil_p(service)) {
135 servname = NULL;
136 } else {
137 mrb_raise(mrb, E_TYPE_ERROR, "service must be String, Fixnum, or nil");
140 memset(&hints, 0, sizeof(hints));
141 hints.ai_flags = (int)flags;
143 if (mrb_fixnum_p(family)) {
144 hints.ai_family = (int)mrb_fixnum(family);
147 if (mrb_fixnum_p(socktype)) {
148 hints.ai_socktype = (int)mrb_fixnum(socktype);
151 if (mrb_fixnum_p(protocol)) {
152 hints.ai_protocol = (int)mrb_fixnum(protocol);
155 if (mrb_fixnum_p(protocol)) {
156 hints.ai_protocol = mrb_fixnum(protocol);
159 lastai = mrb_cv_get(mrb, klass, mrb_intern_lit(mrb, "_lastai"));
160 if (mrb_cptr_p(lastai)) {
161 freeaddrinfo((struct addrinfo*)mrb_cptr(lastai));
162 mrb_cv_set(mrb, klass, mrb_intern_lit(mrb, "_lastai"), mrb_nil_value());
165 error = getaddrinfo(hostname, servname, &hints, &res0);
166 if (error) {
167 mrb_raisef(mrb, E_SOCKET_ERROR, "getaddrinfo: %S", mrb_str_new_cstr(mrb, gai_strerror(error)));
169 mrb_cv_set(mrb, klass, mrb_intern_lit(mrb, "_lastai"), mrb_cptr_value(mrb, res0));
171 for (res = res0; res != NULL; res = res->ai_next) {
172 sa = mrb_str_new(mrb, (char*)res->ai_addr, res->ai_addrlen);
173 ai = mrb_funcall(mrb, klass, "new", 4, sa, mrb_fixnum_value(res->ai_family), mrb_fixnum_value(res->ai_socktype), mrb_fixnum_value(res->ai_protocol));
174 mrb_ary_push(mrb, ary, ai);
175 mrb_gc_arena_restore(mrb, arena_idx);
178 freeaddrinfo(res0);
179 mrb_cv_set(mrb, klass, mrb_intern_lit(mrb, "_lastai"), mrb_nil_value());
181 return ary;
184 static mrb_value
185 mrb_addrinfo_getnameinfo(mrb_state *mrb, mrb_value self)
187 mrb_int flags;
188 mrb_value ary, host, sastr, serv;
189 int error;
191 flags = 0;
192 mrb_get_args(mrb, "|i", &flags);
193 host = mrb_str_buf_new(mrb, NI_MAXHOST);
194 serv = mrb_str_buf_new(mrb, NI_MAXSERV);
196 sastr = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@sockaddr"));
197 if (!mrb_string_p(sastr)) {
198 mrb_raise(mrb, E_SOCKET_ERROR, "invalid sockaddr");
200 error = getnameinfo((struct sockaddr *)RSTRING_PTR(sastr), (socklen_t)RSTRING_LEN(sastr), RSTRING_PTR(host), NI_MAXHOST, RSTRING_PTR(serv), NI_MAXSERV, (int)flags);
201 if (error != 0) {
202 mrb_raisef(mrb, E_SOCKET_ERROR, "getnameinfo: %s", gai_strerror(error));
204 ary = mrb_ary_new_capa(mrb, 2);
205 mrb_str_resize(mrb, host, strlen(RSTRING_PTR(host)));
206 mrb_ary_push(mrb, ary, host);
207 mrb_str_resize(mrb, serv, strlen(RSTRING_PTR(serv)));
208 mrb_ary_push(mrb, ary, serv);
209 return ary;
212 #ifndef _WIN32
213 static mrb_value
214 mrb_addrinfo_unix_path(mrb_state *mrb, mrb_value self)
216 mrb_value sastr;
218 sastr = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@sockaddr"));
219 if (((struct sockaddr *)RSTRING_PTR(sastr))->sa_family != AF_UNIX)
220 mrb_raise(mrb, E_SOCKET_ERROR, "need AF_UNIX address");
221 return mrb_str_new_cstr(mrb, ((struct sockaddr_un *)RSTRING_PTR(sastr))->sun_path);
223 #endif
225 static mrb_value
226 sa2addrlist(mrb_state *mrb, const struct sockaddr *sa, socklen_t salen)
228 mrb_value ary, host;
229 unsigned short port;
230 const char *afstr;
232 switch (sa->sa_family) {
233 case AF_INET:
234 afstr = "AF_INET";
235 port = ((struct sockaddr_in *)sa)->sin_port;
236 break;
237 case AF_INET6:
238 afstr = "AF_INET6";
239 port = ((struct sockaddr_in6 *)sa)->sin6_port;
240 break;
241 default:
242 mrb_raise(mrb, E_ARGUMENT_ERROR, "bad af");
243 return mrb_nil_value();
245 port = ntohs(port);
246 host = mrb_str_buf_new(mrb, NI_MAXHOST);
247 if (getnameinfo(sa, salen, RSTRING_PTR(host), NI_MAXHOST, NULL, 0, NI_NUMERICHOST) == -1)
248 mrb_sys_fail(mrb, "getnameinfo");
249 mrb_str_resize(mrb, host, strlen(RSTRING_PTR(host)));
250 ary = mrb_ary_new_capa(mrb, 4);
251 mrb_ary_push(mrb, ary, mrb_str_new_cstr(mrb, afstr));
252 mrb_ary_push(mrb, ary, mrb_fixnum_value(port));
253 mrb_ary_push(mrb, ary, host);
254 mrb_ary_push(mrb, ary, host);
255 return ary;
258 static int
259 socket_fd(mrb_state *mrb, mrb_value sock)
261 return (int)mrb_fixnum(mrb_funcall(mrb, sock, "fileno", 0));
264 static int
265 socket_family(int s)
267 struct sockaddr_storage ss;
268 socklen_t salen;
270 salen = sizeof(ss);
271 if (getsockname(s, (struct sockaddr *)&ss, &salen) == -1)
272 return AF_UNSPEC;
273 return ss.ss_family;
276 static mrb_value
277 mrb_basicsocket_getpeereid(mrb_state *mrb, mrb_value self)
279 #ifdef HAVE_GETPEEREID
280 mrb_value ary;
281 gid_t egid;
282 uid_t euid;
283 int s;
285 s = socket_fd(mrb, self);
286 if (getpeereid(s, &euid, &egid) != 0)
287 mrb_sys_fail(mrb, "getpeereid");
289 ary = mrb_ary_new_capa(mrb, 2);
290 mrb_ary_push(mrb, ary, mrb_fixnum_value((mrb_int)euid));
291 mrb_ary_push(mrb, ary, mrb_fixnum_value((mrb_int)egid));
292 return ary;
293 #else
294 mrb_raise(mrb, E_RUNTIME_ERROR, "getpeereid is not avaialble on this system");
295 return mrb_nil_value();
296 #endif
299 static mrb_value
300 mrb_basicsocket_getpeername(mrb_state *mrb, mrb_value self)
302 struct sockaddr_storage ss;
303 socklen_t salen;
305 salen = sizeof(ss);
306 if (getpeername(socket_fd(mrb, self), (struct sockaddr *)&ss, &salen) != 0)
307 mrb_sys_fail(mrb, "getpeername");
309 return mrb_str_new(mrb, (char*)&ss, salen);
312 static mrb_value
313 mrb_basicsocket_getsockname(mrb_state *mrb, mrb_value self)
315 struct sockaddr_storage ss;
316 socklen_t salen;
318 salen = sizeof(ss);
319 if (getsockname(socket_fd(mrb, self), (struct sockaddr *)&ss, &salen) != 0)
320 mrb_sys_fail(mrb, "getsockname");
322 return mrb_str_new(mrb, (char*)&ss, salen);
325 static mrb_value
326 mrb_basicsocket_getsockopt(mrb_state *mrb, mrb_value self)
328 char opt[8];
329 int s;
330 mrb_int family, level, optname;
331 mrb_value c, data;
332 socklen_t optlen;
334 mrb_get_args(mrb, "ii", &level, &optname);
335 s = socket_fd(mrb, self);
336 optlen = sizeof(opt);
337 if (getsockopt(s, (int)level, (int)optname, opt, &optlen) == -1)
338 mrb_sys_fail(mrb, "getsockopt");
339 c = mrb_const_get(mrb, mrb_obj_value(mrb_class_get(mrb, "Socket")), mrb_intern_lit(mrb, "Option"));
340 family = socket_family(s);
341 data = mrb_str_new(mrb, opt, optlen);
342 return mrb_funcall(mrb, c, "new", 4, mrb_fixnum_value(family), mrb_fixnum_value(level), mrb_fixnum_value(optname), data);
345 static mrb_value
346 mrb_basicsocket_recv(mrb_state *mrb, mrb_value self)
348 ssize_t n;
349 mrb_int maxlen, flags = 0;
350 mrb_value buf;
352 mrb_get_args(mrb, "i|i", &maxlen, &flags);
353 buf = mrb_str_buf_new(mrb, maxlen);
354 n = recv(socket_fd(mrb, self), RSTRING_PTR(buf), (fsize_t)maxlen, (int)flags);
355 if (n == -1)
356 mrb_sys_fail(mrb, "recv");
357 mrb_str_resize(mrb, buf, (mrb_int)n);
358 return buf;
361 static mrb_value
362 mrb_basicsocket_recvfrom(mrb_state *mrb, mrb_value self)
364 ssize_t n;
365 mrb_int maxlen, flags = 0;
366 mrb_value ary, buf, sa;
367 socklen_t socklen;
369 mrb_get_args(mrb, "i|i", &maxlen, &flags);
370 buf = mrb_str_buf_new(mrb, maxlen);
371 socklen = sizeof(struct sockaddr_storage);
372 sa = mrb_str_buf_new(mrb, socklen);
373 n = recvfrom(socket_fd(mrb, self), RSTRING_PTR(buf), (fsize_t)maxlen, (int)flags, (struct sockaddr *)RSTRING_PTR(sa), &socklen);
374 if (n == -1)
375 mrb_sys_fail(mrb, "recvfrom");
376 mrb_str_resize(mrb, buf, (mrb_int)n);
377 mrb_str_resize(mrb, sa, (mrb_int)socklen);
378 ary = mrb_ary_new_capa(mrb, 2);
379 mrb_ary_push(mrb, ary, buf);
380 mrb_ary_push(mrb, ary, sa);
381 return ary;
384 static mrb_value
385 mrb_basicsocket_send(mrb_state *mrb, mrb_value self)
387 ssize_t n;
388 mrb_int flags;
389 mrb_value dest, mesg;
391 dest = mrb_nil_value();
392 mrb_get_args(mrb, "Si|S", &mesg, &flags, &dest);
393 if (mrb_nil_p(dest)) {
394 n = send(socket_fd(mrb, self), RSTRING_PTR(mesg), (fsize_t)RSTRING_LEN(mesg), (int)flags);
395 } else {
396 n = sendto(socket_fd(mrb, self), RSTRING_PTR(mesg), (fsize_t)RSTRING_LEN(mesg), (int)flags, (const struct sockaddr*)RSTRING_PTR(dest), (fsize_t)RSTRING_LEN(dest));
398 if (n == -1)
399 mrb_sys_fail(mrb, "send");
400 return mrb_fixnum_value((mrb_int)n);
403 static mrb_value
404 mrb_basicsocket_setnonblock(mrb_state *mrb, mrb_value self)
406 int fd, flags;
407 mrb_bool nonblocking;
408 #ifdef _WIN32
409 u_long mode = 1;
410 #endif
412 mrb_get_args(mrb, "b", &nonblocking);
413 fd = socket_fd(mrb, self);
414 #ifdef _WIN32
415 flags = ioctlsocket(fd, FIONBIO, &mode);
416 if (flags != NO_ERROR)
417 mrb_sys_fail(mrb, "ioctlsocket");
418 #else
419 flags = fcntl(fd, F_GETFL, 0);
420 if (flags == 1)
421 mrb_sys_fail(mrb, "fcntl");
422 if (nonblocking)
423 flags |= O_NONBLOCK;
424 else
425 flags &= ~O_NONBLOCK;
426 if (fcntl(fd, F_SETFL, flags) == -1)
427 mrb_sys_fail(mrb, "fcntl");
428 #endif
429 return mrb_nil_value();
432 static mrb_value
433 mrb_basicsocket_setsockopt(mrb_state *mrb, mrb_value self)
435 int s;
436 mrb_int argc, level = 0, optname;
437 mrb_value optval, so;
439 argc = mrb_get_args(mrb, "o|io", &so, &optname, &optval);
440 if (argc == 3) {
441 if (!mrb_fixnum_p(so)) {
442 mrb_raise(mrb, E_ARGUMENT_ERROR, "level is not an integer");
444 level = mrb_fixnum(so);
445 if (mrb_string_p(optval)) {
446 /* that's good */
447 } else if (mrb_type(optval) == MRB_TT_TRUE || mrb_type(optval) == MRB_TT_FALSE) {
448 mrb_int i = mrb_test(optval) ? 1 : 0;
449 optval = mrb_str_new(mrb, (char*)&i, sizeof(i));
450 } else if (mrb_fixnum_p(optval)) {
451 if (optname == IP_MULTICAST_TTL || optname == IP_MULTICAST_LOOP) {
452 char uc = (char)mrb_fixnum(optval);
453 optval = mrb_str_new(mrb, &uc, sizeof(uc));
454 } else {
455 mrb_int i = mrb_fixnum(optval);
456 optval = mrb_str_new(mrb, (char*)&i, sizeof(i));
458 } else {
459 mrb_raise(mrb, E_ARGUMENT_ERROR, "optval should be true, false, an integer, or a string");
461 } else if (argc == 1) {
462 if (strcmp(mrb_obj_classname(mrb, so), "Socket::Option") != 0)
463 mrb_raisef(mrb, E_ARGUMENT_ERROR, "not an instance of Socket::Option");
464 level = mrb_fixnum(mrb_funcall(mrb, so, "level", 0));
465 optname = mrb_fixnum(mrb_funcall(mrb, so, "optname", 0));
466 optval = mrb_funcall(mrb, so, "data", 0);
467 } else {
468 mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%d for 3)", argc);
471 s = socket_fd(mrb, self);
472 if (setsockopt(s, (int)level, (int)optname, RSTRING_PTR(optval), (socklen_t)RSTRING_LEN(optval)) == -1)
473 mrb_sys_fail(mrb, "setsockopt");
474 return mrb_fixnum_value(0);
477 static mrb_value
478 mrb_basicsocket_shutdown(mrb_state *mrb, mrb_value self)
480 mrb_int how = SHUT_RDWR;
482 mrb_get_args(mrb, "|i", &how);
483 if (shutdown(socket_fd(mrb, self), (int)how) != 0)
484 mrb_sys_fail(mrb, "shutdown");
485 return mrb_fixnum_value(0);
488 static mrb_value
489 mrb_basicsocket_set_is_socket(mrb_state *mrb, mrb_value self)
491 mrb_bool b;
492 struct mrb_io *io_p;
493 mrb_get_args(mrb, "b", &b);
495 io_p = (struct mrb_io*)DATA_PTR(self);
496 if (io_p) {
497 io_p->is_socket = b;
500 return mrb_bool_value(b);
503 static mrb_value
504 mrb_ipsocket_ntop(mrb_state *mrb, mrb_value klass)
506 mrb_int af, n;
507 char *addr, buf[50];
509 mrb_get_args(mrb, "is", &af, &addr, &n);
510 if ((af == AF_INET && n != 4) || (af == AF_INET6 && n != 16))
511 mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid address");
512 if (inet_ntop((int)af, addr, buf, sizeof(buf)) == NULL)
513 mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid address");
514 return mrb_str_new_cstr(mrb, buf);
517 static mrb_value
518 mrb_ipsocket_pton(mrb_state *mrb, mrb_value klass)
520 mrb_int af, n;
521 char *bp, buf[50];
523 mrb_get_args(mrb, "is", &af, &bp, &n);
524 if ((size_t)n > sizeof(buf) - 1)
525 mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid address");
526 memcpy(buf, bp, n);
527 buf[n] = '\0';
529 if (af == AF_INET) {
530 struct in_addr in;
531 if (inet_pton(AF_INET, buf, (void *)&in.s_addr) != 1)
532 goto invalid;
533 return mrb_str_new(mrb, (char*)&in.s_addr, 4);
534 } else if (af == AF_INET6) {
535 struct in6_addr in6;
536 if (inet_pton(AF_INET6, buf, (void *)&in6.s6_addr) != 1)
537 goto invalid;
538 return mrb_str_new(mrb, (char*)&in6.s6_addr, 16);
539 } else
540 mrb_raise(mrb, E_ARGUMENT_ERROR, "unsupported address family");
542 invalid:
543 mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid address");
544 return mrb_nil_value(); /* dummy */
547 static mrb_value
548 mrb_ipsocket_recvfrom(mrb_state *mrb, mrb_value self)
550 struct sockaddr_storage ss;
551 socklen_t socklen;
552 mrb_value a, buf, pair;
553 mrb_int flags, maxlen;
554 ssize_t n;
555 int fd;
557 fd = socket_fd(mrb, self);
558 flags = 0;
559 mrb_get_args(mrb, "i|i", &maxlen, &flags);
560 buf = mrb_str_buf_new(mrb, maxlen);
561 socklen = sizeof(ss);
562 n = recvfrom(fd, RSTRING_PTR(buf), (fsize_t)maxlen, (int)flags,
563 (struct sockaddr *)&ss, &socklen);
564 if (n == -1) {
565 mrb_sys_fail(mrb, "recvfrom");
567 mrb_str_resize(mrb, buf, (mrb_int)n);
568 a = sa2addrlist(mrb, (struct sockaddr *)&ss, socklen);
569 pair = mrb_ary_new_capa(mrb, 2);
570 mrb_ary_push(mrb, pair, buf);
571 mrb_ary_push(mrb, pair, a);
572 return pair;
575 static mrb_value
576 mrb_socket_gethostname(mrb_state *mrb, mrb_value cls)
578 mrb_value buf;
579 size_t bufsize;
581 #ifdef HOST_NAME_MAX
582 bufsize = HOST_NAME_MAX + 1;
583 #else
584 bufsize = 256;
585 #endif
586 buf = mrb_str_buf_new(mrb, (mrb_int)bufsize);
587 if (gethostname(RSTRING_PTR(buf), (fsize_t)bufsize) != 0)
588 mrb_sys_fail(mrb, "gethostname");
589 mrb_str_resize(mrb, buf, (mrb_int)strlen(RSTRING_PTR(buf)));
590 return buf;
593 static mrb_value
594 mrb_socket_accept(mrb_state *mrb, mrb_value klass)
596 mrb_value ary, sastr;
597 int s1;
598 mrb_int s0;
599 socklen_t socklen;
601 mrb_get_args(mrb, "i", &s0);
602 socklen = sizeof(struct sockaddr_storage);
603 sastr = mrb_str_buf_new(mrb, socklen);
604 s1 = (int)accept(s0, (struct sockaddr *)RSTRING_PTR(sastr), &socklen);
605 if (s1 == -1) {
606 mrb_sys_fail(mrb, "accept");
608 // XXX: possible descriptor leakage here!
609 mrb_str_resize(mrb, sastr, socklen);
610 ary = mrb_ary_new_capa(mrb, 2);
611 mrb_ary_push(mrb, ary, mrb_fixnum_value(s1));
612 mrb_ary_push(mrb, ary, sastr);
613 return ary;
616 static mrb_value
617 mrb_socket_bind(mrb_state *mrb, mrb_value klass)
619 mrb_value sastr;
620 mrb_int s;
622 mrb_get_args(mrb, "iS", &s, &sastr);
623 if (bind((int)s, (struct sockaddr *)RSTRING_PTR(sastr), (socklen_t)RSTRING_LEN(sastr)) == -1) {
624 mrb_sys_fail(mrb, "bind");
626 return mrb_nil_value();
629 static mrb_value
630 mrb_socket_connect(mrb_state *mrb, mrb_value klass)
632 mrb_value sastr;
633 mrb_int s;
635 mrb_get_args(mrb, "iS", &s, &sastr);
636 if (connect((int)s, (struct sockaddr *)RSTRING_PTR(sastr), (socklen_t)RSTRING_LEN(sastr)) == -1) {
637 mrb_sys_fail(mrb, "connect");
639 return mrb_nil_value();
642 static mrb_value
643 mrb_socket_listen(mrb_state *mrb, mrb_value klass)
645 mrb_int backlog, s;
647 mrb_get_args(mrb, "ii", &s, &backlog);
648 if (listen((int)s, (int)backlog) == -1) {
649 mrb_sys_fail(mrb, "listen");
651 return mrb_nil_value();
654 static mrb_value
655 mrb_socket_sockaddr_family(mrb_state *mrb, mrb_value klass)
657 mrb_value sa;
659 mrb_get_args(mrb, "S", &sa);
660 #ifdef __linux__
661 if ((size_t)RSTRING_LEN(sa) < offsetof(struct sockaddr, sa_family) + sizeof(sa_family_t)) {
662 mrb_raisef(mrb, E_SOCKET_ERROR, "invalid sockaddr (too short)");
664 #else
665 if ((size_t)RSTRING_LEN(sa) < sizeof(struct sockaddr)) {
666 mrb_raisef(mrb, E_SOCKET_ERROR, "invalid sockaddr (too short)");
668 #endif
669 return mrb_fixnum_value(((struct sockaddr *)RSTRING_PTR(sa))->sa_family);
672 static mrb_value
673 mrb_socket_sockaddr_un(mrb_state *mrb, mrb_value klass)
675 #ifdef _WIN32
676 mrb_raise(mrb, E_NOTIMP_ERROR, "sockaddr_un unsupported on Windows");
677 return mrb_nil_value();
678 #else
679 struct sockaddr_un *sunp;
680 mrb_value path, s;
682 mrb_get_args(mrb, "S", &path);
683 if ((size_t)RSTRING_LEN(path) > sizeof(sunp->sun_path) - 1) {
684 mrb_raisef(mrb, E_ARGUMENT_ERROR, "too long unix socket path (max: %ubytes)", (unsigned int)sizeof(sunp->sun_path) - 1);
686 s = mrb_str_buf_new(mrb, sizeof(struct sockaddr_un));
687 sunp = (struct sockaddr_un *)RSTRING_PTR(s);
688 sunp->sun_family = AF_UNIX;
689 memcpy(sunp->sun_path, RSTRING_PTR(path), RSTRING_LEN(path));
690 sunp->sun_path[RSTRING_LEN(path)] = '\0';
691 mrb_str_resize(mrb, s, sizeof(struct sockaddr_un));
692 return s;
693 #endif
696 static mrb_value
697 mrb_socket_socketpair(mrb_state *mrb, mrb_value klass)
699 #ifdef _WIN32
700 mrb_raise(mrb, E_NOTIMP_ERROR, "socketpair unsupported on Windows");
701 return mrb_nil_value();
702 #else
703 mrb_value ary;
704 mrb_int domain, type, protocol;
705 int sv[2];
707 mrb_get_args(mrb, "iii", &domain, &type, &protocol);
708 if (socketpair(domain, type, protocol, sv) == -1) {
709 mrb_sys_fail(mrb, "socketpair");
711 // XXX: possible descriptor leakage here!
712 ary = mrb_ary_new_capa(mrb, 2);
713 mrb_ary_push(mrb, ary, mrb_fixnum_value(sv[0]));
714 mrb_ary_push(mrb, ary, mrb_fixnum_value(sv[1]));
715 return ary;
716 #endif
719 static mrb_value
720 mrb_socket_socket(mrb_state *mrb, mrb_value klass)
722 mrb_int domain, type, protocol;
723 int s;
725 mrb_get_args(mrb, "iii", &domain, &type, &protocol);
726 s = (int)socket((int)domain, (int)type, (int)protocol);
727 if (s == -1)
728 mrb_sys_fail(mrb, "socket");
729 return mrb_fixnum_value(s);
732 static mrb_value
733 mrb_tcpsocket_allocate(mrb_state *mrb, mrb_value klass)
735 struct RClass *c = mrb_class_ptr(klass);
736 enum mrb_vtype ttype = MRB_INSTANCE_TT(c);
738 /* copied from mrb_instance_alloc() */
739 if (ttype == 0) ttype = MRB_TT_OBJECT;
740 return mrb_obj_value((struct RObject*)mrb_obj_alloc(mrb, ttype, c));
743 /* Windows overrides for IO methods on BasicSocket objects.
744 * This is because sockets on Windows are not the same as file
745 * descriptors, and thus functions which operate on file descriptors
746 * will break on socket descriptors.
748 #ifdef _WIN32
749 static mrb_value
750 mrb_win32_basicsocket_close(mrb_state *mrb, mrb_value self)
752 if (closesocket(socket_fd(mrb, self)) != NO_ERROR)
753 mrb_raise(mrb, E_SOCKET_ERROR, "closesocket unsuccessful");
754 return mrb_nil_value();
757 #define E_EOF_ERROR (mrb_class_get(mrb, "EOFError"))
758 static mrb_value
759 mrb_win32_basicsocket_sysread(mrb_state *mrb, mrb_value self)
761 int sd, ret;
762 mrb_value buf = mrb_nil_value();
763 mrb_int maxlen;
765 mrb_get_args(mrb, "i|S", &maxlen, &buf);
766 if (maxlen < 0) {
767 return mrb_nil_value();
770 if (mrb_nil_p(buf)) {
771 buf = mrb_str_new(mrb, NULL, maxlen);
773 if (RSTRING_LEN(buf) != maxlen) {
774 buf = mrb_str_resize(mrb, buf, maxlen);
777 sd = socket_fd(mrb, self);
778 ret = recv(sd, RSTRING_PTR(buf), (int)maxlen, 0);
780 switch (ret) {
781 case 0: /* EOF */
782 if (maxlen == 0) {
783 buf = mrb_str_new_cstr(mrb, "");
784 } else {
785 mrb_raise(mrb, E_EOF_ERROR, "sysread failed: End of File");
787 break;
788 case SOCKET_ERROR: /* Error */
789 mrb_sys_fail(mrb, "recv");
790 break;
791 default:
792 if (RSTRING_LEN(buf) != ret) {
793 buf = mrb_str_resize(mrb, buf, ret);
795 break;
798 return buf;
801 static mrb_value
802 mrb_win32_basicsocket_sysseek(mrb_state *mrb, mrb_value self)
804 mrb_raise(mrb, E_NOTIMP_ERROR, "sysseek not implemented for windows sockets");
805 return mrb_nil_value();
808 static mrb_value
809 mrb_win32_basicsocket_syswrite(mrb_state *mrb, mrb_value self)
811 int n;
812 SOCKET sd;
813 mrb_value str;
815 sd = socket_fd(mrb, self);
816 mrb_get_args(mrb, "S", &str);
817 n = send(sd, RSTRING_PTR(str), (int)RSTRING_LEN(str), 0);
818 if (n == SOCKET_ERROR)
819 mrb_sys_fail(mrb, "send");
820 return mrb_fixnum_value(n);
823 #endif
825 void
826 mrb_mruby_socket_gem_init(mrb_state* mrb)
828 struct RClass *io, *ai, *sock, *bsock, *ipsock, *tcpsock;
829 struct RClass *constants;
831 #ifdef _WIN32
832 WSADATA wsaData;
833 int result;
834 result = WSAStartup(MAKEWORD(2,2), &wsaData);
835 if (result != NO_ERROR)
836 mrb_raise(mrb, E_RUNTIME_ERROR, "WSAStartup failed");
837 #endif
839 ai = mrb_define_class(mrb, "Addrinfo", mrb->object_class);
840 mrb_mod_cv_set(mrb, ai, mrb_intern_lit(mrb, "_lastai"), mrb_nil_value());
841 mrb_define_class_method(mrb, ai, "getaddrinfo", mrb_addrinfo_getaddrinfo, MRB_ARGS_REQ(2)|MRB_ARGS_OPT(4));
842 mrb_define_method(mrb, ai, "getnameinfo", mrb_addrinfo_getnameinfo, MRB_ARGS_OPT(1));
843 #ifndef _WIN32
844 mrb_define_method(mrb, ai, "unix_path", mrb_addrinfo_unix_path, MRB_ARGS_NONE());
845 #endif
847 io = mrb_class_get(mrb, "IO");
849 bsock = mrb_define_class(mrb, "BasicSocket", io);
850 mrb_define_method(mrb, bsock, "_recvfrom", mrb_basicsocket_recvfrom, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
851 mrb_define_method(mrb, bsock, "_setnonblock", mrb_basicsocket_setnonblock, MRB_ARGS_REQ(1));
852 mrb_define_method(mrb, bsock, "getpeereid", mrb_basicsocket_getpeereid, MRB_ARGS_NONE());
853 mrb_define_method(mrb, bsock, "getpeername", mrb_basicsocket_getpeername, MRB_ARGS_NONE());
854 mrb_define_method(mrb, bsock, "getsockname", mrb_basicsocket_getsockname, MRB_ARGS_NONE());
855 mrb_define_method(mrb, bsock, "getsockopt", mrb_basicsocket_getsockopt, MRB_ARGS_REQ(2));
856 mrb_define_method(mrb, bsock, "recv", mrb_basicsocket_recv, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
857 // #recvmsg(maxlen, flags=0)
858 mrb_define_method(mrb, bsock, "send", mrb_basicsocket_send, MRB_ARGS_REQ(2)|MRB_ARGS_OPT(1));
859 // #sendmsg
860 // #sendmsg_nonblock
861 mrb_define_method(mrb, bsock, "setsockopt", mrb_basicsocket_setsockopt, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(2));
862 mrb_define_method(mrb, bsock, "shutdown", mrb_basicsocket_shutdown, MRB_ARGS_OPT(1));
863 mrb_define_method(mrb, bsock, "_is_socket=", mrb_basicsocket_set_is_socket, MRB_ARGS_REQ(1));
865 ipsock = mrb_define_class(mrb, "IPSocket", bsock);
866 mrb_define_class_method(mrb, ipsock, "ntop", mrb_ipsocket_ntop, MRB_ARGS_REQ(1));
867 mrb_define_class_method(mrb, ipsock, "pton", mrb_ipsocket_pton, MRB_ARGS_REQ(2));
868 mrb_define_method(mrb, ipsock, "recvfrom", mrb_ipsocket_recvfrom, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
870 tcpsock = mrb_define_class(mrb, "TCPSocket", ipsock);
871 mrb_define_class_method(mrb, tcpsock, "_allocate", mrb_tcpsocket_allocate, MRB_ARGS_NONE());
872 mrb_define_class(mrb, "TCPServer", tcpsock);
874 mrb_define_class(mrb, "UDPSocket", ipsock);
875 //#recvfrom_nonblock
877 sock = mrb_define_class(mrb, "Socket", bsock);
878 mrb_define_class_method(mrb, sock, "_accept", mrb_socket_accept, MRB_ARGS_REQ(1));
879 mrb_define_class_method(mrb, sock, "_bind", mrb_socket_bind, MRB_ARGS_REQ(3));
880 mrb_define_class_method(mrb, sock, "_connect", mrb_socket_connect, MRB_ARGS_REQ(3));
881 mrb_define_class_method(mrb, sock, "_listen", mrb_socket_listen, MRB_ARGS_REQ(2));
882 mrb_define_class_method(mrb, sock, "_sockaddr_family", mrb_socket_sockaddr_family, MRB_ARGS_REQ(1));
883 mrb_define_class_method(mrb, sock, "_socket", mrb_socket_socket, MRB_ARGS_REQ(3));
884 //mrb_define_class_method(mrb, sock, "gethostbyaddr", mrb_socket_gethostbyaddr, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
885 //mrb_define_class_method(mrb, sock, "gethostbyname", mrb_socket_gethostbyname, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
886 mrb_define_class_method(mrb, sock, "gethostname", mrb_socket_gethostname, MRB_ARGS_NONE());
887 //mrb_define_class_method(mrb, sock, "getservbyname", mrb_socket_getservbyname, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
888 //mrb_define_class_method(mrb, sock, "getservbyport", mrb_socket_getservbyport, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
889 mrb_define_class_method(mrb, sock, "sockaddr_un", mrb_socket_sockaddr_un, MRB_ARGS_REQ(1));
890 mrb_define_class_method(mrb, sock, "socketpair", mrb_socket_socketpair, MRB_ARGS_REQ(3));
891 //mrb_define_method(mrb, sock, "sysaccept", mrb_socket_accept, MRB_ARGS_NONE());
893 #ifndef _WIN32
894 mrb_define_class(mrb, "UNIXSocket", bsock);
895 //mrb_define_class_method(mrb, usock, "pair", mrb_unixsocket_open, MRB_ARGS_OPT(2));
896 //mrb_define_class_method(mrb, usock, "socketpair", mrb_unixsocket_open, MRB_ARGS_OPT(2));
898 //mrb_define_method(mrb, usock, "recv_io", mrb_unixsocket_peeraddr, MRB_ARGS_NONE());
899 //mrb_define_method(mrb, usock, "recvfrom", mrb_unixsocket_peeraddr, MRB_ARGS_NONE());
900 //mrb_define_method(mrb, usock, "send_io", mrb_unixsocket_peeraddr, MRB_ARGS_NONE());
901 #endif
903 /* Windows IO Method Overrides on BasicSocket */
904 #ifdef _WIN32
905 mrb_define_method(mrb, bsock, "close", mrb_win32_basicsocket_close, MRB_ARGS_NONE());
906 mrb_define_method(mrb, bsock, "sysread", mrb_win32_basicsocket_sysread, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
907 mrb_define_method(mrb, bsock, "sysseek", mrb_win32_basicsocket_sysseek, MRB_ARGS_REQ(1));
908 mrb_define_method(mrb, bsock, "syswrite", mrb_win32_basicsocket_syswrite, MRB_ARGS_REQ(1));
909 #endif
911 constants = mrb_define_module_under(mrb, sock, "Constants");
913 #define define_const(SYM) \
914 do { \
915 mrb_define_const(mrb, constants, #SYM, mrb_fixnum_value(SYM)); \
916 } while (0)
918 #include "const.cstub"
921 void
922 mrb_mruby_socket_gem_final(mrb_state* mrb)
924 mrb_value ai;
925 ai = mrb_mod_cv_get(mrb, mrb_class_get(mrb, "Addrinfo"), mrb_intern_lit(mrb, "_lastai"));
926 if (mrb_cptr_p(ai)) {
927 freeaddrinfo((struct addrinfo*)mrb_cptr(ai));
929 #ifdef _WIN32
930 WSACleanup();
931 #endif