source: EcnlProtoTool/trunk/mrbgems/mruby-socket/src/socket.c@ 279

Last change on this file since 279 was 279, checked in by coas-nagasima, 7 years ago

ファイルを追加、更新。

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