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