Set protocol of AddrInfo
[mruby.git] / src / socket.c
blobd0df1c2f8a54605affdf6237b743a9294d15980c
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 #else
16 #include <sys/types.h>
17 #include <sys/socket.h>
18 #include <sys/un.h>
19 #include <netinet/in.h>
20 #include <netinet/tcp.h>
21 #include <arpa/inet.h>
22 #include <fcntl.h>
23 #include <netdb.h>
24 #include <unistd.h>
25 #endif
27 #include <stddef.h>
28 #include <string.h>
30 #include "mruby.h"
31 #include "mruby/array.h"
32 #include "mruby/class.h"
33 #include "mruby/data.h"
34 #include "mruby/string.h"
35 #include "mruby/variable.h"
36 #include "error.h"
38 #define E_SOCKET_ERROR (mrb_class_get(mrb, "SocketError"))
40 #if !defined(mrb_cptr)
41 #define mrb_cptr_value(m,p) mrb_voidp_value((m),(p))
42 #define mrb_cptr(o) mrb_voidp(o)
43 #define mrb_cptr_p(o) mrb_voidp_p(o)
44 #endif
46 #ifdef _WIN32
47 const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
49 if (af == AF_INET)
51 struct sockaddr_in in;
52 memset(&in, 0, sizeof(in));
53 in.sin_family = AF_INET;
54 memcpy(&in.sin_addr, src, sizeof(struct in_addr));
55 getnameinfo((struct sockaddr *)&in, sizeof(struct
56 sockaddr_in), dst, cnt, NULL, 0, NI_NUMERICHOST);
57 return dst;
59 else if (af == AF_INET6)
61 struct sockaddr_in6 in;
62 memset(&in, 0, sizeof(in));
63 in.sin6_family = AF_INET6;
64 memcpy(&in.sin6_addr, src, sizeof(struct in_addr6));
65 getnameinfo((struct sockaddr *)&in, sizeof(struct
66 sockaddr_in6), dst, cnt, NULL, 0, NI_NUMERICHOST);
67 return dst;
69 return NULL;
72 int inet_pton(int af, const char *src, void *dst)
74 struct addrinfo hints, *res, *ressave;
76 memset(&hints, 0, sizeof(struct addrinfo));
77 hints.ai_family = af;
79 if (getaddrinfo(src, NULL, &hints, &res) != 0)
81 printf("Couldn't resolve host %s\n", src);
82 return -1;
85 ressave = res;
87 while (res)
89 memcpy(dst, res->ai_addr, res->ai_addrlen);
90 res = res->ai_next;
93 freeaddrinfo(ressave);
94 return 0;
97 #endif
99 static mrb_value
100 mrb_addrinfo_getaddrinfo(mrb_state *mrb, mrb_value klass)
102 struct addrinfo hints, *res0, *res;
103 mrb_value ai, ary, family, lastai, nodename, protocol, sa, service, socktype;
104 mrb_int flags;
105 int arena_idx, error;
106 const char *hostname = NULL, *servname = NULL;
108 ary = mrb_ary_new(mrb);
109 arena_idx = mrb_gc_arena_save(mrb); /* ary must be on arena! */
111 family = socktype = protocol = mrb_nil_value();
112 flags = 0;
113 mrb_get_args(mrb, "oo|oooi", &nodename, &service, &family, &socktype, &protocol, &flags);
115 if (mrb_string_p(nodename)) {
116 hostname = mrb_str_to_cstr(mrb, nodename);
117 } else if (mrb_nil_p(nodename)) {
118 hostname = NULL;
119 } else {
120 mrb_raise(mrb, E_TYPE_ERROR, "nodename must be String or nil");
123 if (mrb_string_p(service)) {
124 servname = mrb_str_to_cstr(mrb, service);
125 } else if (mrb_fixnum_p(service)) {
126 servname = mrb_str_to_cstr(mrb, mrb_funcall(mrb, service, "to_s", 0));
127 } else if (mrb_nil_p(service)) {
128 servname = NULL;
129 } else {
130 mrb_raise(mrb, E_TYPE_ERROR, "service must be String, Fixnum, or nil");
133 memset(&hints, 0, sizeof(hints));
134 hints.ai_flags = flags;
136 if (mrb_fixnum_p(family)) {
137 hints.ai_family = mrb_fixnum(family);
140 if (mrb_fixnum_p(socktype)) {
141 hints.ai_socktype = mrb_fixnum(socktype);
144 if (mrb_fixnum_p(protocol)) {
145 hints.ai_protocol = mrb_fixnum(protocol);
148 lastai = mrb_cv_get(mrb, klass, mrb_intern_lit(mrb, "_lastai"));
149 if (mrb_cptr_p(lastai)) {
150 freeaddrinfo(mrb_cptr(lastai));
151 mrb_cv_set(mrb, klass, mrb_intern_lit(mrb, "_lastai"), mrb_nil_value());
154 error = getaddrinfo(hostname, servname, &hints, &res0);
155 if (error) {
156 mrb_raisef(mrb, E_SOCKET_ERROR, "getaddrinfo: %S", mrb_str_new_cstr(mrb, gai_strerror(error)));
158 mrb_cv_set(mrb, klass, mrb_intern_lit(mrb, "_lastai"), mrb_cptr_value(mrb, res0));
160 for (res = res0; res != NULL; res = res->ai_next) {
161 sa = mrb_str_new(mrb, (void *)res->ai_addr, res->ai_addrlen);
162 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));
163 mrb_ary_push(mrb, ary, ai);
164 mrb_gc_arena_restore(mrb, arena_idx);
167 freeaddrinfo(res0);
168 mrb_cv_set(mrb, klass, mrb_intern_lit(mrb, "_lastai"), mrb_nil_value());
170 return ary;
173 static mrb_value
174 mrb_addrinfo_getnameinfo(mrb_state *mrb, mrb_value self)
176 mrb_int flags;
177 mrb_value ary, host, sastr, serv;
178 int error;
180 flags = 0;
181 mrb_get_args(mrb, "|i", &flags);
182 host = mrb_str_buf_new(mrb, NI_MAXHOST);
183 serv = mrb_str_buf_new(mrb, NI_MAXSERV);
185 sastr = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@sockaddr"));
186 if (!mrb_string_p(sastr)) {
187 mrb_raise(mrb, E_SOCKET_ERROR, "invalid sockaddr");
189 error = getnameinfo((struct sockaddr *)RSTRING_PTR(sastr), (socklen_t)RSTRING_LEN(sastr), RSTRING_PTR(host), NI_MAXHOST, RSTRING_PTR(serv), NI_MAXSERV, flags);
190 if (error != 0) {
191 mrb_raisef(mrb, E_SOCKET_ERROR, "getnameinfo: %s", gai_strerror(error));
193 ary = mrb_ary_new_capa(mrb, 2);
194 mrb_str_resize(mrb, host, strlen(RSTRING_PTR(host)));
195 mrb_ary_push(mrb, ary, host);
196 mrb_str_resize(mrb, serv, strlen(RSTRING_PTR(serv)));
197 mrb_ary_push(mrb, ary, serv);
198 return ary;
201 #ifndef _WIN32
202 static mrb_value
203 mrb_addrinfo_unix_path(mrb_state *mrb, mrb_value self)
205 mrb_value sastr;
207 sastr = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@sockaddr"));
208 if (((struct sockaddr *)RSTRING_PTR(sastr))->sa_family != AF_UNIX)
209 mrb_raise(mrb, E_SOCKET_ERROR, "need AF_UNIX address");
210 return mrb_str_new_cstr(mrb, ((struct sockaddr_un *)RSTRING_PTR(sastr))->sun_path);
212 #endif
214 static mrb_value
215 sa2addrlist(mrb_state *mrb, const struct sockaddr *sa, socklen_t salen)
217 mrb_value ary, host;
218 unsigned short port;
219 const char *afstr;
221 switch (sa->sa_family) {
222 case AF_INET:
223 afstr = "AF_INET";
224 port = ((struct sockaddr_in *)sa)->sin_port;
225 break;
226 case AF_INET6:
227 afstr = "AF_INET6";
228 port = ((struct sockaddr_in6 *)sa)->sin6_port;
229 break;
230 default:
231 mrb_raise(mrb, E_ARGUMENT_ERROR, "bad af");
232 return mrb_nil_value();
234 port = ntohs(port);
235 host = mrb_str_buf_new(mrb, NI_MAXHOST);
236 if (getnameinfo(sa, salen, RSTRING_PTR(host), NI_MAXHOST, NULL, 0, NI_NUMERICHOST) == -1)
237 mrb_sys_fail(mrb, "getnameinfo");
238 mrb_str_resize(mrb, host, strlen(RSTRING_PTR(host)));
239 ary = mrb_ary_new_capa(mrb, 4);
240 mrb_ary_push(mrb, ary, mrb_str_new_cstr(mrb, afstr));
241 mrb_ary_push(mrb, ary, mrb_fixnum_value(port));
242 mrb_ary_push(mrb, ary, host);
243 mrb_ary_push(mrb, ary, host);
244 return ary;
247 static int
248 socket_fd(mrb_state *mrb, mrb_value sock)
250 return mrb_fixnum(mrb_funcall(mrb, sock, "fileno", 0));
253 static int
254 socket_family(int s)
256 struct sockaddr_storage ss;
257 socklen_t salen;
259 salen = sizeof(ss);
260 if (getsockname(s, (struct sockaddr *)&ss, &salen) == -1)
261 return AF_UNSPEC;
262 return ss.ss_family;
265 static mrb_value
266 mrb_basicsocket_getpeereid(mrb_state *mrb, mrb_value self)
268 #ifdef HAVE_GETPEEREID
269 mrb_value ary;
270 gid_t egid;
271 uid_t euid;
272 int s;
274 s = socket_fd(mrb, self);
275 if (getpeereid(s, &euid, &egid) != 0)
276 mrb_sys_fail(mrb, "getpeereid");
278 ary = mrb_ary_new_capa(mrb, 2);
279 mrb_ary_push(mrb, ary, mrb_fixnum_value((mrb_int)euid));
280 mrb_ary_push(mrb, ary, mrb_fixnum_value((mrb_int)egid));
281 return ary;
282 #else
283 mrb_raise(mrb, E_RUNTIME_ERROR, "getpeereid is not avaialble on this system");
284 return mrb_nil_value();
285 #endif
288 static mrb_value
289 mrb_basicsocket_getpeername(mrb_state *mrb, mrb_value self)
291 struct sockaddr_storage ss;
292 socklen_t salen;
294 salen = sizeof(ss);
295 if (getpeername(socket_fd(mrb, self), (struct sockaddr *)&ss, &salen) != 0)
296 mrb_sys_fail(mrb, "getpeername");
298 return mrb_str_new(mrb, (void *)&ss, salen);
301 static mrb_value
302 mrb_basicsocket_getsockname(mrb_state *mrb, mrb_value self)
304 struct sockaddr_storage ss;
305 socklen_t salen;
307 salen = sizeof(ss);
308 if (getsockname(socket_fd(mrb, self), (struct sockaddr *)&ss, &salen) != 0)
309 mrb_sys_fail(mrb, "getsockname");
311 return mrb_str_new(mrb, (void *)&ss, salen);
314 static mrb_value
315 mrb_basicsocket_getsockopt(mrb_state *mrb, mrb_value self)
317 char opt[8];
318 int s;
319 mrb_int family, level, optname;
320 mrb_value c, data;
321 socklen_t optlen;
323 mrb_get_args(mrb, "ii", &level, &optname);
324 s = socket_fd(mrb, self);
325 optlen = sizeof(opt);
326 if (getsockopt(s, level, optname, opt, &optlen) == -1)
327 mrb_sys_fail(mrb, "getsockopt");
328 c = mrb_const_get(mrb, mrb_obj_value(mrb_class_get(mrb, "Socket")), mrb_intern_lit(mrb, "Option"));
329 family = socket_family(s);
330 data = mrb_str_new(mrb, opt, optlen);
331 return mrb_funcall(mrb, c, "new", 4, mrb_fixnum_value(family), mrb_fixnum_value(level), mrb_fixnum_value(optname), data);
334 static mrb_value
335 mrb_basicsocket_recv(mrb_state *mrb, mrb_value self)
337 int n;
338 mrb_int maxlen, flags = 0;
339 mrb_value buf;
341 mrb_get_args(mrb, "i|i", &maxlen, &flags);
342 buf = mrb_str_buf_new(mrb, maxlen);
343 n = recv(socket_fd(mrb, self), RSTRING_PTR(buf), maxlen, flags);
344 if (n == -1)
345 mrb_sys_fail(mrb, "recv");
346 mrb_str_resize(mrb, buf, n);
347 return buf;
350 static mrb_value
351 mrb_basicsocket_recvfrom(mrb_state *mrb, mrb_value self)
353 int n;
354 mrb_int maxlen, flags = 0;
355 mrb_value ary, buf, sa;
356 socklen_t socklen;
358 mrb_get_args(mrb, "i|i", &maxlen, &flags);
359 buf = mrb_str_buf_new(mrb, maxlen);
360 socklen = sizeof(struct sockaddr_storage);
361 sa = mrb_str_buf_new(mrb, socklen);
362 n = recvfrom(socket_fd(mrb, self), RSTRING_PTR(buf), maxlen, flags, (struct sockaddr *)RSTRING_PTR(sa), &socklen);
363 if (n == -1)
364 mrb_sys_fail(mrb, "recvfrom");
365 mrb_str_resize(mrb, buf, n);
366 mrb_str_resize(mrb, sa, socklen);
367 ary = mrb_ary_new_capa(mrb, 2);
368 mrb_ary_push(mrb, ary, buf);
369 mrb_ary_push(mrb, ary, sa);
370 return ary;
373 static mrb_value
374 mrb_basicsocket_send(mrb_state *mrb, mrb_value self)
376 int n;
377 mrb_int flags;
378 mrb_value dest, mesg;
380 dest = mrb_nil_value();
381 mrb_get_args(mrb, "Si|S", &mesg, &flags, &dest);
382 if (mrb_nil_p(dest)) {
383 n = send(socket_fd(mrb, self), RSTRING_PTR(mesg), RSTRING_LEN(mesg), flags);
384 } else {
385 n = sendto(socket_fd(mrb, self), RSTRING_PTR(mesg), RSTRING_LEN(mesg), flags, (const void *)RSTRING_PTR(dest), RSTRING_LEN(dest));
387 if (n == -1)
388 mrb_sys_fail(mrb, "send");
389 return mrb_fixnum_value(n);
392 static mrb_value
393 mrb_basicsocket_setnonblock(mrb_state *mrb, mrb_value self)
395 int fd, flags;
396 mrb_value bool;
397 #ifdef _WIN32
398 u_long mode = 1;
399 #endif
401 mrb_get_args(mrb, "o", &bool);
402 fd = socket_fd(mrb, self);
403 #ifdef _WIN32
404 flags = ioctlsocket(fd, FIONBIO, &mode);
405 if (flags != NO_ERROR)
406 mrb_sys_fail(mrb, "ioctlsocket");
407 #else
408 flags = fcntl(fd, F_GETFL, 0);
409 if (flags == 1)
410 mrb_sys_fail(mrb, "fcntl");
411 if (mrb_test(bool))
412 flags |= O_NONBLOCK;
413 else
414 flags &= ~O_NONBLOCK;
415 if (fcntl(fd, F_SETFL, flags) == -1)
416 mrb_sys_fail(mrb, "fcntl");
417 #endif
418 return mrb_nil_value();
421 static mrb_value
422 mrb_basicsocket_setsockopt(mrb_state *mrb, mrb_value self)
424 int argc, s;
425 mrb_int level = 0, optname;
426 mrb_value optval, so;
428 argc = mrb_get_args(mrb, "o|io", &so, &optname, &optval);
429 if (argc == 3) {
430 if (!mrb_fixnum_p(so)) {
431 mrb_raise(mrb, E_ARGUMENT_ERROR, "level is not an integer");
433 level = mrb_fixnum(so);
434 if (mrb_string_p(optval)) {
435 /* that's good */
436 } else if (mrb_type(optval) == MRB_TT_TRUE || mrb_type(optval) == MRB_TT_FALSE) {
437 mrb_int i = mrb_test(optval) ? 1 : 0;
438 optval = mrb_str_new(mrb, (char *)&i, sizeof(i));
439 } else if (mrb_fixnum_p(optval)) {
440 if (optname == IP_MULTICAST_TTL || optname == IP_MULTICAST_LOOP) {
441 char uc = mrb_fixnum(optval);
442 optval = mrb_str_new(mrb, &uc, sizeof(uc));
443 } else {
444 mrb_int i = mrb_fixnum(optval);
445 optval = mrb_str_new(mrb, (char *)&i, sizeof(i));
447 } else {
448 mrb_raise(mrb, E_ARGUMENT_ERROR, "optval should be true, false, an integer, or a string");
450 } else if (argc == 1) {
451 if (strcmp(mrb_obj_classname(mrb, so), "Socket::Option") != 0)
452 mrb_raisef(mrb, E_ARGUMENT_ERROR, "not an instance of Socket::Option");
453 level = mrb_fixnum(mrb_funcall(mrb, so, "level", 0));
454 optname = mrb_fixnum(mrb_funcall(mrb, so, "optname", 0));
455 optval = mrb_funcall(mrb, so, "data", 0);
456 } else {
457 mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%d for 3)", argc);
460 s = socket_fd(mrb, self);
461 if (setsockopt(s, level, optname, RSTRING_PTR(optval), RSTRING_LEN(optval)) == -1)
462 mrb_sys_fail(mrb, "setsockopt");
463 return mrb_fixnum_value(0);
466 static mrb_value
467 mrb_basicsocket_shutdown(mrb_state *mrb, mrb_value self)
469 mrb_int how = SHUT_RDWR;
471 mrb_get_args(mrb, "|i", &how);
472 if (shutdown(socket_fd(mrb, self), how) != 0)
473 mrb_sys_fail(mrb, "shutdown");
474 return mrb_fixnum_value(0);
477 static mrb_value
478 mrb_ipsocket_ntop(mrb_state *mrb, mrb_value klass)
480 mrb_int af, n;
481 char *addr, buf[50];
483 mrb_get_args(mrb, "is", &af, &addr, &n);
484 if ((af == AF_INET && n != 4) || (af == AF_INET6 && n != 16))
485 mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid address");
486 if (inet_ntop(af, addr, buf, sizeof(buf)) == NULL)
487 mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid address");
488 return mrb_str_new_cstr(mrb, buf);
491 static mrb_value
492 mrb_ipsocket_pton(mrb_state *mrb, mrb_value klass)
494 mrb_int af, n;
495 char *bp, buf[50];
497 mrb_get_args(mrb, "is", &af, &bp, &n);
498 if (n > sizeof(buf) - 1)
499 mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid address");
500 memcpy(buf, bp, n);
501 buf[n] = '\0';
503 if (af == AF_INET) {
504 struct in_addr in;
505 if (inet_pton(AF_INET, buf, (void *)&in.s_addr) != 1)
506 goto invalid;
507 return mrb_str_new(mrb, (char *)&in.s_addr, 4);
508 } else if (af == AF_INET6) {
509 struct in6_addr in6;
510 if (inet_pton(AF_INET6, buf, (void *)&in6.s6_addr) != 1)
511 goto invalid;
512 return mrb_str_new(mrb, (char *)&in6.s6_addr, 16);
513 } else
514 mrb_raise(mrb, E_ARGUMENT_ERROR, "unsupported address family");
516 invalid:
517 mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid address");
518 return mrb_nil_value(); /* dummy */
521 static mrb_value
522 mrb_ipsocket_recvfrom(mrb_state *mrb, mrb_value self)
524 struct sockaddr_storage ss;
525 socklen_t socklen;
526 mrb_value a, buf, pair;
527 mrb_int flags, maxlen, n;
528 int fd;
530 fd = socket_fd(mrb, self);
531 flags = 0;
532 mrb_get_args(mrb, "i|i", &maxlen, &flags);
533 buf = mrb_str_buf_new(mrb, maxlen);
534 socklen = sizeof(ss);
535 n = recvfrom(fd, RSTRING_PTR(buf), maxlen, flags,
536 (struct sockaddr *)&ss, &socklen);
537 if (n == -1) {
538 mrb_sys_fail(mrb, "recvfrom");
540 mrb_str_resize(mrb, buf, n);
541 a = sa2addrlist(mrb, (struct sockaddr *)&ss, socklen);
542 pair = mrb_ary_new_capa(mrb, 2);
543 mrb_ary_push(mrb, pair, buf);
544 mrb_ary_push(mrb, pair, a);
545 return pair;
548 static mrb_value
549 mrb_socket_gethostname(mrb_state *mrb, mrb_value cls)
551 mrb_value buf;
552 size_t bufsize;
554 #ifdef HOST_NAME_MAX
555 bufsize = HOST_NAME_MAX + 1;
556 #else
557 bufsize = 256;
558 #endif
559 buf = mrb_str_buf_new(mrb, bufsize);
560 if (gethostname(RSTRING_PTR(buf), bufsize) != 0)
561 mrb_sys_fail(mrb, "gethostname");
562 mrb_str_resize(mrb, buf, strlen(RSTRING_PTR(buf)));
563 return buf;
566 static mrb_value
567 mrb_socket_accept(mrb_state *mrb, mrb_value klass)
569 mrb_value ary, sastr;
570 int s1;
571 mrb_int s0;
572 socklen_t socklen;
574 mrb_get_args(mrb, "i", &s0);
575 socklen = sizeof(struct sockaddr_storage);
576 sastr = mrb_str_buf_new(mrb, socklen);
577 s1 = accept(s0, (struct sockaddr *)RSTRING_PTR(sastr), &socklen);
578 if (s1 == -1) {
579 mrb_sys_fail(mrb, "accept");
581 // XXX: possible descriptor leakage here!
582 mrb_str_resize(mrb, sastr, socklen);
583 ary = mrb_ary_new_capa(mrb, 2);
584 mrb_ary_push(mrb, ary, mrb_fixnum_value(s1));
585 mrb_ary_push(mrb, ary, sastr);
586 return ary;
589 static mrb_value
590 mrb_socket_bind(mrb_state *mrb, mrb_value klass)
592 mrb_value sastr;
593 mrb_int s;
595 mrb_get_args(mrb, "iS", &s, &sastr);
596 if (bind((int)s, (struct sockaddr *)RSTRING_PTR(sastr), (socklen_t)RSTRING_LEN(sastr)) == -1) {
597 mrb_sys_fail(mrb, "bind");
599 return mrb_nil_value();
602 static mrb_value
603 mrb_socket_connect(mrb_state *mrb, mrb_value klass)
605 mrb_value sastr;
606 mrb_int s;
608 mrb_get_args(mrb, "iS", &s, &sastr);
609 if (connect((int)s, (struct sockaddr *)RSTRING_PTR(sastr), (socklen_t)RSTRING_LEN(sastr)) == -1) {
610 mrb_sys_fail(mrb, "connect");
612 return mrb_nil_value();
615 static mrb_value
616 mrb_socket_listen(mrb_state *mrb, mrb_value klass)
618 mrb_int backlog, s;
620 mrb_get_args(mrb, "ii", &s, &backlog);
621 if (listen((int)s, (int)backlog) == -1) {
622 mrb_sys_fail(mrb, "listen");
624 return mrb_nil_value();
627 static mrb_value
628 mrb_socket_sockaddr_family(mrb_state *mrb, mrb_value klass)
630 mrb_value sa;
632 mrb_get_args(mrb, "S", &sa);
633 #ifdef __linux__
634 if (RSTRING_LEN(sa) < offsetof(struct sockaddr, sa_family) + sizeof(sa_family_t)) {
635 mrb_raisef(mrb, E_SOCKET_ERROR, "invalid sockaddr (too short)");
637 #else
638 if (RSTRING_LEN(sa) < sizeof(struct sockaddr)) {
639 mrb_raisef(mrb, E_SOCKET_ERROR, "invalid sockaddr (too short)");
641 #endif
642 return mrb_fixnum_value(((struct sockaddr *)RSTRING_PTR(sa))->sa_family);
645 static mrb_value
646 mrb_socket_sockaddr_un(mrb_state *mrb, mrb_value klass)
648 #ifdef _WIN32
649 mrb_raise(mrb, E_NOTIMP_ERROR, "sockaddr_un unsupported on Windows");
650 return mrb_nil_value();
651 #else
652 struct sockaddr_un *sunp;
653 mrb_value path, s;
655 mrb_get_args(mrb, "S", &path);
656 if (RSTRING_LEN(path) > sizeof(sunp->sun_path) - 1) {
657 mrb_raisef(mrb, E_ARGUMENT_ERROR, "too long unix socket path (max: %ubytes)", (unsigned int)sizeof(sunp->sun_path) - 1);
659 s = mrb_str_buf_new(mrb, sizeof(struct sockaddr_un));
660 sunp = (struct sockaddr_un *)RSTRING_PTR(s);
661 sunp->sun_family = AF_UNIX;
662 memcpy(sunp->sun_path, RSTRING_PTR(path), RSTRING_LEN(path));
663 sunp->sun_path[RSTRING_LEN(path)] = '\0';
664 mrb_str_resize(mrb, s, sizeof(struct sockaddr_un));
665 return s;
666 #endif
669 static mrb_value
670 mrb_socket_socketpair(mrb_state *mrb, mrb_value klass)
672 #ifdef _WIN32
673 mrb_raise(mrb, E_NOTIMP_ERROR, "socketpair unsupported on Windows");
674 return mrb_nil_value();
675 #else
676 mrb_value ary;
677 mrb_int domain, type, protocol;
678 int sv[2];
680 mrb_get_args(mrb, "iii", &domain, &type, &protocol);
681 if (socketpair(domain, type, protocol, sv) == -1) {
682 mrb_sys_fail(mrb, "socketpair");
684 // XXX: possible descriptor leakage here!
685 ary = mrb_ary_new_capa(mrb, 2);
686 mrb_ary_push(mrb, ary, mrb_fixnum_value(sv[0]));
687 mrb_ary_push(mrb, ary, mrb_fixnum_value(sv[1]));
688 return ary;
689 #endif
692 static mrb_value
693 mrb_socket_socket(mrb_state *mrb, mrb_value klass)
695 mrb_int domain, type, protocol;
696 int s;
698 mrb_get_args(mrb, "iii", &domain, &type, &protocol);
699 s = socket(domain, type, protocol);
700 if (s == -1)
701 mrb_sys_fail(mrb, "socket");
702 return mrb_fixnum_value(s);
705 static mrb_value
706 mrb_tcpsocket_allocate(mrb_state *mrb, mrb_value klass)
708 struct RClass *c = mrb_class_ptr(klass);
709 enum mrb_vtype ttype = MRB_INSTANCE_TT(c);
711 /* copied from mrb_instance_alloc() */
712 if (ttype == 0) ttype = MRB_TT_OBJECT;
713 return mrb_obj_value((struct RObject*)mrb_obj_alloc(mrb, ttype, c));
716 /* Windows overrides for IO methods on BasicSocket objects.
717 * This is because sockets on Windows are not the same as file
718 * descriptors, and thus functions which operate on file descriptors
719 * will break on socket descriptors.
721 #ifdef _WIN32
722 static mrb_value
723 mrb_win32_basicsocket_close(mrb_state *mrb, mrb_value self)
725 if (closesocket(socket_fd(mrb, self)) != NO_ERROR)
726 mrb_raise(mrb, E_SOCKET_ERROR, "closesocket unsuccessful");
727 return mrb_nil_value();
730 #define E_EOF_ERROR (mrb_class_get(mrb, "EOFError"))
731 static mrb_value
732 mrb_win32_basicsocket_sysread(mrb_state *mrb, mrb_value self)
734 int sd, ret;
735 mrb_value buf = mrb_nil_value();
736 mrb_int maxlen;
738 mrb_get_args(mrb, "i|S", &maxlen, &buf);
739 if (maxlen < 0) {
740 return mrb_nil_value();
743 if (mrb_nil_p(buf)) {
744 buf = mrb_str_new(mrb, NULL, maxlen);
746 if (RSTRING_LEN(buf) != maxlen) {
747 buf = mrb_str_resize(mrb, buf, maxlen);
750 sd = socket_fd(mrb, self);
751 ret = recv(sd, RSTRING_PTR(buf), maxlen, 0);
753 switch (ret) {
754 case 0: /* EOF */
755 if (maxlen == 0) {
756 buf = mrb_str_new_cstr(mrb, "");
757 } else {
758 mrb_raise(mrb, E_EOF_ERROR, "sysread failed: End of File");
760 break;
761 case SOCKET_ERROR: /* Error */
762 mrb_sys_fail(mrb, "recv");
763 break;
764 default:
765 if (RSTRING_LEN(buf) != ret) {
766 buf = mrb_str_resize(mrb, buf, ret);
768 break;
771 return buf;
774 static mrb_value
775 mrb_win32_basicsocket_sysseek(mrb_state *mrb, mrb_value self)
777 mrb_raise(mrb, E_NOTIMP_ERROR, "sysseek not implemented for windows sockets");
778 return mrb_nil_value();
781 static mrb_value
782 mrb_win32_basicsocket_syswrite(mrb_state *mrb, mrb_value self)
784 int n;
785 SOCKET sd;
786 mrb_value str;
788 sd = socket_fd(mrb, self);
789 mrb_get_args(mrb, "S", &str);
790 n = send(sd, RSTRING_PTR(str), RSTRING_LEN(str), 0);
791 if (n == SOCKET_ERROR)
792 mrb_sys_fail(mrb, "send");
793 return mrb_fixnum_value(n);
796 #endif
798 void
799 mrb_mruby_socket_gem_init(mrb_state* mrb)
801 struct RClass *io, *ai, *sock, *bsock, *ipsock, *tcpsock;
802 struct RClass *constants;
804 #ifdef _WIN32
805 WSADATA wsaData;
806 int result;
807 result = WSAStartup(MAKEWORD(2,2), &wsaData);
808 if (result != NO_ERROR)
809 mrb_raise(mrb, E_RUNTIME_ERROR, "WSAStartup failed");
810 #else
811 struct RClass *usock;
812 #endif
814 ai = mrb_define_class(mrb, "Addrinfo", mrb->object_class);
815 mrb_mod_cv_set(mrb, ai, mrb_intern_lit(mrb, "_lastai"), mrb_nil_value());
816 mrb_define_class_method(mrb, ai, "getaddrinfo", mrb_addrinfo_getaddrinfo, MRB_ARGS_REQ(2)|MRB_ARGS_OPT(4));
817 mrb_define_method(mrb, ai, "getnameinfo", mrb_addrinfo_getnameinfo, MRB_ARGS_OPT(1));
818 #ifndef _WIN32
819 mrb_define_method(mrb, ai, "unix_path", mrb_addrinfo_unix_path, MRB_ARGS_NONE());
820 #endif
822 io = mrb_class_get(mrb, "IO");
824 bsock = mrb_define_class(mrb, "BasicSocket", io);
825 mrb_define_method(mrb, bsock, "_recvfrom", mrb_basicsocket_recvfrom, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
826 mrb_define_method(mrb, bsock, "_setnonblock", mrb_basicsocket_setnonblock, MRB_ARGS_REQ(1));
827 mrb_define_method(mrb, bsock, "getpeereid", mrb_basicsocket_getpeereid, MRB_ARGS_NONE());
828 mrb_define_method(mrb, bsock, "getpeername", mrb_basicsocket_getpeername, MRB_ARGS_NONE());
829 mrb_define_method(mrb, bsock, "getsockname", mrb_basicsocket_getsockname, MRB_ARGS_NONE());
830 mrb_define_method(mrb, bsock, "getsockopt", mrb_basicsocket_getsockopt, MRB_ARGS_REQ(2));
831 mrb_define_method(mrb, bsock, "recv", mrb_basicsocket_recv, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
832 // #recvmsg(maxlen, flags=0)
833 mrb_define_method(mrb, bsock, "send", mrb_basicsocket_send, MRB_ARGS_REQ(2)|MRB_ARGS_OPT(1));
834 // #sendmsg
835 // #sendmsg_nonblock
836 mrb_define_method(mrb, bsock, "setsockopt", mrb_basicsocket_setsockopt, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(2));
837 mrb_define_method(mrb, bsock, "shutdown", mrb_basicsocket_shutdown, MRB_ARGS_OPT(1));
839 ipsock = mrb_define_class(mrb, "IPSocket", bsock);
840 mrb_define_class_method(mrb, ipsock, "ntop", mrb_ipsocket_ntop, MRB_ARGS_REQ(1));
841 mrb_define_class_method(mrb, ipsock, "pton", mrb_ipsocket_pton, MRB_ARGS_REQ(2));
842 mrb_define_method(mrb, ipsock, "recvfrom", mrb_ipsocket_recvfrom, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
844 tcpsock = mrb_define_class(mrb, "TCPSocket", ipsock);
845 mrb_define_class_method(mrb, tcpsock, "_allocate", mrb_tcpsocket_allocate, MRB_ARGS_NONE());
846 mrb_define_class(mrb, "TCPServer", tcpsock);
848 mrb_define_class(mrb, "UDPSocket", ipsock);
849 //#recvfrom_nonblock
851 sock = mrb_define_class(mrb, "Socket", bsock);
852 mrb_define_class_method(mrb, sock, "_accept", mrb_socket_accept, MRB_ARGS_REQ(1));
853 mrb_define_class_method(mrb, sock, "_bind", mrb_socket_bind, MRB_ARGS_REQ(3));
854 mrb_define_class_method(mrb, sock, "_connect", mrb_socket_connect, MRB_ARGS_REQ(3));
855 mrb_define_class_method(mrb, sock, "_listen", mrb_socket_listen, MRB_ARGS_REQ(2));
856 mrb_define_class_method(mrb, sock, "_sockaddr_family", mrb_socket_sockaddr_family, MRB_ARGS_REQ(1));
857 mrb_define_class_method(mrb, sock, "_socket", mrb_socket_socket, MRB_ARGS_REQ(3));
858 //mrb_define_class_method(mrb, sock, "gethostbyaddr", mrb_socket_gethostbyaddr, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
859 //mrb_define_class_method(mrb, sock, "gethostbyname", mrb_socket_gethostbyname, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
860 mrb_define_class_method(mrb, sock, "gethostname", mrb_socket_gethostname, MRB_ARGS_NONE());
861 //mrb_define_class_method(mrb, sock, "getservbyname", mrb_socket_getservbyname, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
862 //mrb_define_class_method(mrb, sock, "getservbyport", mrb_socket_getservbyport, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
863 mrb_define_class_method(mrb, sock, "sockaddr_un", mrb_socket_sockaddr_un, MRB_ARGS_REQ(1));
864 mrb_define_class_method(mrb, sock, "socketpair", mrb_socket_socketpair, MRB_ARGS_REQ(3));
865 //mrb_define_method(mrb, sock, "sysaccept", mrb_socket_accept, MRB_ARGS_NONE());
867 #ifndef _WIN32
868 usock = mrb_define_class(mrb, "UNIXSocket", bsock);
869 #endif
870 //mrb_define_class_method(mrb, usock, "pair", mrb_unixsocket_open, MRB_ARGS_OPT(2));
871 //mrb_define_class_method(mrb, usock, "socketpair", mrb_unixsocket_open, MRB_ARGS_OPT(2));
873 //mrb_define_method(mrb, usock, "recv_io", mrb_unixsocket_peeraddr, MRB_ARGS_NONE());
874 //mrb_define_method(mrb, usock, "recvfrom", mrb_unixsocket_peeraddr, MRB_ARGS_NONE());
875 //mrb_define_method(mrb, usock, "send_io", mrb_unixsocket_peeraddr, MRB_ARGS_NONE());
877 /* Windows IO Method Overrides on BasicSocket */
878 #ifdef _WIN32
879 mrb_define_method(mrb, bsock, "close", mrb_win32_basicsocket_close, MRB_ARGS_NONE());
880 mrb_define_method(mrb, bsock, "sysread", mrb_win32_basicsocket_sysread, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
881 mrb_define_method(mrb, bsock, "sysseek", mrb_win32_basicsocket_sysseek, MRB_ARGS_REQ(1));
882 mrb_define_method(mrb, bsock, "syswrite", mrb_win32_basicsocket_syswrite, MRB_ARGS_REQ(1));
883 #endif
885 constants = mrb_define_module_under(mrb, sock, "Constants");
887 #define define_const(SYM) \
888 do { \
889 mrb_define_const(mrb, constants, #SYM, mrb_fixnum_value(SYM)); \
890 } while (0)
892 #include "const.cstub"
895 void
896 mrb_mruby_socket_gem_final(mrb_state* mrb)
898 mrb_value ai;
899 ai = mrb_mod_cv_get(mrb, mrb_class_get(mrb, "Addrinfo"), mrb_intern_lit(mrb, "_lastai"));
900 if (mrb_cptr_p(ai)) {
901 freeaddrinfo(mrb_cptr(ai));
903 #ifdef _WIN32
904 WSACleanup();
905 #endif