From 06f1c82f64422d12b1e646d322ac6d5d734e430c Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Mon, 20 May 2013 21:15:50 -0700 Subject: Initial commit --- README.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 000000000..1e574b4f4 --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +mruby-socket +============ + +socket module for mruby -- cgit v1.2.3 From 49e53bca5df530d0356852d6ce675b6d0cbf6933 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 21 May 2013 13:17:34 +0900 Subject: Socket library for mruby. --- mrbgem.rake | 4 + mrblib/socket.rb | 548 +++++++++++++++++++++++++++++++++++++++ src/const.cstub | 219 ++++++++++++++++ src/const.def | 81 ++++++ src/gen.rb | 17 ++ src/socket.c | 775 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ test/socket.rb | 139 ++++++++++ 7 files changed, 1783 insertions(+) create mode 100644 mrbgem.rake create mode 100644 mrblib/socket.rb create mode 100644 src/const.cstub create mode 100644 src/const.def create mode 100755 src/gen.rb create mode 100644 src/socket.c create mode 100644 test/socket.rb diff --git a/mrbgem.rake b/mrbgem.rake new file mode 100644 index 000000000..db6b8b56f --- /dev/null +++ b/mrbgem.rake @@ -0,0 +1,4 @@ +MRuby::Gem::Specification.new('mruby-socket') do |spec| + spec.license = 'MIT' + spec.authors = 'Internet Initiative Japan' +end diff --git a/mrblib/socket.rb b/mrblib/socket.rb new file mode 100644 index 000000000..c7e8a5672 --- /dev/null +++ b/mrblib/socket.rb @@ -0,0 +1,548 @@ +class Addrinfo + def initialize(sockaddr, family=Socket::PF_UNSPEC, socktype=0, protocol=0) + @hostname = nil + if sockaddr.is_a? Array + sary = sockaddr + if sary[0] == 'AF_INET' || sary[0] == 'AF_INET6' + @sockaddr = Socket.sockaddr_in(sary[1], sary[3]) + @hostname = sary[2] + elsif sary[0] == 'AF_UNIX' + @sockaddr = Socket.sockaddr_un(sary[1]) + end + else + @sockaddr = sockaddr.dup + end + if family == Socket::PF_UNSPEC or family == nil + @family = Socket._sockaddr_family(@sockaddr) + else + @family = family + end + @socktype = socktype + @protocol = protocol + @canonname = nil + end + + def self.foreach(nodename, service, family=nil, socktype=nil, protocol=nil, flags=0, &block) + a = self.getaddrinfo(nodename, service, family, socktype, protocol, flags) + a.each { |ai| block.call(ai) } + a + end + + def self.ip(host) + Addrinfo.new(Socket.sockaddr_in(0, host)) + end + + def self.tcp(host, port) + Addrinfo.new(Socket.sockaddr_in(port, host), nil, Socket::SOCK_STREAM, Socket::IPPROTO_TCP) + end + + def self.udp(host, port) + Addrinfo.new(Socket.sockaddr_in(port, host), nil, Socket::SOCK_DGRAM, Socket::IPPROTO_UDP) + end + + def self.unix(path, socktype=Socket::SOCK_STREAM) + Addrinfo.new(Socket.sockaddr_un(path), Socket::AF_UNIX, socktype) + end + + def afamily + @family + end + + #def bind + + attr_reader :canonname + + #def connect + #def connect_from + #def connect_to + + #def family_addrinfo(host, port=nil) + #def getnameinfo(flags=0) + # Socket.getnameinfo + #end + + def inspect + if ipv4? or ipv6? + if @protocol == Socket::IPPROTO_TCP + proto = 'TCP' + elsif @protocol == Socket::IPPROTO_UDP + proto = 'UDP' + else + proto = '???' + end + # how can we get the last part? + "#" + else + "#" + end + end + + def inspect_sockaddr + if ipv4? + a, p = ip_unpack + "#{a}:#{p}" + elsif ipv6? + a, p = ip_unpack + "[#{a}]:#{p}" + elsif unix? + unix_path + else + '???' + end + end + + def ip? + ipv4? or ipv6? + end + + def ip_address + ip_unpack[0] + end + + def ip_port + ip_unpack[1] + end + + def ip_unpack + h, p = getnameinfo(Socket::NI_NUMERICHOST|Socket::NI_NUMERICSERV) + [ h, p.to_i ] + end + + def ipv4? + @family == Socket::AF_INET + end + + #def ipv4_loopback? + #def ipv4_multicast? + #def ipv4_private? + + def ipv6? + @family == Socket::AF_INET6 + end + + #def ipv6_loopback? + #def ipv6_mc_global? + #def ipv6_mc_linklocal? + #def ipv6_mc_nodelocal? + #def ipv6_mc_orilocal? + #def ipv6_mc_sitelocal? + #def ipv6_multicast? + #def ipv6_to_ipv4 + #def ipv6_unspecified + #def ipv6_v4compat? + #def ipv6_v4mapped? + #def listen(backlog=5) + + def pfamily + @family + end + + attr_reader :protocol + attr_reader :socktype + + def to_sockaddr + @sockaddr + end + + alias to_s to_sockaddr + + def unix? + @family == Socket::AF_UNIX + end +end + +class BasicSocket + @@do_not_reverse_lookup = true + + def self.do_not_reverse_lookup + @@do_not_reverse_lookup + end + + def self.do_not_reverse_lookup=(val) + @@do_not_reverse_lookup = val ? true : false + end + + def initialize(*args) + super(*args) + @do_not_reverse_lookup = @@do_not_reverse_lookup + end + + #def connect_address + + def local_address + Addrinfo.new self.getsockname + end + + def recv_nonblock(maxlen, flags=0) + begin + _setnonblock(true) + recv(maxlen, flags) + ensure + _setnonblock(false) + end + end + + def remote_address + Addrinfo.new self.getpeername + end + + attr_accessor :do_not_reverse_lookup +end + +class IPSocket + def self.getddress(host) + Addrinfo.ip(host).ip_address + end + + def _ai_to_array(ai) + case ai.afamily + when Socket::AF_INET + s = "AF_INET" + when Socket::AF_INET6 + s = "AF_INET6" + when Socket::AF_UNIX + s = "AF_UNIX" + else + s = "(unknown AF)" + end + [ s, ai.ip_port, ai.ip_address, ai.ip_address ] + end + + def addr + _ai_to_array(Addrinfo.new(self.getsockname)) + end + + def peeraddr + _ai_to_array(Addrinfo.new(self.getpeername)) + end + + def recvfrom(maxlen, flags=0) + msg, sa = _recvfrom(maxlen, flags) + [ msg, _ai_to_array(Addrinfo.new(sa)) ] + end +end + +class TCPSocket + def initialize(host, service, local_host=nil, local_service=nil) + self._bless + if self.is_a? TCPServer + super(host, service) + else + ai = Addrinfo.getaddrinfo(host, service)[0] + super(Socket._socket(ai.afamily, Socket::SOCK_STREAM, 0), "r+") + # XXX: bind(2) + Socket._connect(self.fileno, ai.to_sockaddr) + self + end + end + + #def self.gethostbyname(host) +end + +class TCPServer + def initialize(host=nil, service) + self._bless + ai = Addrinfo.getaddrinfo(host, service, nil, nil, nil, Socket::AI_PASSIVE)[0] + super(Socket._socket(ai.afamily, Socket::SOCK_STREAM, 0), "r+") + Socket._bind(self.fileno, ai.to_sockaddr) + listen(5) + self + end + + def accept + TCPSocket.for_fd(self.sysaccept) + end + + def accept_nonblock + begin + self._setnonblock(true) + self.accept + ensure + self._setnonblock(false) + end + end + + def listen(backlog) + Socket._listen(self.fileno, backlog) + 0 + end + + def sysaccept + Socket._accept(self.fileno)[0] + end +end + +class UDPSocket + def initialize(af=Socket::AF_INET) + self._bless + super(Socket._socket(af, Socket::SOCK_DGRAM, 0), "r+") + self + end + + def bind(host, port) + Socket._bind(self.fileno, Socket.sockaddr_in(port, host)) + 0 + end + + def connect(host, port) + Socket._connect(self.fileno, Socket.sockaddr_in(port, host)) + 0 + end + + def recvfrom_nonblock(*args) + s = self + begin + self._setnonblock(true) + self.recvfrom(*args) + ensure + # XXX: self is a SystemcallException here! (should be bug) + s._setnonblock(false) + end + end + + def send(mesg, flags, host=nil, port=nil) + if port + super(mesg, flags, Socket.sockaddr_in(port, host)) + elsif host + super(mesg, flags, host) + else + super(mesg, flags) + end + end +end + +class Socket + def initialize(domain, type, protocol=0) + self._bless + super(Socket._socket(domain, type, protocol), "r+") + end + + #def self.accept_loop + + # def self.getaddrinfo + # by Addrinfo.getaddrinfo + #end + + #def self.getnameinfo + #def self.ip_address_list + + def self.open(*args) + new(args) + end + + def self.sockaddr_in(port, host) + ai = Addrinfo.getaddrinfo(host, port)[0] + ai.to_sockaddr + end + + #def self.tcp + #def self.tcp_server_loop + #def self.tcp_server_sockets + #def self.udp_server_loop + #def self.udp_server_loop_on + #def self.udp_server_recv + #def self.udp_server_sockets + #def self.unix(path) + #def self.unix_server_loop + #def self.unix_server_socket + + def self.unpack_sockaddr_in(sa) + Addrinfo.new(sa).ip_unpack.reverse + end + + def self.unpack_sockaddr_un(sa) + Addrinfo.new(sa).unix_path + end + + class << self + alias pack_sockaddr_in sockaddr_in + alias pack_sockaddr_un sockaddr_un + alias pair socketpair + end + + def accept + fd, addr = self.sysaccept + [ Socket.for_fd(fd), addr ] + end + + def accept_nonblock + begin + self._setnonblock(true) + self.accept + ensure + self._setnonblock(false) + end + end + + def bind(sockaddr) + sockaddr = sockaddr.to_sockaddr if sockaddr.is_a? Addrinfo + Socket._bind(self.fileno, sockaddr) + 0 + end + + def connect(sockaddr) + sockaddr = sockaddr.to_sockaddr if sockaddr.is_a? Addrinfo + Socket._bind(self.fileno, sockaddr) + 0 + end + + def connect_nonblock(sockaddr) + begin + self._setnonblock(true) + self.connect(sockaddr) + ensure + self._setnonblock(false) + end + end + + #def ipv6only! + + def listen(backlog) + Socket._listen(self.fileno, backlog) + 0 + end + + def recvfrom(maxlen, flags=0) + msg, sa = _recvfrom(maxlen, flags) + [ msg, _ai_to_array(Addrinfo.new(sa)) ] + end + + def recvfrom_nonblock(*args) + begin + self._setnonblock(true) + self._recvfrom(*args) + ensure + self._setnonblock(false) + end + end + + def sysaccept + Socket._accept(self.fileno)[0] + end +end + +class UNIXSocket + def initialize(path, &block) + self._bless + super(Socket._socket(AF_UNIX, SOCK_STREAM, 0), "r+") + Socket._connect(self.fileno, Socket.sockaddr_un(path)) + if block + block.call(self) + else + self + end + end + + def self.socketpair(type=Socket::SOCK_STREAM, protocol=0) + a = Socket.socketpair(Socket::AF_UNIX, type, protocol) + [ UNIXSocket.for_fd(a[0]), UNIXSocket.for_fd(a[1]) ] + end + + class << self + alias pair socketpair + end + + def addr + [ "AF_UNIX", path ] + end + + def path + Addrinfo.new(self.getsockname).unix_path + end + + def peeraddr + [ "AF_UNIX", Addrinfo.new(self.getpeername).unix_path ] + end + + #def recv_io + + def recvfrom(maxlen, flags=0) + msg, sa = _recvfrom(maxlen, flags) + [ msg, [ "AF_UNIX", Addrinfo.new(sa).unix_path ] ] + end + + #def send_io +end + +class UNIXServer + def initialize(path, &block) + self._bless + super(Socket._socket(Socket::AF_UNIX, Socket::SOCK_STREAM, 0), "r") + Socket._bind(self.fileno, Socket.pack_sockaddr_un(path)) + listen(5) + self + end + + def accept + fd, addr = self.sysaccept + [ UNIXSocket.for_fd(fd), addr ] + end + + def accept_nonblock + begin + self._setnonblock(true) + self.accept + ensure + self._setnonblock(false) + end + end + + def listen(backlog) + Socket._listen(self.fileno, backlog) + 0 + end + + def sysaccept + Socket._accept(self.fileno)[0] + end +end + +class Socket + include Constants +end + +class Socket + class Option + def initialize(family, level, optname, data) + @family = family + @level = level + @optname = optname + @data = data + end + + def self.bool(family, level, optname, bool) + self.new(family, level, optname, [(bool ? 1 : 0)].pack('i')) + end + + def self.int(family, level, optname, integer) + self.new(family, level, optname, [integer].pack('i')) + end + + #def self.linger(family, level, optname, integer) + #end + + attr_reader :data, :family, :level, :optname + + def bool + @data.unpack('i')[0] != 0 + end + + def inspect + # notyet + end + + def int + @data.unpack('i')[0] + end + + def linger + raise NotImplementedError.new + end + + def unpack(template) + raise NotImplementedError.new + end + end +end + +class SocketError < StandardError; end diff --git a/src/const.cstub b/src/const.cstub new file mode 100644 index 000000000..3ddac21dd --- /dev/null +++ b/src/const.cstub @@ -0,0 +1,219 @@ +#ifdef AF_INET + define_const(AF_INET); +#endif +#ifdef PF_INET + define_const(PF_INET); +#endif +#ifdef AF_INET6 + define_const(AF_INET6); +#endif +#ifdef PF_INET6 + define_const(PF_INET6); +#endif +#ifdef AF_LINK + define_const(AF_LINK); +#endif +#ifdef PF_LINK + define_const(PF_LINK); +#endif +#ifdef AF_LOCAL + define_const(AF_LOCAL); +#endif +#ifdef PF_LOCAL + define_const(PF_LOCAL); +#endif +#ifdef AF_UNIX + define_const(AF_UNIX); +#endif +#ifdef PF_UNIX + define_const(PF_UNIX); +#endif +#ifdef AF_MAX + define_const(AF_MAX); +#endif +#ifdef AF_UNSPEC + define_const(AF_UNSPEC); +#endif +#ifdef PF_UNSPEC + define_const(PF_UNSPEC); +#endif +#ifdef AF_ROUTE + define_const(AF_ROUTE); +#endif +#ifdef PF_ROUTE + define_const(PF_ROUTE); +#endif +#ifdef AI_CANONNAME + define_const(AI_CANONNAME); +#endif +#ifdef AI_FQDN + define_const(AI_FQDN); +#endif +#ifdef AI_NUMERICHOST + define_const(AI_NUMERICHOST); +#endif +#ifdef AI_NUMERICSERV + define_const(AI_NUMERICSERV); +#endif +#ifdef AI_PASSIVE + define_const(AI_PASSIVE); +#endif +#ifdef IPPROTO_ICMP + define_const(IPPROTO_ICMP); +#endif +#ifdef IPPROTO_IP + define_const(IPPROTO_IP); +#endif +#ifdef IPPROTO_IPV6 + define_const(IPPROTO_IPV6); +#endif +#ifdef IPPROTO_RAW + define_const(IPPROTO_RAW); +#endif +#ifdef IPPROTO_TCP + define_const(IPPROTO_TCP); +#endif +#ifdef IPPROTO_UDP + define_const(IPPROTO_UDP); +#endif +#ifdef MSG_BCAST + define_const(MSG_BCAST); +#endif +#ifdef MSG_CTRUNC + define_const(MSG_CTRUNC); +#endif +#ifdef MSG_DONTROUTE + define_const(MSG_DONTROUTE); +#endif +#ifdef MSG_DONTWAIT + define_const(MSG_DONTWAIT); +#endif +#ifdef MSG_EOR + define_const(MSG_EOR); +#endif +#ifdef MSG_MCAST + define_const(MSG_MCAST); +#endif +#ifdef MSG_NOSIGNAL + define_const(MSG_NOSIGNAL); +#endif +#ifdef MSG_OOB + define_const(MSG_OOB); +#endif +#ifdef MSG_PEEK + define_const(MSG_PEEK); +#endif +#ifdef MSG_TRUNC + define_const(MSG_TRUNC); +#endif +#ifdef MSG_WAITALL + define_const(MSG_WAITALL); +#endif +#ifdef NI_DGRAM + define_const(NI_DGRAM); +#endif +#ifdef NI_MAXHOST + define_const(NI_MAXHOST); +#endif +#ifdef NI_MAXSERV + define_const(NI_MAXSERV); +#endif +#ifdef NI_NAMEREQD + define_const(NI_NAMEREQD); +#endif +#ifdef NI_NOFQDN + define_const(NI_NOFQDN); +#endif +#ifdef NI_NUMERICHOST + define_const(NI_NUMERICHOST); +#endif +#ifdef NI_NUMERICSERV + define_const(NI_NUMERICSERV); +#endif +#ifdef SHUT_RD + define_const(SHUT_RD); +#endif +#ifdef SHUT_WR + define_const(SHUT_WR); +#endif +#ifdef SHUT_RDWR + define_const(SHUT_RDWR); +#endif +#ifdef SO_BINDANY + define_const(SO_BINDANY); +#endif +#ifdef SO_BROADCAST + define_const(SO_BROADCAST); +#endif +#ifdef SO_DEBUG + define_const(SO_DEBUG); +#endif +#ifdef SO_DONTROUTE + define_const(SO_DONTROUTE); +#endif +#ifdef SO_ERROR + define_const(SO_ERROR); +#endif +#ifdef SO_KEEPALIVE + define_const(SO_KEEPALIVE); +#endif +#ifdef SO_LINGER + define_const(SO_LINGER); +#endif +#ifdef SO_OOBINLINE + define_const(SO_OOBINLINE); +#endif +#ifdef SO_PEERCRED + define_const(SO_PEERCRED); +#endif +#ifdef SO_RCVBUF + define_const(SO_RCVBUF); +#endif +#ifdef SO_RCVLOWAT + define_const(SO_RCVLOWAT); +#endif +#ifdef SO_RCVTIMEO + define_const(SO_RCVTIMEO); +#endif +#ifdef SO_REUSEADDR + define_const(SO_REUSEADDR); +#endif +#ifdef SO_REUSEPORT + define_const(SO_REUSEPORT); +#endif +#ifdef SO_RTABLE + define_const(SO_RTABLE); +#endif +#ifdef SO_SNDBUF + define_const(SO_SNDBUF); +#endif +#ifdef SO_SNDLOWAT + define_const(SO_SNDLOWAT); +#endif +#ifdef SO_SNDTIMEO + define_const(SO_SNDTIMEO); +#endif +#ifdef SO_SPLICE + define_const(SO_SPLICE); +#endif +#ifdef SO_TIMESTAMP + define_const(SO_TIMESTAMP); +#endif +#ifdef SO_TYPE + define_const(SO_TYPE); +#endif +#ifdef SOCK_DGRAM + define_const(SOCK_DGRAM); +#endif +#ifdef SOCK_RAW + define_const(SOCK_RAW); +#endif +#ifdef SOCK_SEQPACKET + define_const(SOCK_SEQPACKET); +#endif +#ifdef SOCK_STREAM + define_const(SOCK_STREAM); +#endif +#ifdef SOL_SOCKET + define_const(SOL_SOCKET); +#endif diff --git a/src/const.def b/src/const.def new file mode 100644 index 000000000..7290a17fb --- /dev/null +++ b/src/const.def @@ -0,0 +1,81 @@ +AF_INET +PF_INET +AF_INET6 +PF_INET6 +AF_LINK +PF_LINK +AF_LOCAL +PF_LOCAL +AF_UNIX +PF_UNIX +AF_MAX +AF_UNSPEC +PF_UNSPEC +AF_ROUTE +PF_ROUTE + +AI_CANONNAME +AI_FQDN +AI_NUMERICHOST +AI_NUMERICSERV +AI_PASSIVE + +IPPROTO_ICMP +IPPROTO_IP +IPPROTO_IPV6 +IPPROTO_RAW +IPPROTO_TCP +IPPROTO_UDP + +MSG_BCAST +MSG_CTRUNC +MSG_DONTROUTE +MSG_DONTWAIT +MSG_EOR +MSG_MCAST +MSG_NOSIGNAL +MSG_OOB +MSG_PEEK +MSG_TRUNC +MSG_WAITALL + +NI_DGRAM +NI_MAXHOST +NI_MAXSERV +NI_NAMEREQD +NI_NOFQDN +NI_NUMERICHOST +NI_NUMERICSERV + +SHUT_RD +SHUT_WR +SHUT_RDWR + +SO_BINDANY +SO_BROADCAST +SO_DEBUG +SO_DONTROUTE +SO_ERROR +SO_KEEPALIVE +SO_LINGER +SO_OOBINLINE +SO_PEERCRED +SO_RCVBUF +SO_RCVLOWAT +SO_RCVTIMEO +SO_REUSEADDR +SO_REUSEPORT +SO_RTABLE +SO_SNDBUF +SO_SNDLOWAT +SO_SNDTIMEO +SO_SPLICE +SO_TIMESTAMP +SO_TYPE + +SOCK_DGRAM +SOCK_RAW +SOCK_SEQPACKET +SOCK_STREAM + +SOL_SOCKET diff --git a/src/gen.rb b/src/gen.rb new file mode 100755 index 000000000..8423dc442 --- /dev/null +++ b/src/gen.rb @@ -0,0 +1,17 @@ +#!/usr/bin/env ruby + +Dir.chdir(File.dirname($0)) + +f = File.open("const.cstub", "w") + +IO.readlines("const.def").each { |name| + name.sub(/^#.*/, "") + name.strip! + next if name.empty? + + f.write < +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mruby/array.h" +#include "mruby/class.h" +#include "mruby/data.h" +#include "mruby/string.h" +#include "mruby/variable.h" +#include "mruby/ext/io.h" + +#define E_SOCKET_ERROR (mrb_class_get(mrb, "SocketError")) + + +static mrb_value +mrb_addrinfo_getaddrinfo(mrb_state *mrb, mrb_value klass) +{ + struct addrinfo hints, *res0, *res; + struct sockaddr_un sun; + mrb_value ai, ary, family, lastai, nodename, protocol, s, sa, service, socktype; + mrb_int flags; + int arena_idx, error; + const char *hostname = NULL, *servname = NULL; + + ary = mrb_ary_new(mrb); + arena_idx = mrb_gc_arena_save(mrb); /* ary must be on arena! */ + + s = mrb_str_new(mrb, (void *)&sun, sizeof(sun)); + + family = socktype = protocol = mrb_nil_value(); + flags = 0; + mrb_get_args(mrb, "oo|oooi", &nodename, &service, &family, &socktype, &protocol, &flags); + + if (mrb_string_p(nodename)) { + hostname = mrb_str_to_cstr(mrb, nodename); + } else if (mrb_nil_p(nodename)) { + hostname = NULL; + } else { + mrb_raise(mrb, E_TYPE_ERROR, "nodename must be String or nil"); + } + + if (mrb_string_p(service)) { + servname = mrb_str_to_cstr(mrb, service); + } else if (mrb_fixnum_p(service)) { + servname = mrb_str_to_cstr(mrb, mrb_funcall(mrb, service, "to_s", 0)); + } else if (mrb_nil_p(nodename)) { + servname = NULL; + } else { + mrb_raise(mrb, E_TYPE_ERROR, "service must be String, Fixnum, or nil"); + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = flags; + + if (mrb_fixnum_p(family)) { + hints.ai_family = mrb_fixnum(family); + } + + if (mrb_fixnum_p(socktype)) { + hints.ai_socktype = mrb_fixnum(socktype); + } + + lastai = mrb_cv_get(mrb, klass, mrb_intern_cstr(mrb, "_lastai")); + if (mrb_voidp_p(ai)) { + freeaddrinfo(mrb_voidp(ai)); + mrb_cv_set(mrb, klass, mrb_intern_cstr(mrb, "_lastai"), mrb_nil_value()); + } + + error = getaddrinfo(hostname, servname, &hints, &res0); + if (error) { + mrb_raisef(mrb, E_SOCKET_ERROR, "getaddrinfo: %S", mrb_str_new_cstr(mrb, gai_strerror(error))); + } + mrb_cv_set(mrb, klass, mrb_intern_cstr(mrb, "_lastai"), mrb_voidp_value(res0)); + + for (res = res0; res != NULL; res = res->ai_next) { + sa = mrb_str_new(mrb, (void *)res->ai_addr, res->ai_addrlen); + 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)); + mrb_ary_push(mrb, ary, ai); + mrb_gc_arena_restore(mrb, arena_idx); + } + + freeaddrinfo(res0); + mrb_cv_set(mrb, klass, mrb_intern_cstr(mrb, "_lastai"), mrb_nil_value()); + + return ary; +} + +static mrb_value +mrb_addrinfo_getnameinfo(mrb_state *mrb, mrb_value self) +{ + mrb_int flags; + mrb_value ary, host, sastr, serv; + int error; + + flags = 0; + mrb_get_args(mrb, "|i", &flags); + host = mrb_str_buf_new(mrb, NI_MAXHOST); + serv = mrb_str_buf_new(mrb, NI_MAXSERV); + + sastr = mrb_iv_get(mrb, self, mrb_intern(mrb, "@sockaddr")); + if (!mrb_string_p(sastr)) { + mrb_raise(mrb, E_SOCKET_ERROR, "invalid sockaddr"); + } + error = getnameinfo((struct sockaddr *)RSTRING_PTR(sastr), (socklen_t)RSTRING_LEN(sastr), RSTRING_PTR(host), NI_MAXHOST, RSTRING_PTR(serv), NI_MAXSERV, flags); + if (error != 0) { + mrb_raisef(mrb, E_SOCKET_ERROR, "getnameinfo: %s", gai_strerror(error)); + } + ary = mrb_ary_new_capa(mrb, 2); + mrb_str_resize(mrb, host, strlen(RSTRING_PTR(host))); + mrb_ary_push(mrb, ary, host); + mrb_str_resize(mrb, serv, strlen(RSTRING_PTR(serv))); + mrb_ary_push(mrb, ary, serv); + return ary; +} + +static mrb_value +mrb_addrinfo_unix_path(mrb_state *mrb, mrb_value self) +{ + mrb_value sastr; + + sastr = mrb_iv_get(mrb, self, mrb_intern(mrb, "@sockaddr")); + if (((struct sockaddr *)RSTRING_PTR(sastr))->sa_family != AF_UNIX) + mrb_raise(mrb, E_SOCKET_ERROR, "need AF_UNIX address"); + return mrb_str_new_cstr(mrb, ((struct sockaddr_un *)RSTRING_PTR(sastr))->sun_path); +} + +static mrb_value +sa2addrlist(mrb_state *mrb, const struct sockaddr *sa, socklen_t salen) +{ + mrb_value ary, host; + unsigned short port; + const char *afstr; + + switch (sa->sa_family) { + case AF_INET: + afstr = "AF_INET"; + port = ((struct sockaddr_in *)sa)->sin_port; + break; + case AF_INET6: + afstr = "AF_INET6"; + port = ((struct sockaddr_in6 *)sa)->sin6_port; + break; + default: + mrb_raise(mrb, E_ARGUMENT_ERROR, "bad af"); + return mrb_nil_value(); + } + port = ntohs(port); + host = mrb_str_buf_new(mrb, NI_MAXHOST); + if (getnameinfo(sa, salen, RSTRING_PTR(host), NI_MAXHOST, NULL, 0, NI_NUMERICHOST) == -1) + mrb_sys_fail(mrb, "getnameinfo"); + mrb_str_resize(mrb, host, strlen(RSTRING_PTR(host))); + ary = mrb_ary_new_capa(mrb, 4); + mrb_ary_push(mrb, ary, mrb_str_new_cstr(mrb, afstr)); + mrb_ary_push(mrb, ary, mrb_fixnum_value(port)); + mrb_ary_push(mrb, ary, host); + mrb_ary_push(mrb, ary, host); + return ary; +} + +static int +socket_fd(mrb_state *mrb, mrb_value sock) +{ + return mrb_fixnum(mrb_funcall(mrb, sock, "fileno", 0)); +} + +static int +socket_family(int s) +{ + struct sockaddr_storage ss; + socklen_t salen; + + salen = sizeof(ss); + if (getsockname(s, (struct sockaddr *)&ss, &salen) == -1) + return AF_UNSPEC; + return ss.ss_family; +} + +static mrb_value +mrb_basicsocket_getpeereid(mrb_state *mrb, mrb_value self) +{ + mrb_value ary; + gid_t egid; + uid_t euid; + int s; + + s = socket_fd(mrb, self); + if (getpeereid(s, &euid, &egid) != 0) + mrb_sys_fail(mrb, "getpeereid"); + + ary = mrb_ary_new_capa(mrb, 2); + mrb_ary_push(mrb, ary, mrb_fixnum_value((mrb_int)euid)); + mrb_ary_push(mrb, ary, mrb_fixnum_value((mrb_int)egid)); + return ary; +} + +static mrb_value +mrb_basicsocket_getpeername(mrb_state *mrb, mrb_value self) +{ + struct sockaddr_storage ss; + socklen_t salen; + + salen = sizeof(ss); + if (getpeername(socket_fd(mrb, self), (struct sockaddr *)&ss, &salen) != 0) + mrb_sys_fail(mrb, "getpeername"); + + return mrb_str_new(mrb, (void *)&ss, salen); +} + +static mrb_value +mrb_basicsocket_getsockname(mrb_state *mrb, mrb_value self) +{ + struct sockaddr_storage ss; + socklen_t salen; + + salen = sizeof(ss); + if (getsockname(socket_fd(mrb, self), (struct sockaddr *)&ss, &salen) != 0) + mrb_sys_fail(mrb, "getsockname"); + + return mrb_str_new(mrb, (void *)&ss, salen); +} + +static mrb_value +mrb_basicsocket_getsockopt(mrb_state *mrb, mrb_value self) +{ + int opt, s; + mrb_int family, level, optname; + mrb_value c, data; + socklen_t optlen; + + mrb_get_args(mrb, "ii", &level, &optname); + s = socket_fd(mrb, self); + optlen = sizeof(opt); + if (getsockopt(s, level, optname, &opt, &optlen) == -1) + mrb_sys_fail(mrb, "getsockopt"); + c = mrb_const_get(mrb, mrb_obj_value(mrb_class_get(mrb, "Socket")), mrb_intern(mrb, "Option")); + family = socket_family(s); + data = mrb_str_new(mrb, (char *)&opt, sizeof(int)); + return mrb_funcall(mrb, c, "new", 4, mrb_fixnum_value(family), mrb_fixnum_value(level), mrb_fixnum_value(optname), data); +} + +static mrb_value +mrb_basicsocket_recv(mrb_state *mrb, mrb_value self) +{ + int n; + mrb_int maxlen, flags = 0; + mrb_value buf; + + mrb_get_args(mrb, "i|i", &maxlen, &flags); + buf = mrb_str_buf_new(mrb, maxlen); + n = recv(socket_fd(mrb, self), RSTRING_PTR(buf), maxlen, flags); + if (n == -1) + mrb_sys_fail(mrb, "recv"); + mrb_str_resize(mrb, buf, n); + return buf; +} + +static mrb_value +mrb_basicsocket_recvfrom(mrb_state *mrb, mrb_value self) +{ + int n; + mrb_int maxlen, flags = 0; + mrb_value ary, buf, sa; + socklen_t socklen; + + mrb_get_args(mrb, "i|i", &maxlen, &flags); + buf = mrb_str_buf_new(mrb, maxlen); + socklen = sizeof(struct sockaddr_storage); + sa = mrb_str_buf_new(mrb, socklen); + n = recvfrom(socket_fd(mrb, self), RSTRING_PTR(buf), maxlen, flags, (struct sockaddr *)RSTRING_PTR(sa), &socklen); + if (n == -1) + mrb_sys_fail(mrb, "recvfrom"); + mrb_str_resize(mrb, buf, n); + mrb_str_resize(mrb, sa, socklen); + ary = mrb_ary_new_capa(mrb, 2); + mrb_ary_push(mrb, ary, buf); + mrb_ary_push(mrb, ary, sa); + return ary; +} + +static mrb_value +mrb_basicsocket_send(mrb_state *mrb, mrb_value self) +{ + int n; + mrb_int flags; + mrb_value dest, mesg; + + dest = mrb_nil_value(); + mrb_get_args(mrb, "Si|S", &mesg, &flags, &dest); + if (mrb_nil_p(dest)) { + n = send(socket_fd(mrb, self), RSTRING_PTR(mesg), RSTRING_LEN(mesg), flags); + } else { + // XXX: length check + n = sendto(socket_fd(mrb, self), RSTRING_PTR(mesg), RSTRING_LEN(mesg), flags, (const void *)RSTRING_PTR(dest), RSTRING_LEN(dest)); + } + if (n == -1) + mrb_sys_fail(mrb, "send"); + return mrb_fixnum_value(n); +} + +static mrb_value +mrb_basicsocket_setnonblock(mrb_state *mrb, mrb_value self) +{ + int fd, flags; + mrb_value bool; + + mrb_get_args(mrb, "o", &bool); + fd = socket_fd(mrb, self); + + flags = fcntl(fd, F_GETFL, 0); + if (flags == 1) + mrb_sys_fail(mrb, "fcntl"); + if (mrb_test(bool)) + flags |= O_NONBLOCK; + else + flags &= ~O_NONBLOCK; + if (fcntl(fd, F_SETFL, flags) == -1) + mrb_sys_fail(mrb, "fcntl"); + return mrb_nil_value(); +} + +static mrb_value +mrb_basicsocket_setsockopt(mrb_state *mrb, mrb_value self) +{ + int argc, s; + mrb_int level = 0, optname; + mrb_value optval, so; + + argc = mrb_get_args(mrb, "o|io", &so, &optname, &optval); + if (argc == 3) { + if (!mrb_fixnum_p(so)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "level is not an integer"); + } + level = mrb_fixnum(so); + if (mrb_string_p(optval)) { + /* that's good */ + } else if (mrb_type(optval) == MRB_TT_TRUE || mrb_type(optval) == MRB_TT_FALSE) { + mrb_int i = mrb_test(optval) ? 1 : 0; + optval = mrb_str_new(mrb, (char *)&i, sizeof(i)); + } else if (mrb_fixnum_p(optval)) { + mrb_int i = mrb_fixnum(optval); + optval = mrb_str_new(mrb, (char *)&i, sizeof(i)); + } else { + mrb_raise(mrb, E_ARGUMENT_ERROR, "optval should be true, false, an integer, or a string"); + } + } else if (argc == 1) { + if (strcmp(mrb_obj_classname(mrb, so), "Socket::Option") != 0) + mrb_raisef(mrb, E_ARGUMENT_ERROR, "not an instance of Socket::Option"); + level = mrb_fixnum(mrb_funcall(mrb, so, "level", 0)); + optname = mrb_fixnum(mrb_funcall(mrb, so, "optname", 0)); + optval = mrb_funcall(mrb, so, "data", 0); + } else { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%d for 3)", argc); + } + + s = socket_fd(mrb, self); + if (setsockopt(s, level, optname, RSTRING_PTR(optval), RSTRING_LEN(optval)) == -1) + mrb_sys_fail(mrb, "setsockopt"); + return mrb_fixnum_value(0); +} + +static mrb_value +mrb_basicsocket_shutdown(mrb_state *mrb, mrb_value self) +{ + mrb_int how = SHUT_RDWR; + + mrb_get_args(mrb, "|i", &how); + if (shutdown(socket_fd(mrb, self), how) != 0) + mrb_sys_fail(mrb, "shutdown"); + return mrb_fixnum_value(0); +} + +static mrb_value +mrb_ipsocket_ntop(mrb_state *mrb, mrb_value klass) +{ + mrb_int af, n; + char *addr, buf[50]; + + mrb_get_args(mrb, "is", &af, &addr, &n); + if ((af == AF_INET && n != 4) || (af == AF_INET6 && n != 16)) + mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid address"); + if (inet_ntop(af, addr, buf, sizeof(buf)) == NULL) + mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid address"); + return mrb_str_new_cstr(mrb, buf); +} + +static mrb_value +mrb_ipsocket_pton(mrb_state *mrb, mrb_value klass) +{ + mrb_int af, n; + char *bp, buf[50]; + + mrb_get_args(mrb, "is", &af, &bp, &n); + if (n > sizeof(buf) - 1) + mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid address"); + memcpy(buf, bp, n); + buf[n] = '\0'; + + if (af == AF_INET) { + struct in_addr in; + if (inet_pton(AF_INET, buf, (void *)&in.s_addr) != 1) + goto invalid; + return mrb_str_new(mrb, (char *)&in.s_addr, 4); + } else if (af == AF_INET6) { + struct in6_addr in6; + if (inet_pton(AF_INET6, buf, (void *)&in6.s6_addr) != 1) + goto invalid; + return mrb_str_new(mrb, (char *)&in6.s6_addr, 16); + } else + mrb_raise(mrb, E_ARGUMENT_ERROR, "unsupported address family"); + +invalid: + mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid address"); + return mrb_nil_value(); /* dummy */ +} + +static mrb_value +mrb_ipsocket_recvfrom(mrb_state *mrb, mrb_value self) +{ + struct sockaddr_storage ss; + socklen_t socklen; + mrb_value a, buf, pair; + mrb_int flags, maxlen, n; + int fd; + + fd = socket_fd(mrb, self); + flags = 0; + mrb_get_args(mrb, "i|i", &maxlen, &flags); + buf = mrb_str_buf_new(mrb, maxlen); + socklen = sizeof(ss); + n = recvfrom(fd, RSTRING_PTR(buf), maxlen, flags, + (struct sockaddr *)&ss, &socklen); + if (n == -1) { + mrb_sys_fail(mrb, "recvfrom"); + } + mrb_str_resize(mrb, buf, n); + a = sa2addrlist(mrb, (struct sockaddr *)&ss, socklen); + pair = mrb_ary_new_capa(mrb, 2); + mrb_ary_push(mrb, pair, buf); + mrb_ary_push(mrb, pair, a); + return pair; +} + +static mrb_value +mrb_udpsocket_bind(mrb_state *mrb, mrb_value self) +{ + struct addrinfo hints, *res; + mrb_int n, port; + int error, s; + char *host, hostbuf[256], portbuf[6]; + + s = socket_fd(mrb, self); + mrb_get_args(mrb, "si", &host, &n, &port); + if (n > sizeof(hostbuf) - 1) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "host is too long"); + } + memcpy(hostbuf, host, n); + hostbuf[n] = '\0'; + + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_NUMERICSERV|AI_PASSIVE; + snprintf(portbuf, sizeof(portbuf), "%d", port); + error = getaddrinfo(hostbuf, portbuf, &hints, &res); + if (error != 0) + mrb_raise(mrb, E_RUNTIME_ERROR, "getaddrinfo(2) failed"); + if (bind(s, res->ai_addr, res->ai_addrlen) == -1) { + freeaddrinfo(res); + mrb_raise(mrb, E_RUNTIME_ERROR, "bind(2) failed"); + } + freeaddrinfo(res); + return mrb_fixnum_value(0); +} + +static mrb_value +mrb_udpsocket_connect(mrb_state *mrb, mrb_value self) +{ + struct addrinfo hints, *res; + mrb_int n, port; + int error, s; + char *host, hostbuf[256], portbuf[6]; + + mrb_get_args(mrb, "si", &host, &n, &port); + s = socket_fd(mrb, self); + + if (n > sizeof(hostbuf) - 1) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "host is too long"); + } + memcpy(hostbuf, host, n); + hostbuf[n] = '\0'; + + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_NUMERICSERV; + snprintf(portbuf, sizeof(portbuf), "%d", port); + error = getaddrinfo(hostbuf, portbuf, &hints, &res); + if (error != 0) + mrb_raise(mrb, E_RUNTIME_ERROR, "getaddrinfo(2) failed"); + if (connect(s, res->ai_addr, res->ai_addrlen) == -1) { + freeaddrinfo(res); + mrb_raise(mrb, E_RUNTIME_ERROR, "connect(2) failed"); + } + freeaddrinfo(res); + return mrb_fixnum_value(0); +} + +static mrb_value +mrb_udpsocket_send(mrb_state *mrb, mrb_value self) +{ + struct addrinfo hints, *res; + mrb_int n, flags; + mrb_value host, port; + int argc, hlen, s; + char hostbuf[256], *msg, portbuf[6]; + + argc = mrb_get_args(mrb, "si|oo", &msg, &hlen, &flags, &host, &port); + s = socket_fd(mrb, self); + n = -1; + if (argc == 2) { + n = send(s, msg, hlen, flags); + } else if (argc == 4) { + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + hints.ai_flags = AI_NUMERICHOST|AI_NUMERICSERV; + memcpy(hostbuf, RSTRING_PTR(host), RSTRING_LEN(host)); + hostbuf[RSTRING_LEN(host)] = '\0'; + snprintf(portbuf, sizeof(portbuf), "%u", mrb_fixnum(port)); + if (getaddrinfo(hostbuf, portbuf, &hints, &res) != 0) + mrb_sys_fail(mrb, "getaddrinfo"); + // XXX: try all addresses? + n = sendto(s, msg, hlen, flags, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + } + if (n == -1) + mrb_sys_fail(mrb, "send"); + return mrb_fixnum_value(n); +} + +static mrb_value +mrb_socket_gethostname(mrb_state *mrb, mrb_value cls) +{ + mrb_value buf; + +#ifdef HOST_NAME_MAX + buf = mrb_str_buf_new(mrb, HOST_NAME_MAX+1); +#else + buf = mrb_str_buf_new(mrb, 256); +#endif + if (gethostname(RSTRING_PTR(buf), RSTRING_LEN(buf)) != 0) + mrb_sys_fail(mrb, "gethostname"); + return buf; +} + +static mrb_value +mrb_socket_accept(mrb_state *mrb, mrb_value klass) +{ + mrb_value ary, sastr; + int s1; + mrb_int s0; + socklen_t socklen; + + mrb_get_args(mrb, "i", &s0); + socklen = sizeof(struct sockaddr_storage); + sastr = mrb_str_buf_new(mrb, socklen); + s1 = accept(s0, (struct sockaddr *)RSTRING_PTR(sastr), &socklen); + if (s1 == -1) { + mrb_sys_fail(mrb, "accept"); + } + // XXX: possible descriptor leakage here! + mrb_str_resize(mrb, sastr, socklen); + ary = mrb_ary_new_capa(mrb, 2); + mrb_ary_push(mrb, ary, mrb_fixnum_value(s1)); + mrb_ary_push(mrb, ary, sastr); + return ary; +} + +static mrb_value +mrb_socket_bind(mrb_state *mrb, mrb_value klass) +{ + mrb_value sastr; + int s; + + mrb_get_args(mrb, "iS", &s, &sastr); + if (bind(s, (struct sockaddr *)RSTRING_PTR(sastr), (socklen_t)RSTRING_LEN(sastr)) == -1) { + mrb_sys_fail(mrb, "bind"); + } + return mrb_nil_value(); +} + +static mrb_value +mrb_socket_connect(mrb_state *mrb, mrb_value klass) +{ + mrb_value sastr; + int s; + + mrb_get_args(mrb, "iS", &s, &sastr); + if (connect(s, (struct sockaddr *)RSTRING_PTR(sastr), (socklen_t)RSTRING_LEN(sastr)) == -1) { + mrb_sys_fail(mrb, "connect"); + } + return mrb_nil_value(); +} + +static mrb_value +mrb_socket_listen(mrb_state *mrb, mrb_value klass) +{ + int backlog, s; + + mrb_get_args(mrb, "ii", &s, &backlog); + if (listen(s, backlog) == -1) { + mrb_sys_fail(mrb, "listen"); + } + return mrb_nil_value(); +} + +static mrb_value +mrb_socket_sockaddr_family(mrb_state *mrb, mrb_value klass) +{ + mrb_value sa; + + mrb_get_args(mrb, "S", &sa); + if (RSTRING_LEN(sa) < sizeof(struct sockaddr)) { + mrb_raisef(mrb, E_SOCKET_ERROR, "invalid sockaddr (too short)"); + } + return mrb_fixnum_value(((struct sockaddr *)RSTRING_PTR(sa))->sa_family); +} + +static mrb_value +mrb_socket_sockaddr_un(mrb_state *mrb, mrb_value klass) +{ + struct sockaddr_un *sunp; + mrb_value path, s; + + mrb_get_args(mrb, "S", &path); + if (RSTRING_LEN(path) > sizeof(sunp->sun_path) - 1) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "too long unix socket path (max: %ubytes)", (unsigned int)sizeof(sunp->sun_path) - 1); + } + s = mrb_str_buf_new(mrb, sizeof(struct sockaddr_un)); + sunp = (struct sockaddr_un *)RSTRING_PTR(s); + sunp->sun_family = AF_UNIX; + memcpy(sunp->sun_path, RSTRING_PTR(path), RSTRING_LEN(path)); + sunp->sun_path[RSTRING_LEN(path)] = '\0'; + mrb_str_resize(mrb, s, sizeof(struct sockaddr_un)); + return s; +} + +static mrb_value +mrb_socket_socketpair(mrb_state *mrb, mrb_value klass) +{ + mrb_value ary; + mrb_int domain, type, protocol; + int sv[2]; + + mrb_get_args(mrb, "iii", &domain, &type, &protocol); + if (socketpair(domain, type, protocol, sv) == -1) { + mrb_sys_fail(mrb, "socketpair"); + } + // XXX: possible descriptor leakage here! + ary = mrb_ary_new_capa(mrb, 2); + mrb_ary_push(mrb, ary, mrb_fixnum_value(sv[0])); + mrb_ary_push(mrb, ary, mrb_fixnum_value(sv[1])); + return ary; +} + +static mrb_value +mrb_socket_socket(mrb_state *mrb, mrb_value klass) +{ + mrb_int domain, type, protocol; + int s; + + mrb_get_args(mrb, "iii", &domain, &type, &protocol); + s = socket(domain, type, protocol); + if (s == -1) + mrb_sys_fail(mrb, "socket"); + return mrb_fixnum_value(s); +} + +void +mrb_mruby_socket_gem_init(mrb_state* mrb) +{ + struct RClass *io, *ai, *sock, *bsock, *ipsock, *tcpsock, *udpsock, *usock; + struct RClass *constants; + + ai = mrb_define_class(mrb, "Addrinfo", mrb->object_class); + mrb_mod_cv_set(mrb, ai, mrb_intern_cstr(mrb, "_lastai"), mrb_nil_value()); + mrb_define_class_method(mrb, ai, "getaddrinfo", mrb_addrinfo_getaddrinfo, ARGS_REQ(2)|ARGS_OPT(4)); + mrb_define_method(mrb, ai, "getnameinfo", mrb_addrinfo_getnameinfo, ARGS_OPT(1)); + mrb_define_method(mrb, ai, "unix_path", mrb_addrinfo_unix_path, ARGS_NONE()); + + io = mrb_class_get(mrb, "IO"); + + bsock = mrb_define_class(mrb, "BasicSocket", io); + mrb_define_method(mrb, bsock, "_recvfrom", mrb_basicsocket_recvfrom, ARGS_REQ(1)|ARGS_OPT(1)); + mrb_define_method(mrb, bsock, "_setnonblock", mrb_basicsocket_setnonblock, ARGS_REQ(1)); + mrb_define_method(mrb, bsock, "getpeereid", mrb_basicsocket_getpeereid, ARGS_NONE()); + mrb_define_method(mrb, bsock, "getpeername", mrb_basicsocket_getpeername, ARGS_NONE()); + mrb_define_method(mrb, bsock, "getsockname", mrb_basicsocket_getsockname, ARGS_NONE()); + mrb_define_method(mrb, bsock, "getsockopt", mrb_basicsocket_getsockopt, ARGS_REQ(2)); + mrb_define_method(mrb, bsock, "recv", mrb_basicsocket_recv, ARGS_REQ(1)|ARGS_OPT(1)); + // #recvmsg(maxlen, flags=0) + mrb_define_method(mrb, bsock, "send", mrb_basicsocket_send, ARGS_REQ(2)|ARGS_OPT(1)); + // #sendmsg + // #sendmsg_nonblock + mrb_define_method(mrb, bsock, "setsockopt", mrb_basicsocket_setsockopt, ARGS_REQ(1)|ARGS_OPT(2)); + mrb_define_method(mrb, bsock, "shutdown", mrb_basicsocket_shutdown, ARGS_OPT(1)); + + ipsock = mrb_define_class(mrb, "IPSocket", bsock); + mrb_define_class_method(mrb, ipsock, "ntop", mrb_ipsocket_ntop, ARGS_REQ(1)); + mrb_define_class_method(mrb, ipsock, "pton", mrb_ipsocket_pton, ARGS_REQ(2)); + mrb_define_method(mrb, ipsock, "recvfrom", mrb_ipsocket_recvfrom, ARGS_REQ(1)|ARGS_OPT(1)); + + tcpsock = mrb_define_class(mrb, "TCPSocket", ipsock); + //mrb_define_class_method(mrb, tcpsock, "open", mrb_tcpsocket_open, ARGS_REQ(2)|ARGS_OPT(2)); + //mrb_define_class_method(mrb, tcpsock, "new", mrb_tcpsocket_open, ARGS_REQ(2)|ARGS_OPT(2)); + mrb_define_class(mrb, "TCPServer", tcpsock); + + udpsock = mrb_define_class(mrb, "UDPSocket", ipsock); + //#recvfrom_nonblock + + sock = mrb_define_class(mrb, "Socket", bsock); + mrb_define_class_method(mrb, sock, "_accept", mrb_socket_accept, ARGS_REQ(1)); + mrb_define_class_method(mrb, sock, "_bind", mrb_socket_bind, ARGS_REQ(3)); + mrb_define_class_method(mrb, sock, "_connect", mrb_socket_connect, ARGS_REQ(3)); + mrb_define_class_method(mrb, sock, "_listen", mrb_socket_listen, ARGS_REQ(2)); + mrb_define_class_method(mrb, sock, "_sockaddr_family", mrb_socket_sockaddr_family, ARGS_REQ(1)); + mrb_define_class_method(mrb, sock, "_socket", mrb_socket_socket, ARGS_REQ(3)); + //mrb_define_class_method(mrb, sock, "gethostbyaddr", mrb_socket_gethostbyaddr, ARGS_REQ(1)|ARGS_OPT(1)); + //mrb_define_class_method(mrb, sock, "gethostbyname", mrb_socket_gethostbyname, ARGS_REQ(1)|ARGS_OPT(1)); + mrb_define_class_method(mrb, sock, "gethostname", mrb_socket_gethostname, ARGS_NONE()); + //mrb_define_class_method(mrb, sock, "getservbyname", mrb_socket_getservbyname, ARGS_REQ(1)|ARGS_OPT(1)); + //mrb_define_class_method(mrb, sock, "getservbyport", mrb_socket_getservbyport, ARGS_REQ(1)|ARGS_OPT(1)); + mrb_define_class_method(mrb, sock, "sockaddr_un", mrb_socket_sockaddr_un, ARGS_REQ(1)); + mrb_define_class_method(mrb, sock, "socketpair", mrb_socket_socketpair, ARGS_REQ(3)); + //mrb_define_method(mrb, sock, "sysaccept", mrb_socket_accept, ARGS_NONE()); + + usock = mrb_define_class(mrb, "UNIXSocket", io); + //mrb_define_class_method(mrb, usock, "pair", mrb_unixsocket_open, ARGS_OPT(2)); + //mrb_define_class_method(mrb, usock, "socketpair", mrb_unixsocket_open, ARGS_OPT(2)); + + //mrb_define_method(mrb, usock, "recv_io", mrb_unixsocket_peeraddr, ARGS_NONE()); + //mrb_define_method(mrb, usock, "recvfrom", mrb_unixsocket_peeraddr, ARGS_NONE()); + //mrb_define_method(mrb, usock, "send_io", mrb_unixsocket_peeraddr, ARGS_NONE()); + + constants = mrb_define_module_under(mrb, sock, "Constants"); + +#define define_const(SYM) \ + do { \ + mrb_define_const(mrb, constants, #SYM, mrb_fixnum_value(SYM)); \ + } while (0) + +#include "const.cstub" +} + +void +mrb_mruby_socket_gem_final(mrb_state* mrb) +{ + mrb_value ai; + ai = mrb_mod_cv_get(mrb, mrb_class_get(mrb, "Addrinfo"), mrb_intern_cstr(mrb, "_lastai")); + if (mrb_voidp_p(ai)) { + freeaddrinfo(mrb_voidp(ai)); + } +} diff --git a/test/socket.rb b/test/socket.rb new file mode 100644 index 000000000..b7fd458c4 --- /dev/null +++ b/test/socket.rb @@ -0,0 +1,139 @@ +assert('Addrinfo') do + assert_equal(Class, Addrinfo.class) +end + +assert('super class of Addrinfo') do + assert_equal(Object, Addrinfo.superclass) +end + +assert('Addrinfo.getadrinfo') do + ary = Addrinfo.getaddrinfo("localhost", "domain", Socket::AF_INET, Socket::SOCK_STREAM) + assert_equal(ary.size, 1) + ai = ary[0] + assert_equal(ai.afamily, Socket::AF_INET) + assert_equal(ai.pfamily, Socket::PF_INET) + assert_equal(ai.socktype, Socket::SOCK_STREAM) + assert_equal(ai.ip_address, '127.0.0.1') + assert_equal(ai.ip_port, 53) +end + +assert('Addrinfo.foreach') do + # assume Addrinfo.getaddrinfo works well + b = [] + a = Addrinfo.foreach("localhost", "domain") { |ai| + assert_include([Socket::AF_INET, Socket::AF_INET6], ai.afamily) + if ai.afamily == Socket::AF_INET + assert_equal(ai.ip_address, '127.0.0.1') + else + assert_equal(ai.ip_address, '::1') + end + assert_equal(ai.ip_port, 53) + assert_include([Socket::SOCK_STREAM, Socket::SOCK_DGRAM], ai.socktype) + b << ai + } + assert_equal(a.size, b.size) +end + +assert('Addrinfo.ip') do + ai = Addrinfo.ip('127.0.0.1') + assert_equal('127.0.0.1', ai.ip_address) + assert_equal(Socket::AF_INET, ai.afamily) + assert_equal(0, ai.ip_port) + assert_equal(0, ai.socktype) + assert_equal(0, ai.protocol) +end + +assert('Addrinfo.tcp') do + ai = Addrinfo.tcp('127.0.0.1', 'smtp') + assert_equal('127.0.0.1', ai.ip_address) + assert_equal(Socket::AF_INET, ai.afamily) + assert_equal(25, ai.ip_port) + assert_equal(Socket::SOCK_STREAM, ai.socktype) + assert_equal(Socket::IPPROTO_TCP, ai.protocol) +end + +assert('Addrinfo.udp') do + ai = Addrinfo.udp('127.0.0.1', 'domain') + assert_equal('127.0.0.1', ai.ip_address) + assert_equal(Socket::AF_INET, ai.afamily) + assert_equal(53, ai.ip_port) + assert_equal(Socket::SOCK_DGRAM, ai.socktype) + assert_equal(Socket::IPPROTO_UDP, ai.protocol) +end + +assert('Addrinfo.unix') do + a1 = Addrinfo.unix('/tmp/sock') + assert_true(a1.unix?) + assert_equal('/tmp/sock', a1.unix_path) + assert_equal(Socket::SOCK_STREAM, a1.socktype) + a2 = Addrinfo.unix('/tmp/sock', Socket::SOCK_DGRAM) + assert_equal(Socket::SOCK_DGRAM, a2.socktype) +end + +assert('Addrinfo#afamily') do + ai4 = Addrinfo.new(Socket.sockaddr_in(1, '127.0.0.1')) + ai6 = Addrinfo.new(Socket.sockaddr_in(1, '::1')) + aiu = Addrinfo.new(Socket.sockaddr_un('/tmp/sock')) + assert_equal(Socket::AF_INET, ai4.afamily) + assert_equal(Socket::AF_INET6, ai6.afamily) + assert_equal(Socket::AF_UNIX, aiu.afamily) +end + +# assert('Addrinfo#canonname') do + +# #getnameinfo +# assert('Addrinfo#inspect') do +# assert('Addrinfo#inspect_socket') do +# assert('Addrinfo#ip?') do +# assert('Addrinfo#ip_address') do +# assert('Addrinfo#ip_port') do +# assert('Addrinfo#ip_unpack') do +# assert('Addrinfo#ipv4?') do +# assert('Addrinfo#ipv6?') do +# assert('Addrinfo#pfamily') do +# assert('Addrinfo#protocol') do +# assert('Addrinfo#socktype') do +# assert('Addrinfo#to_sockaddr') do +# assert('Addrinfo#unix?') do +# #unix_path + + +assert('BasicSocket') do + assert_equal(Class, BasicSocket.class) +end + +assert('super class of BasicSocket') do + assert_equal(IO, BasicSocket.superclass) +end + +assert('BasicSocket.do_not_reverse_lookup') do + assert_equal(BasicSocket.do_not_reverse_lookup, true) +end + +assert('BasicSocket.do_not_reverse_lookup=') do + BasicSocket.do_not_reverse_lookup = false + assert_equal(BasicSocket.do_not_reverse_lookup, false) + BasicSocket.do_not_reverse_lookup = true +end + +assert('UDPSocket.new') do + s = UDPSocket.new + assert_true(s.is_a? UDPSocket) + s.close + s = UDPSocket.new(Socket::AF_INET6) + assert_true(s.is_a? UDPSocket) + s.close + true +end + +#assert('UDPSocket#connect') do +#assert('UDPSocket#send') do +#assert('UDPSocket#recv') do + +#assert('UDPSocket#bind') do +#assert('UDPSocket#recvfrom_nonblock') do + +#assert('TCPSocket.gethostbyname') do +#assert('TCPSocket.new') do +#assert('TCPSocket#close') do +#assert('TCPSocket#write') do -- cgit v1.2.3 From bc5feb39a149d16a1b66d34f849606952a560f1e Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 21 May 2013 13:40:14 +0900 Subject: short description, example, requirement, todo, license. --- README.md | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1e574b4f4..afa689c0d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,52 @@ mruby-socket ============ -socket module for mruby +"mruby-socket" mrbgem provides BSD socket interface for mruby. +API is compatible with CRuby's "socket" library. + + +## Example +```sh +% vi kame.rb +s = TCPSocket.open("www.kame.net", 80) +s.write("GET / HTTP/1.0\r\n\r\n") +puts s.read +s.close + +% mruby kame.rb +HTTP/1.1 200 OK +Date: Tue, 21 May 2013 04:31:30 GMT +... +``` + +## Requirement +- system must have RFC3493 basic socket interface +- and some POSIX API... + +## TODO +- add missing methods +- write more tests +- fix possible descriptor leakage (see XXX comments) + + +## License + +Copyright (c) 2013 Internet Initiative Japan Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. -- cgit v1.2.3 From 89147066f8909f91b738f3dbfb9bc9fc78c66190 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 21 May 2013 13:48:33 +0900 Subject: mruby-socket depends on mruby-io. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index afa689c0d..581628646 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ Date: Tue, 21 May 2013 04:31:30 GMT ``` ## Requirement +- mruby-io (https://github.com/iij/mruby-io) - system must have RFC3493 basic socket interface - and some POSIX API... -- cgit v1.2.3 From cfe18142cbb34fe7080d6a98b02a6e425490e972 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 21 May 2013 13:53:27 +0900 Subject: test runner. --- run_test.rb | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 run_test.rb diff --git a/run_test.rb b/run_test.rb new file mode 100644 index 000000000..bbdfaab90 --- /dev/null +++ b/run_test.rb @@ -0,0 +1,26 @@ +#!/usr/bin/env ruby +# +# mrbgems test runner +# + +if __FILE__ == $0 + repository, dir = 'https://github.com/mruby/mruby.git', 'tmp/mruby' + build_args = ARGV + + Dir.mkdir 'tmp' unless File.exist?('tmp') + unless File.exist?(dir) + system "git clone #{repository} #{dir}" + end + + exit system(%Q[cd #{dir}; MRUBY_CONFIG=#{File.expand_path __FILE__} ruby minirake #{build_args.join(' ')}]) +end + +MRuby::Build.new do |conf| + toolchain :gcc + conf.gembox 'default' + + conf.gem :git => 'https://github.com/iij/mruby-mtest.git' + conf.gem :git => 'https://github.com/iij/mruby-io.git' + + conf.gem File.expand_path(File.dirname(__FILE__)) +end -- cgit v1.2.3 From 4bebd4d70f6ac45819cf8cf6055c62993a4138e3 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 21 May 2013 14:03:10 +0900 Subject: mrb_sys_fail() is declared in src/error.h --- mrbgem.rake | 2 ++ src/socket.c | 1 + 2 files changed, 3 insertions(+) diff --git a/mrbgem.rake b/mrbgem.rake index db6b8b56f..1e31e1d11 100644 --- a/mrbgem.rake +++ b/mrbgem.rake @@ -1,4 +1,6 @@ MRuby::Gem::Specification.new('mruby-socket') do |spec| spec.license = 'MIT' spec.authors = 'Internet Initiative Japan' + + spec.cc.include_paths << "#{build.root}/src" end diff --git a/src/socket.c b/src/socket.c index ec52e302f..ea5fa5543 100644 --- a/src/socket.c +++ b/src/socket.c @@ -22,6 +22,7 @@ #include "mruby/string.h" #include "mruby/variable.h" #include "mruby/ext/io.h" +#include "error.h" #define E_SOCKET_ERROR (mrb_class_get(mrb, "SocketError")) -- cgit v1.2.3 From b8912c35084c515b2cd8b1011d4e754adc808571 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 21 May 2013 14:13:15 +0900 Subject: Linux does not have getpeereid(2). --- src/socket.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/socket.c b/src/socket.c index ea5fa5543..db053cdf2 100644 --- a/src/socket.c +++ b/src/socket.c @@ -193,6 +193,7 @@ socket_family(int s) static mrb_value mrb_basicsocket_getpeereid(mrb_state *mrb, mrb_value self) { +#ifdef HAVE_GETPEEREID mrb_value ary; gid_t egid; uid_t euid; @@ -206,6 +207,10 @@ mrb_basicsocket_getpeereid(mrb_state *mrb, mrb_value self) mrb_ary_push(mrb, ary, mrb_fixnum_value((mrb_int)euid)); mrb_ary_push(mrb, ary, mrb_fixnum_value((mrb_int)egid)); return ary; +#else + mrb_raise(mrb, E_RUNTIME_ERROR, "getpeereid is not avaialble on this system"); + return mrb_nil_value(); +#endif } static mrb_value -- cgit v1.2.3 From 0f2d7e8a999a98fee160f02906d2ba7091c09d1f Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 21 May 2013 14:15:15 +0900 Subject: fix reading wrong variable. --- src/socket.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/socket.c b/src/socket.c index db053cdf2..34c495503 100644 --- a/src/socket.c +++ b/src/socket.c @@ -76,8 +76,8 @@ mrb_addrinfo_getaddrinfo(mrb_state *mrb, mrb_value klass) } lastai = mrb_cv_get(mrb, klass, mrb_intern_cstr(mrb, "_lastai")); - if (mrb_voidp_p(ai)) { - freeaddrinfo(mrb_voidp(ai)); + if (mrb_voidp_p(lastai)) { + freeaddrinfo(mrb_voidp(lastai)); mrb_cv_set(mrb, klass, mrb_intern_cstr(mrb, "_lastai"), mrb_nil_value()); } -- cgit v1.2.3 From 12144b9ad2daf4d81df5ed0e616bfbcd5e400d29 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 21 May 2013 14:23:07 +0900 Subject: getaddrinfo("localhost") may return 2 or more. --- test/socket.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/socket.rb b/test/socket.rb index b7fd458c4..dc2f896b9 100644 --- a/test/socket.rb +++ b/test/socket.rb @@ -6,9 +6,9 @@ assert('super class of Addrinfo') do assert_equal(Object, Addrinfo.superclass) end -assert('Addrinfo.getadrinfo') do +assert('Addrinfo.getaddrinfo') do ary = Addrinfo.getaddrinfo("localhost", "domain", Socket::AF_INET, Socket::SOCK_STREAM) - assert_equal(ary.size, 1) + assert_true(ary.size >= 1) ai = ary[0] assert_equal(ai.afamily, Socket::AF_INET) assert_equal(ai.pfamily, Socket::PF_INET) -- cgit v1.2.3 From 1411d5b97475041f4f1bcf103e8e453fb4ca6761 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 21 May 2013 14:23:35 +0900 Subject: using mruby-mtest on test/socket.rb. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 581628646..a6962ae17 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Date: Tue, 21 May 2013 04:31:30 GMT ## Requirement - mruby-io (https://github.com/iij/mruby-io) +- mruby-mtest (https://github.com/iij/mruby-mtest) - system must have RFC3493 basic socket interface - and some POSIX API... -- cgit v1.2.3 From f4aa3e7ae761cd5595829fb920fa483c2f95abff Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 21 May 2013 14:48:42 +0900 Subject: getaddrinfo("localhost") returns "fe80::1%lo0" on MacOS! --- test/socket.rb | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/test/socket.rb b/test/socket.rb index dc2f896b9..1ccf05364 100644 --- a/test/socket.rb +++ b/test/socket.rb @@ -19,18 +19,9 @@ end assert('Addrinfo.foreach') do # assume Addrinfo.getaddrinfo works well + a = Addrinfo.getaddrinfo("localhost", "domain") b = [] - a = Addrinfo.foreach("localhost", "domain") { |ai| - assert_include([Socket::AF_INET, Socket::AF_INET6], ai.afamily) - if ai.afamily == Socket::AF_INET - assert_equal(ai.ip_address, '127.0.0.1') - else - assert_equal(ai.ip_address, '::1') - end - assert_equal(ai.ip_port, 53) - assert_include([Socket::SOCK_STREAM, Socket::SOCK_DGRAM], ai.socktype) - b << ai - } + Addrinfo.foreach("localhost", "domain") { |ai| b << ai } assert_equal(a.size, b.size) end -- cgit v1.2.3 From 35defaf1c937408f8e5d817f25a24dbc75a64c99 Mon Sep 17 00:00:00 2001 From: Akito Mochizuki Date: Tue, 28 May 2013 10:15:25 +0900 Subject: fix mrb_voidp_value function call --- src/socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/socket.c b/src/socket.c index 34c495503..e8f1f6135 100644 --- a/src/socket.c +++ b/src/socket.c @@ -85,7 +85,7 @@ mrb_addrinfo_getaddrinfo(mrb_state *mrb, mrb_value klass) if (error) { mrb_raisef(mrb, E_SOCKET_ERROR, "getaddrinfo: %S", mrb_str_new_cstr(mrb, gai_strerror(error))); } - mrb_cv_set(mrb, klass, mrb_intern_cstr(mrb, "_lastai"), mrb_voidp_value(res0)); + mrb_cv_set(mrb, klass, mrb_intern_cstr(mrb, "_lastai"), mrb_voidp_value(mrb, res0)); for (res = res0; res != NULL; res = res->ai_next) { sa = mrb_str_new(mrb, (void *)res->ai_addr, res->ai_addrlen); -- cgit v1.2.3 From 216e32751e79781ba3eb6319d7513b80a32c537e Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 21 Jun 2013 09:14:53 +0900 Subject: Socket.gethostname always fails. --- src/socket.c | 9 ++++++--- test/socket.rb | 5 +++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/socket.c b/src/socket.c index e8f1f6135..7966b9c83 100644 --- a/src/socket.c +++ b/src/socket.c @@ -560,14 +560,17 @@ static mrb_value mrb_socket_gethostname(mrb_state *mrb, mrb_value cls) { mrb_value buf; + size_t bufsize; #ifdef HOST_NAME_MAX - buf = mrb_str_buf_new(mrb, HOST_NAME_MAX+1); + bufsize = HOST_NAME_MAX + 1; #else - buf = mrb_str_buf_new(mrb, 256); + bufsize = 256; #endif - if (gethostname(RSTRING_PTR(buf), RSTRING_LEN(buf)) != 0) + buf = mrb_str_buf_new(mrb, bufsize); + if (gethostname(RSTRING_PTR(buf), bufsize) != 0) mrb_sys_fail(mrb, "gethostname"); + mrb_str_resize(mrb, buf, strlen(RSTRING_PTR(buf))); return buf; } diff --git a/test/socket.rb b/test/socket.rb index 1ccf05364..309e7cf11 100644 --- a/test/socket.rb +++ b/test/socket.rb @@ -128,3 +128,8 @@ end #assert('TCPSocket.new') do #assert('TCPSocket#close') do #assert('TCPSocket#write') do + +assert('Socket.gethostname') do + assert_true(Socket.gethostname.is_a? String) +end + -- cgit v1.2.3 From cf827ab0e79827ea077016080cfcb11faaab1294 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Thu, 25 Jul 2013 11:54:53 +0900 Subject: fix Addrinfo.getaddrinfo("127.0.0.1", nil). Closes #2 --- src/socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/socket.c b/src/socket.c index 7966b9c83..1e6d6459a 100644 --- a/src/socket.c +++ b/src/socket.c @@ -58,7 +58,7 @@ mrb_addrinfo_getaddrinfo(mrb_state *mrb, mrb_value klass) servname = mrb_str_to_cstr(mrb, service); } else if (mrb_fixnum_p(service)) { servname = mrb_str_to_cstr(mrb, mrb_funcall(mrb, service, "to_s", 0)); - } else if (mrb_nil_p(nodename)) { + } else if (mrb_nil_p(service)) { servname = NULL; } else { mrb_raise(mrb, E_TYPE_ERROR, "service must be String, Fixnum, or nil"); -- cgit v1.2.3 From a341b8e0ffe6ba5892e00bc3bbcac619763773d0 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Thu, 25 Jul 2013 11:58:05 +0900 Subject: more socket options (for multicast). --- src/const.cstub | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/const.def | 48 ++++++++++++++++++++ 2 files changed, 186 insertions(+) diff --git a/src/const.cstub b/src/const.cstub index 3ddac21dd..6171c67e1 100644 --- a/src/const.cstub +++ b/src/const.cstub @@ -58,6 +58,123 @@ #ifdef AI_PASSIVE define_const(AI_PASSIVE); #endif +#ifdef IP_ADD_MEMBERSHIP + define_const(IP_ADD_MEMBERSHIP); +#endif +#ifdef IP_ADD_SOURCE_MEMBERSHIP + define_const(IP_ADD_SOURCE_MEMBERSHIP); +#endif +#ifdef IP_BLOCK_SOURCE + define_const(IP_BLOCK_SOURCE); +#endif +#ifdef IP_DROP_MEMBERSHIP + define_const(IP_DROP_MEMBERSHIP); +#endif +#ifdef IP_DROP_SOURCE_MEMBERSHIP + define_const(IP_DROP_SOURCE_MEMBERSHIP); +#endif +#ifdef IP_FREEBIND + define_const(IP_FREEBIND); +#endif +#ifdef IP_HDRINCL + define_const(IP_HDRINCL); +#endif +#ifdef IP_IPSEC_POLICY + define_const(IP_IPSEC_POLICY); +#endif +#ifdef IP_MINTTL + define_const(IP_MINTTL); +#endif +#ifdef IP_MSFILTER + define_const(IP_MSFILTER); +#endif +#ifdef IP_MTU + define_const(IP_MTU); +#endif +#ifdef IP_MTU_DISCOVER + define_const(IP_MTU_DISCOVER); +#endif +#ifdef IP_MULTICAST_ALL + define_const(IP_MULTICAST_ALL); +#endif +#ifdef IP_MULTICAST_IF + define_const(IP_MULTICAST_IF); +#endif +#ifdef IP_MULTICAST_LOOP + define_const(IP_MULTICAST_LOOP); +#endif +#ifdef IP_MULTICAST_TTL + define_const(IP_MULTICAST_TTL); +#endif +#ifdef IP_OPTIONS + define_const(IP_OPTIONS); +#endif +#ifdef IP_ORIGDSTADDR + define_const(IP_ORIGDSTADDR); +#endif +#ifdef IP_PASSSEC + define_const(IP_PASSSEC); +#endif +#ifdef IP_PKTINFO + define_const(IP_PKTINFO); +#endif +#ifdef IP_PKTOPTIONS + define_const(IP_PKTOPTIONS); +#endif +#ifdef IP_PMTUDISC_DO + define_const(IP_PMTUDISC_DO); +#endif +#ifdef IP_PMTUDISC_DONT + define_const(IP_PMTUDISC_DONT); +#endif +#ifdef IP_PMTUDISC_PROBE + define_const(IP_PMTUDISC_PROBE); +#endif +#ifdef IP_PMTUDISC_WANT + define_const(IP_PMTUDISC_WANT); +#endif +#ifdef IP_RECVDSTADDR + define_const(IP_RECVDSTADDR); +#endif +#ifdef IP_RECVERR + define_const(IP_RECVERR); +#endif +#ifdef IP_RECVOPTS + define_const(IP_RECVOPTS); +#endif +#ifdef IP_RECVORIGDSTADDR + define_const(IP_RECVORIGDSTADDR); +#endif +#ifdef IP_RECVRETOPTS + define_const(IP_RECVRETOPTS); +#endif +#ifdef IP_RECVTOS + define_const(IP_RECVTOS); +#endif +#ifdef IP_RECVTTL + define_const(IP_RECVTTL); +#endif +#ifdef IP_RETOPTS + define_const(IP_RETOPTS); +#endif +#ifdef IP_ROUTER_ALERT + define_const(IP_ROUTER_ALERT); +#endif +#ifdef IP_TOS + define_const(IP_TOS); +#endif +#ifdef IP_TRANSPARENT + define_const(IP_TRANSPARENT); +#endif +#ifdef IP_TTL + define_const(IP_TTL); +#endif +#ifdef IP_UNBLOCK_SOURCE + define_const(IP_UNBLOCK_SOURCE); +#endif +#ifdef IP_XFRM_POLICY + define_const(IP_XFRM_POLICY); +#endif #ifdef IPPROTO_ICMP define_const(IPPROTO_ICMP); #endif @@ -76,6 +193,27 @@ #ifdef IPPROTO_UDP define_const(IPPROTO_UDP); #endif +#ifdef MCAST_BLOCK_SOURCE + define_const(MCAST_BLOCK_SOURCE); +#endif +#ifdef MCAST_JOIN_GROUP + define_const(MCAST_JOIN_GROUP); +#endif +#ifdef MCAST_JOIN_SOURCE_GROUP + define_const(MCAST_JOIN_SOURCE_GROUP); +#endif +#ifdef MCAST_LEAVE_GROUP + define_const(MCAST_LEAVE_GROUP); +#endif +#ifdef MCAST_LEAVE_SOURCE_GROUP + define_const(MCAST_LEAVE_SOURCE_GROUP); +#endif +#ifdef MCAST_MSFILTER + define_const(MCAST_MSFILTER); +#endif +#ifdef MCAST_UNBLOCK_SOURCE + define_const(MCAST_UNBLOCK_SOURCE); +#endif #ifdef MSG_BCAST define_const(MSG_BCAST); #endif diff --git a/src/const.def b/src/const.def index 7290a17fb..85ad6f26b 100644 --- a/src/const.def +++ b/src/const.def @@ -20,6 +20,46 @@ AI_NUMERICHOST AI_NUMERICSERV AI_PASSIVE +IP_ADD_MEMBERSHIP +IP_ADD_SOURCE_MEMBERSHIP +IP_BLOCK_SOURCE +IP_DROP_MEMBERSHIP +IP_DROP_SOURCE_MEMBERSHIP +IP_FREEBIND +IP_HDRINCL +IP_IPSEC_POLICY +IP_MINTTL +IP_MSFILTER +IP_MTU +IP_MTU_DISCOVER +IP_MULTICAST_ALL +IP_MULTICAST_IF +IP_MULTICAST_LOOP +IP_MULTICAST_TTL +IP_OPTIONS +IP_ORIGDSTADDR +IP_PASSSEC +IP_PKTINFO +IP_PKTOPTIONS +IP_PMTUDISC_DO +IP_PMTUDISC_DONT +IP_PMTUDISC_PROBE +IP_PMTUDISC_WANT +IP_RECVDSTADDR +IP_RECVERR +IP_RECVOPTS +IP_RECVORIGDSTADDR +IP_RECVRETOPTS +IP_RECVTOS +IP_RECVTTL +IP_RETOPTS +IP_ROUTER_ALERT +IP_TOS +IP_TRANSPARENT +IP_TTL +IP_UNBLOCK_SOURCE +IP_XFRM_POLICY + IPPROTO_ICMP IPPROTO_IP IPPROTO_IPV6 @@ -27,6 +67,14 @@ IPPROTO_RAW IPPROTO_TCP IPPROTO_UDP +MCAST_BLOCK_SOURCE +MCAST_JOIN_GROUP +MCAST_JOIN_SOURCE_GROUP +MCAST_LEAVE_GROUP +MCAST_LEAVE_SOURCE_GROUP +MCAST_MSFILTER +MCAST_UNBLOCK_SOURCE + MSG_BCAST MSG_CTRUNC MSG_DONTROUTE -- cgit v1.2.3 From 76e1017f481b6facb38e7db8af8db61c8afaf751 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Thu, 25 Jul 2013 15:04:59 +0900 Subject: hints.ai_socktype must be set if servname is not NULL on NetBSD3. Closes #1 --- mrblib/socket.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mrblib/socket.rb b/mrblib/socket.rb index c7e8a5672..4762c00af 100644 --- a/mrblib/socket.rb +++ b/mrblib/socket.rb @@ -33,11 +33,11 @@ class Addrinfo end def self.tcp(host, port) - Addrinfo.new(Socket.sockaddr_in(port, host), nil, Socket::SOCK_STREAM, Socket::IPPROTO_TCP) + Addrinfo.getaddrinfo(host, port, nil, Socket::SOCK_STREAM, Socket::IPPROTO_TCP)[0] end def self.udp(host, port) - Addrinfo.new(Socket.sockaddr_in(port, host), nil, Socket::SOCK_DGRAM, Socket::IPPROTO_UDP) + Addrinfo.getaddrinfo(host, port, nil, Socket::SOCK_DGRAM, Socket::IPPROTO_UDP)[0] end def self.unix(path, socktype=Socket::SOCK_STREAM) @@ -331,7 +331,7 @@ class Socket end def self.sockaddr_in(port, host) - ai = Addrinfo.getaddrinfo(host, port)[0] + ai = Addrinfo.getaddrinfo(host, port, nil, Socket::SOCK_DGRAM)[0] ai.to_sockaddr end -- cgit v1.2.3 From a9593e1f5774e980fbb24831c9065386a11fbf74 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Wed, 14 Aug 2013 09:34:22 +0900 Subject: v4/v6 fallback for TCP. --- mrblib/socket.rb | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/mrblib/socket.rb b/mrblib/socket.rb index 4762c00af..58d097e5c 100644 --- a/mrblib/socket.rb +++ b/mrblib/socket.rb @@ -70,7 +70,6 @@ class Addrinfo else proto = '???' end - # how can we get the last part? "#" else "#" @@ -228,11 +227,19 @@ class TCPSocket if self.is_a? TCPServer super(host, service) else - ai = Addrinfo.getaddrinfo(host, service)[0] - super(Socket._socket(ai.afamily, Socket::SOCK_STREAM, 0), "r+") - # XXX: bind(2) - Socket._connect(self.fileno, ai.to_sockaddr) - self + s = nil + e = SocketError + Addrinfo.foreach(host, service) { |ai| + begin + s = Socket._socket(ai.afamily, Socket::SOCK_STREAM, 0) + Socket._connect(s, ai.to_sockaddr) + super(s, "r+") + return + rescue => e0 + e = e0 + end + } + raise e end end -- cgit v1.2.3 From 0345215465c031b38a7345eaa80ef4d21cab1885 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Wed, 14 Aug 2013 11:51:53 +0900 Subject: fix a possible address family mismatch. --- mrblib/socket.rb | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/mrblib/socket.rb b/mrblib/socket.rb index 58d097e5c..63bd6b90d 100644 --- a/mrblib/socket.rb +++ b/mrblib/socket.rb @@ -283,16 +283,17 @@ class UDPSocket def initialize(af=Socket::AF_INET) self._bless super(Socket._socket(af, Socket::SOCK_DGRAM, 0), "r+") + @af = af self end def bind(host, port) - Socket._bind(self.fileno, Socket.sockaddr_in(port, host)) + Socket._bind(self.fileno, _sockaddr_in(port, host)) 0 end def connect(host, port) - Socket._connect(self.fileno, Socket.sockaddr_in(port, host)) + Socket._connect(self.fileno, _sockaddr_in(port, host)) 0 end @@ -309,13 +310,18 @@ class UDPSocket def send(mesg, flags, host=nil, port=nil) if port - super(mesg, flags, Socket.sockaddr_in(port, host)) + super(mesg, flags, _sockaddr_in(port, host)) elsif host super(mesg, flags, host) else super(mesg, flags) end end + + def _sockaddr_in(port, host) + ai = Addrinfo.getaddrinfo(host, port, @af, Socket::SOCK_DGRAM)[0] + ai.to_sockaddr + end end class Socket -- cgit v1.2.3 From 40adffc676859b2965f46f96aa7bd0d970e0e3dc Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Wed, 21 Aug 2013 09:29:38 +0900 Subject: ARGS_XXX -> MRB_ARGS_XXX --- src/socket.c | 74 ++++++++++++++++++++++++++++++------------------------------ 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/src/socket.c b/src/socket.c index 1e6d6459a..96de174db 100644 --- a/src/socket.c +++ b/src/socket.c @@ -705,63 +705,63 @@ mrb_mruby_socket_gem_init(mrb_state* mrb) ai = mrb_define_class(mrb, "Addrinfo", mrb->object_class); mrb_mod_cv_set(mrb, ai, mrb_intern_cstr(mrb, "_lastai"), mrb_nil_value()); - mrb_define_class_method(mrb, ai, "getaddrinfo", mrb_addrinfo_getaddrinfo, ARGS_REQ(2)|ARGS_OPT(4)); - mrb_define_method(mrb, ai, "getnameinfo", mrb_addrinfo_getnameinfo, ARGS_OPT(1)); - mrb_define_method(mrb, ai, "unix_path", mrb_addrinfo_unix_path, ARGS_NONE()); + mrb_define_class_method(mrb, ai, "getaddrinfo", mrb_addrinfo_getaddrinfo, MRB_ARGS_REQ(2)|MRB_ARGS_OPT(4)); + mrb_define_method(mrb, ai, "getnameinfo", mrb_addrinfo_getnameinfo, MRB_ARGS_OPT(1)); + mrb_define_method(mrb, ai, "unix_path", mrb_addrinfo_unix_path, MRB_ARGS_NONE()); io = mrb_class_get(mrb, "IO"); bsock = mrb_define_class(mrb, "BasicSocket", io); - mrb_define_method(mrb, bsock, "_recvfrom", mrb_basicsocket_recvfrom, ARGS_REQ(1)|ARGS_OPT(1)); - mrb_define_method(mrb, bsock, "_setnonblock", mrb_basicsocket_setnonblock, ARGS_REQ(1)); - mrb_define_method(mrb, bsock, "getpeereid", mrb_basicsocket_getpeereid, ARGS_NONE()); - mrb_define_method(mrb, bsock, "getpeername", mrb_basicsocket_getpeername, ARGS_NONE()); - mrb_define_method(mrb, bsock, "getsockname", mrb_basicsocket_getsockname, ARGS_NONE()); - mrb_define_method(mrb, bsock, "getsockopt", mrb_basicsocket_getsockopt, ARGS_REQ(2)); - mrb_define_method(mrb, bsock, "recv", mrb_basicsocket_recv, ARGS_REQ(1)|ARGS_OPT(1)); + mrb_define_method(mrb, bsock, "_recvfrom", mrb_basicsocket_recvfrom, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); + mrb_define_method(mrb, bsock, "_setnonblock", mrb_basicsocket_setnonblock, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, bsock, "getpeereid", mrb_basicsocket_getpeereid, MRB_ARGS_NONE()); + mrb_define_method(mrb, bsock, "getpeername", mrb_basicsocket_getpeername, MRB_ARGS_NONE()); + mrb_define_method(mrb, bsock, "getsockname", mrb_basicsocket_getsockname, MRB_ARGS_NONE()); + mrb_define_method(mrb, bsock, "getsockopt", mrb_basicsocket_getsockopt, MRB_ARGS_REQ(2)); + mrb_define_method(mrb, bsock, "recv", mrb_basicsocket_recv, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); // #recvmsg(maxlen, flags=0) - mrb_define_method(mrb, bsock, "send", mrb_basicsocket_send, ARGS_REQ(2)|ARGS_OPT(1)); + mrb_define_method(mrb, bsock, "send", mrb_basicsocket_send, MRB_ARGS_REQ(2)|MRB_ARGS_OPT(1)); // #sendmsg // #sendmsg_nonblock - mrb_define_method(mrb, bsock, "setsockopt", mrb_basicsocket_setsockopt, ARGS_REQ(1)|ARGS_OPT(2)); - mrb_define_method(mrb, bsock, "shutdown", mrb_basicsocket_shutdown, ARGS_OPT(1)); + mrb_define_method(mrb, bsock, "setsockopt", mrb_basicsocket_setsockopt, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(2)); + mrb_define_method(mrb, bsock, "shutdown", mrb_basicsocket_shutdown, MRB_ARGS_OPT(1)); ipsock = mrb_define_class(mrb, "IPSocket", bsock); - mrb_define_class_method(mrb, ipsock, "ntop", mrb_ipsocket_ntop, ARGS_REQ(1)); - mrb_define_class_method(mrb, ipsock, "pton", mrb_ipsocket_pton, ARGS_REQ(2)); - mrb_define_method(mrb, ipsock, "recvfrom", mrb_ipsocket_recvfrom, ARGS_REQ(1)|ARGS_OPT(1)); + mrb_define_class_method(mrb, ipsock, "ntop", mrb_ipsocket_ntop, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, ipsock, "pton", mrb_ipsocket_pton, MRB_ARGS_REQ(2)); + mrb_define_method(mrb, ipsock, "recvfrom", mrb_ipsocket_recvfrom, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); tcpsock = mrb_define_class(mrb, "TCPSocket", ipsock); - //mrb_define_class_method(mrb, tcpsock, "open", mrb_tcpsocket_open, ARGS_REQ(2)|ARGS_OPT(2)); - //mrb_define_class_method(mrb, tcpsock, "new", mrb_tcpsocket_open, ARGS_REQ(2)|ARGS_OPT(2)); + //mrb_define_class_method(mrb, tcpsock, "open", mrb_tcpsocket_open, MRB_ARGS_REQ(2)|MRB_ARGS_OPT(2)); + //mrb_define_class_method(mrb, tcpsock, "new", mrb_tcpsocket_open, MRB_ARGS_REQ(2)|MRB_ARGS_OPT(2)); mrb_define_class(mrb, "TCPServer", tcpsock); udpsock = mrb_define_class(mrb, "UDPSocket", ipsock); //#recvfrom_nonblock sock = mrb_define_class(mrb, "Socket", bsock); - mrb_define_class_method(mrb, sock, "_accept", mrb_socket_accept, ARGS_REQ(1)); - mrb_define_class_method(mrb, sock, "_bind", mrb_socket_bind, ARGS_REQ(3)); - mrb_define_class_method(mrb, sock, "_connect", mrb_socket_connect, ARGS_REQ(3)); - mrb_define_class_method(mrb, sock, "_listen", mrb_socket_listen, ARGS_REQ(2)); - mrb_define_class_method(mrb, sock, "_sockaddr_family", mrb_socket_sockaddr_family, ARGS_REQ(1)); - mrb_define_class_method(mrb, sock, "_socket", mrb_socket_socket, ARGS_REQ(3)); - //mrb_define_class_method(mrb, sock, "gethostbyaddr", mrb_socket_gethostbyaddr, ARGS_REQ(1)|ARGS_OPT(1)); - //mrb_define_class_method(mrb, sock, "gethostbyname", mrb_socket_gethostbyname, ARGS_REQ(1)|ARGS_OPT(1)); - mrb_define_class_method(mrb, sock, "gethostname", mrb_socket_gethostname, ARGS_NONE()); - //mrb_define_class_method(mrb, sock, "getservbyname", mrb_socket_getservbyname, ARGS_REQ(1)|ARGS_OPT(1)); - //mrb_define_class_method(mrb, sock, "getservbyport", mrb_socket_getservbyport, ARGS_REQ(1)|ARGS_OPT(1)); - mrb_define_class_method(mrb, sock, "sockaddr_un", mrb_socket_sockaddr_un, ARGS_REQ(1)); - mrb_define_class_method(mrb, sock, "socketpair", mrb_socket_socketpair, ARGS_REQ(3)); - //mrb_define_method(mrb, sock, "sysaccept", mrb_socket_accept, ARGS_NONE()); + mrb_define_class_method(mrb, sock, "_accept", mrb_socket_accept, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, sock, "_bind", mrb_socket_bind, MRB_ARGS_REQ(3)); + mrb_define_class_method(mrb, sock, "_connect", mrb_socket_connect, MRB_ARGS_REQ(3)); + mrb_define_class_method(mrb, sock, "_listen", mrb_socket_listen, MRB_ARGS_REQ(2)); + mrb_define_class_method(mrb, sock, "_sockaddr_family", mrb_socket_sockaddr_family, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, sock, "_socket", mrb_socket_socket, MRB_ARGS_REQ(3)); + //mrb_define_class_method(mrb, sock, "gethostbyaddr", mrb_socket_gethostbyaddr, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); + //mrb_define_class_method(mrb, sock, "gethostbyname", mrb_socket_gethostbyname, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); + mrb_define_class_method(mrb, sock, "gethostname", mrb_socket_gethostname, MRB_ARGS_NONE()); + //mrb_define_class_method(mrb, sock, "getservbyname", mrb_socket_getservbyname, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); + //mrb_define_class_method(mrb, sock, "getservbyport", mrb_socket_getservbyport, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); + mrb_define_class_method(mrb, sock, "sockaddr_un", mrb_socket_sockaddr_un, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, sock, "socketpair", mrb_socket_socketpair, MRB_ARGS_REQ(3)); + //mrb_define_method(mrb, sock, "sysaccept", mrb_socket_accept, MRB_ARGS_NONE()); usock = mrb_define_class(mrb, "UNIXSocket", io); - //mrb_define_class_method(mrb, usock, "pair", mrb_unixsocket_open, ARGS_OPT(2)); - //mrb_define_class_method(mrb, usock, "socketpair", mrb_unixsocket_open, ARGS_OPT(2)); + //mrb_define_class_method(mrb, usock, "pair", mrb_unixsocket_open, MRB_ARGS_OPT(2)); + //mrb_define_class_method(mrb, usock, "socketpair", mrb_unixsocket_open, MRB_ARGS_OPT(2)); - //mrb_define_method(mrb, usock, "recv_io", mrb_unixsocket_peeraddr, ARGS_NONE()); - //mrb_define_method(mrb, usock, "recvfrom", mrb_unixsocket_peeraddr, ARGS_NONE()); - //mrb_define_method(mrb, usock, "send_io", mrb_unixsocket_peeraddr, ARGS_NONE()); + //mrb_define_method(mrb, usock, "recv_io", mrb_unixsocket_peeraddr, MRB_ARGS_NONE()); + //mrb_define_method(mrb, usock, "recvfrom", mrb_unixsocket_peeraddr, MRB_ARGS_NONE()); + //mrb_define_method(mrb, usock, "send_io", mrb_unixsocket_peeraddr, MRB_ARGS_NONE()); constants = mrb_define_module_under(mrb, sock, "Constants"); -- cgit v1.2.3 From ec443d45db494c2d4f872f2f415cf113f6f6f8d1 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Thu, 10 Oct 2013 10:24:02 +0900 Subject: more IPPROTO_* related to IPv6. --- src/const.cstub | 21 +++++++++++++++++++++ src/const.def | 7 +++++++ 2 files changed, 28 insertions(+) diff --git a/src/const.cstub b/src/const.cstub index 6171c67e1..8d4f98a61 100644 --- a/src/const.cstub +++ b/src/const.cstub @@ -175,18 +175,39 @@ #ifdef IP_XFRM_POLICY define_const(IP_XFRM_POLICY); #endif +#ifdef IPPROTO_AH + define_const(IPPROTO_AH); +#endif +#ifdef IPPROTO_DSTOPTS + define_const(IPPROTO_DSTOPTS); +#endif +#ifdef IPPROTO_ESP + define_const(IPPROTO_ESP); +#endif +#ifdef IPPROTO_FRAGMENT + define_const(IPPROTO_FRAGMENT); +#endif #ifdef IPPROTO_ICMP define_const(IPPROTO_ICMP); #endif +#ifdef IPPROTO_ICMPV6 + define_const(IPPROTO_ICMPV6); +#endif #ifdef IPPROTO_IP define_const(IPPROTO_IP); #endif #ifdef IPPROTO_IPV6 define_const(IPPROTO_IPV6); #endif +#ifdef IPPROTO_NONE + define_const(IPPROTO_NONE); +#endif #ifdef IPPROTO_RAW define_const(IPPROTO_RAW); #endif +#ifdef IPPROTO_ROUTING + define_const(IPPROTO_ROUTING); +#endif #ifdef IPPROTO_TCP define_const(IPPROTO_TCP); #endif diff --git a/src/const.def b/src/const.def index 85ad6f26b..2899c02cb 100644 --- a/src/const.def +++ b/src/const.def @@ -60,10 +60,17 @@ IP_TTL IP_UNBLOCK_SOURCE IP_XFRM_POLICY +IPPROTO_AH +IPPROTO_DSTOPTS +IPPROTO_ESP +IPPROTO_FRAGMENT IPPROTO_ICMP +IPPROTO_ICMPV6 IPPROTO_IP IPPROTO_IPV6 +IPPROTO_NONE IPPROTO_RAW +IPPROTO_ROUTING IPPROTO_TCP IPPROTO_UDP -- cgit v1.2.3 From 823df14ff4f374ed24a8ba89b56e391c3cc6d744 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 15 Oct 2013 10:43:48 +0900 Subject: remove unused code and irrelevant comment. --- src/socket.c | 97 ------------------------------------------------------------ 1 file changed, 97 deletions(-) diff --git a/src/socket.c b/src/socket.c index 96de174db..372e59793 100644 --- a/src/socket.c +++ b/src/socket.c @@ -309,7 +309,6 @@ mrb_basicsocket_send(mrb_state *mrb, mrb_value self) if (mrb_nil_p(dest)) { n = send(socket_fd(mrb, self), RSTRING_PTR(mesg), RSTRING_LEN(mesg), flags); } else { - // XXX: length check n = sendto(socket_fd(mrb, self), RSTRING_PTR(mesg), RSTRING_LEN(mesg), flags, (const void *)RSTRING_PTR(dest), RSTRING_LEN(dest)); } if (n == -1) @@ -460,102 +459,6 @@ mrb_ipsocket_recvfrom(mrb_state *mrb, mrb_value self) return pair; } -static mrb_value -mrb_udpsocket_bind(mrb_state *mrb, mrb_value self) -{ - struct addrinfo hints, *res; - mrb_int n, port; - int error, s; - char *host, hostbuf[256], portbuf[6]; - - s = socket_fd(mrb, self); - mrb_get_args(mrb, "si", &host, &n, &port); - if (n > sizeof(hostbuf) - 1) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "host is too long"); - } - memcpy(hostbuf, host, n); - hostbuf[n] = '\0'; - - memset(&hints, 0, sizeof(hints)); - hints.ai_socktype = SOCK_DGRAM; - hints.ai_flags = AI_NUMERICSERV|AI_PASSIVE; - snprintf(portbuf, sizeof(portbuf), "%d", port); - error = getaddrinfo(hostbuf, portbuf, &hints, &res); - if (error != 0) - mrb_raise(mrb, E_RUNTIME_ERROR, "getaddrinfo(2) failed"); - if (bind(s, res->ai_addr, res->ai_addrlen) == -1) { - freeaddrinfo(res); - mrb_raise(mrb, E_RUNTIME_ERROR, "bind(2) failed"); - } - freeaddrinfo(res); - return mrb_fixnum_value(0); -} - -static mrb_value -mrb_udpsocket_connect(mrb_state *mrb, mrb_value self) -{ - struct addrinfo hints, *res; - mrb_int n, port; - int error, s; - char *host, hostbuf[256], portbuf[6]; - - mrb_get_args(mrb, "si", &host, &n, &port); - s = socket_fd(mrb, self); - - if (n > sizeof(hostbuf) - 1) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "host is too long"); - } - memcpy(hostbuf, host, n); - hostbuf[n] = '\0'; - - memset(&hints, 0, sizeof(hints)); - hints.ai_socktype = SOCK_DGRAM; - hints.ai_flags = AI_NUMERICSERV; - snprintf(portbuf, sizeof(portbuf), "%d", port); - error = getaddrinfo(hostbuf, portbuf, &hints, &res); - if (error != 0) - mrb_raise(mrb, E_RUNTIME_ERROR, "getaddrinfo(2) failed"); - if (connect(s, res->ai_addr, res->ai_addrlen) == -1) { - freeaddrinfo(res); - mrb_raise(mrb, E_RUNTIME_ERROR, "connect(2) failed"); - } - freeaddrinfo(res); - return mrb_fixnum_value(0); -} - -static mrb_value -mrb_udpsocket_send(mrb_state *mrb, mrb_value self) -{ - struct addrinfo hints, *res; - mrb_int n, flags; - mrb_value host, port; - int argc, hlen, s; - char hostbuf[256], *msg, portbuf[6]; - - argc = mrb_get_args(mrb, "si|oo", &msg, &hlen, &flags, &host, &port); - s = socket_fd(mrb, self); - n = -1; - if (argc == 2) { - n = send(s, msg, hlen, flags); - } else if (argc == 4) { - memset(&hints, 0, sizeof(hints)); - hints.ai_socktype = SOCK_DGRAM; - hints.ai_protocol = IPPROTO_UDP; - hints.ai_flags = AI_NUMERICHOST|AI_NUMERICSERV; - memcpy(hostbuf, RSTRING_PTR(host), RSTRING_LEN(host)); - hostbuf[RSTRING_LEN(host)] = '\0'; - snprintf(portbuf, sizeof(portbuf), "%u", mrb_fixnum(port)); - if (getaddrinfo(hostbuf, portbuf, &hints, &res) != 0) - mrb_sys_fail(mrb, "getaddrinfo"); - // XXX: try all addresses? - n = sendto(s, msg, hlen, flags, res->ai_addr, res->ai_addrlen); - freeaddrinfo(res); - } - if (n == -1) - mrb_sys_fail(mrb, "send"); - return mrb_fixnum_value(n); -} - static mrb_value mrb_socket_gethostname(mrb_state *mrb, mrb_value cls) { -- cgit v1.2.3 From 78ebe1b4277dd03c9a0d3a97602cfaa10f320b24 Mon Sep 17 00:00:00 2001 From: murase_syuka Date: Sat, 2 Nov 2013 14:30:42 +0900 Subject: add mruby-socket dependency gems --- mrbgem.rake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mrbgem.rake b/mrbgem.rake index 1e31e1d11..8b4014b8b 100644 --- a/mrbgem.rake +++ b/mrbgem.rake @@ -3,4 +3,7 @@ MRuby::Gem::Specification.new('mruby-socket') do |spec| spec.authors = 'Internet Initiative Japan' spec.cc.include_paths << "#{build.root}/src" + + spec.add_dependency('mruby-io') + spec.add_dependency('mruby-mtest') end -- cgit v1.2.3 From d12f436bdb471559f731f5413fcd6c5d4fedc7b7 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 3 Dec 2013 10:07:29 +0900 Subject: mrb_intern API change. --- src/socket.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/socket.c b/src/socket.c index 372e59793..bddb8f163 100644 --- a/src/socket.c +++ b/src/socket.c @@ -75,17 +75,17 @@ mrb_addrinfo_getaddrinfo(mrb_state *mrb, mrb_value klass) hints.ai_socktype = mrb_fixnum(socktype); } - lastai = mrb_cv_get(mrb, klass, mrb_intern_cstr(mrb, "_lastai")); + lastai = mrb_cv_get(mrb, klass, mrb_intern_lit(mrb, "_lastai")); if (mrb_voidp_p(lastai)) { freeaddrinfo(mrb_voidp(lastai)); - mrb_cv_set(mrb, klass, mrb_intern_cstr(mrb, "_lastai"), mrb_nil_value()); + mrb_cv_set(mrb, klass, mrb_intern_lit(mrb, "_lastai"), mrb_nil_value()); } error = getaddrinfo(hostname, servname, &hints, &res0); if (error) { mrb_raisef(mrb, E_SOCKET_ERROR, "getaddrinfo: %S", mrb_str_new_cstr(mrb, gai_strerror(error))); } - mrb_cv_set(mrb, klass, mrb_intern_cstr(mrb, "_lastai"), mrb_voidp_value(mrb, res0)); + mrb_cv_set(mrb, klass, mrb_intern_lit(mrb, "_lastai"), mrb_voidp_value(mrb, res0)); for (res = res0; res != NULL; res = res->ai_next) { sa = mrb_str_new(mrb, (void *)res->ai_addr, res->ai_addrlen); @@ -95,7 +95,7 @@ mrb_addrinfo_getaddrinfo(mrb_state *mrb, mrb_value klass) } freeaddrinfo(res0); - mrb_cv_set(mrb, klass, mrb_intern_cstr(mrb, "_lastai"), mrb_nil_value()); + mrb_cv_set(mrb, klass, mrb_intern_lit(mrb, "_lastai"), mrb_nil_value()); return ary; } @@ -112,7 +112,7 @@ mrb_addrinfo_getnameinfo(mrb_state *mrb, mrb_value self) host = mrb_str_buf_new(mrb, NI_MAXHOST); serv = mrb_str_buf_new(mrb, NI_MAXSERV); - sastr = mrb_iv_get(mrb, self, mrb_intern(mrb, "@sockaddr")); + sastr = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@sockaddr")); if (!mrb_string_p(sastr)) { mrb_raise(mrb, E_SOCKET_ERROR, "invalid sockaddr"); } @@ -133,7 +133,7 @@ mrb_addrinfo_unix_path(mrb_state *mrb, mrb_value self) { mrb_value sastr; - sastr = mrb_iv_get(mrb, self, mrb_intern(mrb, "@sockaddr")); + sastr = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@sockaddr")); if (((struct sockaddr *)RSTRING_PTR(sastr))->sa_family != AF_UNIX) mrb_raise(mrb, E_SOCKET_ERROR, "need AF_UNIX address"); return mrb_str_new_cstr(mrb, ((struct sockaddr_un *)RSTRING_PTR(sastr))->sun_path); @@ -252,7 +252,7 @@ mrb_basicsocket_getsockopt(mrb_state *mrb, mrb_value self) optlen = sizeof(opt); if (getsockopt(s, level, optname, &opt, &optlen) == -1) mrb_sys_fail(mrb, "getsockopt"); - c = mrb_const_get(mrb, mrb_obj_value(mrb_class_get(mrb, "Socket")), mrb_intern(mrb, "Option")); + c = mrb_const_get(mrb, mrb_obj_value(mrb_class_get(mrb, "Socket")), mrb_intern_lit(mrb, "Option")); family = socket_family(s); data = mrb_str_new(mrb, (char *)&opt, sizeof(int)); return mrb_funcall(mrb, c, "new", 4, mrb_fixnum_value(family), mrb_fixnum_value(level), mrb_fixnum_value(optname), data); @@ -607,7 +607,7 @@ mrb_mruby_socket_gem_init(mrb_state* mrb) struct RClass *constants; ai = mrb_define_class(mrb, "Addrinfo", mrb->object_class); - mrb_mod_cv_set(mrb, ai, mrb_intern_cstr(mrb, "_lastai"), mrb_nil_value()); + mrb_mod_cv_set(mrb, ai, mrb_intern_lit(mrb, "_lastai"), mrb_nil_value()); mrb_define_class_method(mrb, ai, "getaddrinfo", mrb_addrinfo_getaddrinfo, MRB_ARGS_REQ(2)|MRB_ARGS_OPT(4)); mrb_define_method(mrb, ai, "getnameinfo", mrb_addrinfo_getnameinfo, MRB_ARGS_OPT(1)); mrb_define_method(mrb, ai, "unix_path", mrb_addrinfo_unix_path, MRB_ARGS_NONE()); @@ -680,7 +680,7 @@ void mrb_mruby_socket_gem_final(mrb_state* mrb) { mrb_value ai; - ai = mrb_mod_cv_get(mrb, mrb_class_get(mrb, "Addrinfo"), mrb_intern_cstr(mrb, "_lastai")); + ai = mrb_mod_cv_get(mrb, mrb_class_get(mrb, "Addrinfo"), mrb_intern_lit(mrb, "_lastai")); if (mrb_voidp_p(ai)) { freeaddrinfo(mrb_voidp(ai)); } -- cgit v1.2.3 From a26ce35c64f7bc6568ceae514a104ac238a6229f Mon Sep 17 00:00:00 2001 From: Julien Ammous Date: Wed, 4 Dec 2013 20:51:27 +0100 Subject: removed mtest dependency --- mrbgem.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgem.rake b/mrbgem.rake index 8b4014b8b..6bb141061 100644 --- a/mrbgem.rake +++ b/mrbgem.rake @@ -5,5 +5,5 @@ MRuby::Gem::Specification.new('mruby-socket') do |spec| spec.cc.include_paths << "#{build.root}/src" spec.add_dependency('mruby-io') - spec.add_dependency('mruby-mtest') + # spec.add_dependency('mruby-mtest') end -- cgit v1.2.3 From b3c6075dc5e916c71f4c63512544729bb1742008 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Mon, 10 Feb 2014 09:51:24 +0900 Subject: IO._bless has gone. https://github.com/iij/mruby-io/commit/b74458a486042f4863fa6362057e25f0997694f5 --- mrblib/socket.rb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/mrblib/socket.rb b/mrblib/socket.rb index 63bd6b90d..b04375f60 100644 --- a/mrblib/socket.rb +++ b/mrblib/socket.rb @@ -223,7 +223,6 @@ end class TCPSocket def initialize(host, service, local_host=nil, local_service=nil) - self._bless if self.is_a? TCPServer super(host, service) else @@ -248,7 +247,6 @@ end class TCPServer def initialize(host=nil, service) - self._bless ai = Addrinfo.getaddrinfo(host, service, nil, nil, nil, Socket::AI_PASSIVE)[0] super(Socket._socket(ai.afamily, Socket::SOCK_STREAM, 0), "r+") Socket._bind(self.fileno, ai.to_sockaddr) @@ -281,7 +279,6 @@ end class UDPSocket def initialize(af=Socket::AF_INET) - self._bless super(Socket._socket(af, Socket::SOCK_DGRAM, 0), "r+") @af = af self @@ -326,7 +323,6 @@ end class Socket def initialize(domain, type, protocol=0) - self._bless super(Socket._socket(domain, type, protocol), "r+") end @@ -436,7 +432,6 @@ end class UNIXSocket def initialize(path, &block) - self._bless super(Socket._socket(AF_UNIX, SOCK_STREAM, 0), "r+") Socket._connect(self.fileno, Socket.sockaddr_un(path)) if block @@ -479,7 +474,6 @@ end class UNIXServer def initialize(path, &block) - self._bless super(Socket._socket(Socket::AF_UNIX, Socket::SOCK_STREAM, 0), "r") Socket._bind(self.fileno, Socket.pack_sockaddr_un(path)) listen(5) -- cgit v1.2.3 From a90d8b8a7399b7cf6f22009cd90248705deb027e Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Mon, 24 Feb 2014 11:21:49 +0900 Subject: add Socket.getaddrinfo. --- mrblib/socket.rb | 50 +++++++++++++++++++++++++++++--------------------- test/ipsocket.rb | 40 ++++++++++++++++++++++++++++++++++++++++ test/socket.rb | 13 +++++++++++++ 3 files changed, 82 insertions(+), 21 deletions(-) create mode 100644 test/ipsocket.rb diff --git a/mrblib/socket.rb b/mrblib/socket.rb index b04375f60..d103dbf1d 100644 --- a/mrblib/socket.rb +++ b/mrblib/socket.rb @@ -139,6 +139,21 @@ class Addrinfo attr_reader :protocol attr_reader :socktype + def _to_array + case @family + when Socket::AF_INET + s = "AF_INET" + when Socket::AF_INET6 + s = "AF_INET6" + when Socket::AF_UNIX + s = "AF_UNIX" + else + s = "(unknown AF)" + end + addr, port = self.getnameinfo(Socket::NI_NUMERICHOST|Socket::NI_NUMERICSERV) + [ s, port.to_i, addr, addr ] + end + def to_sockaddr @sockaddr end @@ -189,35 +204,21 @@ class BasicSocket end class IPSocket - def self.getddress(host) + def self.getaddress(host) Addrinfo.ip(host).ip_address end - def _ai_to_array(ai) - case ai.afamily - when Socket::AF_INET - s = "AF_INET" - when Socket::AF_INET6 - s = "AF_INET6" - when Socket::AF_UNIX - s = "AF_UNIX" - else - s = "(unknown AF)" - end - [ s, ai.ip_port, ai.ip_address, ai.ip_address ] - end - def addr - _ai_to_array(Addrinfo.new(self.getsockname)) + Addrinfo.new(self.getsockname)._to_array end def peeraddr - _ai_to_array(Addrinfo.new(self.getpeername)) + Addrinfo.new(self.getpeername)._to_array end def recvfrom(maxlen, flags=0) msg, sa = _recvfrom(maxlen, flags) - [ msg, _ai_to_array(Addrinfo.new(sa)) ] + [ msg, Addrinfo.new(sa)._to_array ] end end @@ -328,9 +329,16 @@ class Socket #def self.accept_loop - # def self.getaddrinfo - # by Addrinfo.getaddrinfo - #end + def self.getaddrinfo(nodename, servname, family=nil, socktype=nil, protocol=nil, flags=0) + Addrinfo.getaddrinfo(nodename, servname, family, socktype, protocol, flags).map { |ai| + ary = ai._to_array + ary[2] = nodename + ary[4] = ai.afamily + ary[5] = ai.socktype + ary[6] = ai.protocol + ary + } + end #def self.getnameinfo #def self.ip_address_list diff --git a/test/ipsocket.rb b/test/ipsocket.rb new file mode 100644 index 000000000..2b9f7e1d7 --- /dev/null +++ b/test/ipsocket.rb @@ -0,0 +1,40 @@ +# Note: most of tests below will fail if UDPSocket is broken. + +assert('IPSocket.getaddress') do + l = IPSocket.getaddress("localhost") + assert_true (l == "127.0.0.1" or l == "::1") +end + +assert('IPSocket.addr') do + localhost = "127.0.0.1" + s = UDPSocket.new + s.bind(localhost, 0) + port = Addrinfo.new(s.getsockname).ip_port + + a = s.addr + assert_equal "AF_INET", a[0] + assert_equal port, a[1] + assert_equal localhost, a[2] + assert_equal localhost, a[3] + s.close + true +end + +assert('IPSocket.peeraddr') do + localhost = "127.0.0.1" + server = UDPSocket.new + server.bind(localhost, 0) + port = server.local_address.ip_port + + client = UDPSocket.new + client.connect(localhost, port) + + a = client.peeraddr + assert_equal "AF_INET", a[0] + assert_equal port, a[1] + assert_equal localhost, a[2] + assert_equal localhost, a[3] + client.close + server.close + true +end diff --git a/test/socket.rb b/test/socket.rb index 309e7cf11..cd50cbaff 100644 --- a/test/socket.rb +++ b/test/socket.rb @@ -133,3 +133,16 @@ assert('Socket.gethostname') do assert_true(Socket.gethostname.is_a? String) end +assert('Socket::getaddrinfo') do + ret = Socket.getaddrinfo("localhost", "domain", Socket::AF_INET, Socket::SOCK_DGRAM) + assert_true ret.size >= 1 + a = ret[0] + assert_equal "AF_INET", a[0] + assert_equal 53, a[1] + # documents says it's a hostname but CRuby returns an address + #assert_equal "127.0.0.1", a[2] + assert_equal "127.0.0.1", a[3] + assert_equal Socket::AF_INET, a[4] + assert_equal Socket::SOCK_DGRAM, a[5] + assert_equal Socket::IPPROTO_UDP, a[6] +end -- cgit v1.2.3 From 11b47459e76ffe6e6d4fe21db045b43d95704b56 Mon Sep 17 00:00:00 2001 From: Masaki Muranaka Date: Tue, 11 Mar 2014 21:18:05 +0900 Subject: Call Socket._connect() in Socket.connect() . --- mrblib/socket.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrblib/socket.rb b/mrblib/socket.rb index d103dbf1d..b8c8b4c18 100644 --- a/mrblib/socket.rb +++ b/mrblib/socket.rb @@ -399,7 +399,7 @@ class Socket def connect(sockaddr) sockaddr = sockaddr.to_sockaddr if sockaddr.is_a? Addrinfo - Socket._bind(self.fileno, sockaddr) + Socket._connect(self.fileno, sockaddr) 0 end -- cgit v1.2.3 From a8558512ec87aa9f1cf0d6d9e99794f7028939d0 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Wed, 12 Mar 2014 09:41:23 +0900 Subject: mruby-mtest is not required to build (but to test). --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a6962ae17..2dac85aa6 100644 --- a/README.md +++ b/README.md @@ -20,8 +20,8 @@ Date: Tue, 21 May 2013 04:31:30 GMT ``` ## Requirement -- mruby-io (https://github.com/iij/mruby-io) -- mruby-mtest (https://github.com/iij/mruby-mtest) +- [iij/mruby-io](https://github.com/iij/mruby-io) mrbgem +- [iij/mruby-mtest](https://github.com/iij/mruby-mtest) mrgbem to run tests - system must have RFC3493 basic socket interface - and some POSIX API... -- cgit v1.2.3 From 279587c138225a979051ab706764bba527471861 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Wed, 12 Mar 2014 09:44:34 +0900 Subject: split. --- test/addrinfo.rb | 89 +++++++++++++++++++++++++++++++++++ test/basicsocket.rb | 17 +++++++ test/socket.rb | 131 ---------------------------------------------------- test/tcpsocket.rb | 4 ++ test/udpsocket.rb | 16 +++++++ 5 files changed, 126 insertions(+), 131 deletions(-) create mode 100644 test/addrinfo.rb create mode 100644 test/basicsocket.rb create mode 100644 test/tcpsocket.rb create mode 100644 test/udpsocket.rb diff --git a/test/addrinfo.rb b/test/addrinfo.rb new file mode 100644 index 000000000..8720eb0ae --- /dev/null +++ b/test/addrinfo.rb @@ -0,0 +1,89 @@ +assert('Addrinfo') do + assert_equal(Class, Addrinfo.class) +end + +assert('super class of Addrinfo') do + assert_equal(Object, Addrinfo.superclass) +end + +assert('Addrinfo.getaddrinfo') do + ary = Addrinfo.getaddrinfo("localhost", "domain", Socket::AF_INET, Socket::SOCK_STREAM) + assert_true(ary.size >= 1) + ai = ary[0] + assert_equal(ai.afamily, Socket::AF_INET) + assert_equal(ai.pfamily, Socket::PF_INET) + assert_equal(ai.socktype, Socket::SOCK_STREAM) + assert_equal(ai.ip_address, '127.0.0.1') + assert_equal(ai.ip_port, 53) +end + +assert('Addrinfo.foreach') do + # assume Addrinfo.getaddrinfo works well + a = Addrinfo.getaddrinfo("localhost", "domain") + b = [] + Addrinfo.foreach("localhost", "domain") { |ai| b << ai } + assert_equal(a.size, b.size) +end + +assert('Addrinfo.ip') do + ai = Addrinfo.ip('127.0.0.1') + assert_equal('127.0.0.1', ai.ip_address) + assert_equal(Socket::AF_INET, ai.afamily) + assert_equal(0, ai.ip_port) + assert_equal(0, ai.socktype) + assert_equal(0, ai.protocol) +end + +assert('Addrinfo.tcp') do + ai = Addrinfo.tcp('127.0.0.1', 'smtp') + assert_equal('127.0.0.1', ai.ip_address) + assert_equal(Socket::AF_INET, ai.afamily) + assert_equal(25, ai.ip_port) + assert_equal(Socket::SOCK_STREAM, ai.socktype) + assert_equal(Socket::IPPROTO_TCP, ai.protocol) +end + +assert('Addrinfo.udp') do + ai = Addrinfo.udp('127.0.0.1', 'domain') + assert_equal('127.0.0.1', ai.ip_address) + assert_equal(Socket::AF_INET, ai.afamily) + assert_equal(53, ai.ip_port) + assert_equal(Socket::SOCK_DGRAM, ai.socktype) + assert_equal(Socket::IPPROTO_UDP, ai.protocol) +end + +assert('Addrinfo.unix') do + a1 = Addrinfo.unix('/tmp/sock') + assert_true(a1.unix?) + assert_equal('/tmp/sock', a1.unix_path) + assert_equal(Socket::SOCK_STREAM, a1.socktype) + a2 = Addrinfo.unix('/tmp/sock', Socket::SOCK_DGRAM) + assert_equal(Socket::SOCK_DGRAM, a2.socktype) +end + +assert('Addrinfo#afamily') do + ai4 = Addrinfo.new(Socket.sockaddr_in(1, '127.0.0.1')) + ai6 = Addrinfo.new(Socket.sockaddr_in(1, '::1')) + aiu = Addrinfo.new(Socket.sockaddr_un('/tmp/sock')) + assert_equal(Socket::AF_INET, ai4.afamily) + assert_equal(Socket::AF_INET6, ai6.afamily) + assert_equal(Socket::AF_UNIX, aiu.afamily) +end + +# assert('Addrinfo#canonname') do + +# #getnameinfo +# assert('Addrinfo#inspect') do +# assert('Addrinfo#inspect_socket') do +# assert('Addrinfo#ip?') do +# assert('Addrinfo#ip_address') do +# assert('Addrinfo#ip_port') do +# assert('Addrinfo#ip_unpack') do +# assert('Addrinfo#ipv4?') do +# assert('Addrinfo#ipv6?') do +# assert('Addrinfo#pfamily') do +# assert('Addrinfo#protocol') do +# assert('Addrinfo#socktype') do +# assert('Addrinfo#to_sockaddr') do +# assert('Addrinfo#unix?') do +# #unix_path diff --git a/test/basicsocket.rb b/test/basicsocket.rb new file mode 100644 index 000000000..8fbfbdd5d --- /dev/null +++ b/test/basicsocket.rb @@ -0,0 +1,17 @@ +assert('BasicSocket') do + assert_equal(Class, BasicSocket.class) +end + +assert('super class of BasicSocket') do + assert_equal(IO, BasicSocket.superclass) +end + +assert('BasicSocket.do_not_reverse_lookup') do + assert_equal(BasicSocket.do_not_reverse_lookup, true) +end + +assert('BasicSocket.do_not_reverse_lookup=') do + BasicSocket.do_not_reverse_lookup = false + assert_equal(BasicSocket.do_not_reverse_lookup, false) + BasicSocket.do_not_reverse_lookup = true +end diff --git a/test/socket.rb b/test/socket.rb index cd50cbaff..b602cc15d 100644 --- a/test/socket.rb +++ b/test/socket.rb @@ -1,134 +1,3 @@ -assert('Addrinfo') do - assert_equal(Class, Addrinfo.class) -end - -assert('super class of Addrinfo') do - assert_equal(Object, Addrinfo.superclass) -end - -assert('Addrinfo.getaddrinfo') do - ary = Addrinfo.getaddrinfo("localhost", "domain", Socket::AF_INET, Socket::SOCK_STREAM) - assert_true(ary.size >= 1) - ai = ary[0] - assert_equal(ai.afamily, Socket::AF_INET) - assert_equal(ai.pfamily, Socket::PF_INET) - assert_equal(ai.socktype, Socket::SOCK_STREAM) - assert_equal(ai.ip_address, '127.0.0.1') - assert_equal(ai.ip_port, 53) -end - -assert('Addrinfo.foreach') do - # assume Addrinfo.getaddrinfo works well - a = Addrinfo.getaddrinfo("localhost", "domain") - b = [] - Addrinfo.foreach("localhost", "domain") { |ai| b << ai } - assert_equal(a.size, b.size) -end - -assert('Addrinfo.ip') do - ai = Addrinfo.ip('127.0.0.1') - assert_equal('127.0.0.1', ai.ip_address) - assert_equal(Socket::AF_INET, ai.afamily) - assert_equal(0, ai.ip_port) - assert_equal(0, ai.socktype) - assert_equal(0, ai.protocol) -end - -assert('Addrinfo.tcp') do - ai = Addrinfo.tcp('127.0.0.1', 'smtp') - assert_equal('127.0.0.1', ai.ip_address) - assert_equal(Socket::AF_INET, ai.afamily) - assert_equal(25, ai.ip_port) - assert_equal(Socket::SOCK_STREAM, ai.socktype) - assert_equal(Socket::IPPROTO_TCP, ai.protocol) -end - -assert('Addrinfo.udp') do - ai = Addrinfo.udp('127.0.0.1', 'domain') - assert_equal('127.0.0.1', ai.ip_address) - assert_equal(Socket::AF_INET, ai.afamily) - assert_equal(53, ai.ip_port) - assert_equal(Socket::SOCK_DGRAM, ai.socktype) - assert_equal(Socket::IPPROTO_UDP, ai.protocol) -end - -assert('Addrinfo.unix') do - a1 = Addrinfo.unix('/tmp/sock') - assert_true(a1.unix?) - assert_equal('/tmp/sock', a1.unix_path) - assert_equal(Socket::SOCK_STREAM, a1.socktype) - a2 = Addrinfo.unix('/tmp/sock', Socket::SOCK_DGRAM) - assert_equal(Socket::SOCK_DGRAM, a2.socktype) -end - -assert('Addrinfo#afamily') do - ai4 = Addrinfo.new(Socket.sockaddr_in(1, '127.0.0.1')) - ai6 = Addrinfo.new(Socket.sockaddr_in(1, '::1')) - aiu = Addrinfo.new(Socket.sockaddr_un('/tmp/sock')) - assert_equal(Socket::AF_INET, ai4.afamily) - assert_equal(Socket::AF_INET6, ai6.afamily) - assert_equal(Socket::AF_UNIX, aiu.afamily) -end - -# assert('Addrinfo#canonname') do - -# #getnameinfo -# assert('Addrinfo#inspect') do -# assert('Addrinfo#inspect_socket') do -# assert('Addrinfo#ip?') do -# assert('Addrinfo#ip_address') do -# assert('Addrinfo#ip_port') do -# assert('Addrinfo#ip_unpack') do -# assert('Addrinfo#ipv4?') do -# assert('Addrinfo#ipv6?') do -# assert('Addrinfo#pfamily') do -# assert('Addrinfo#protocol') do -# assert('Addrinfo#socktype') do -# assert('Addrinfo#to_sockaddr') do -# assert('Addrinfo#unix?') do -# #unix_path - - -assert('BasicSocket') do - assert_equal(Class, BasicSocket.class) -end - -assert('super class of BasicSocket') do - assert_equal(IO, BasicSocket.superclass) -end - -assert('BasicSocket.do_not_reverse_lookup') do - assert_equal(BasicSocket.do_not_reverse_lookup, true) -end - -assert('BasicSocket.do_not_reverse_lookup=') do - BasicSocket.do_not_reverse_lookup = false - assert_equal(BasicSocket.do_not_reverse_lookup, false) - BasicSocket.do_not_reverse_lookup = true -end - -assert('UDPSocket.new') do - s = UDPSocket.new - assert_true(s.is_a? UDPSocket) - s.close - s = UDPSocket.new(Socket::AF_INET6) - assert_true(s.is_a? UDPSocket) - s.close - true -end - -#assert('UDPSocket#connect') do -#assert('UDPSocket#send') do -#assert('UDPSocket#recv') do - -#assert('UDPSocket#bind') do -#assert('UDPSocket#recvfrom_nonblock') do - -#assert('TCPSocket.gethostbyname') do -#assert('TCPSocket.new') do -#assert('TCPSocket#close') do -#assert('TCPSocket#write') do - assert('Socket.gethostname') do assert_true(Socket.gethostname.is_a? String) end diff --git a/test/tcpsocket.rb b/test/tcpsocket.rb new file mode 100644 index 000000000..7056ec164 --- /dev/null +++ b/test/tcpsocket.rb @@ -0,0 +1,4 @@ +#assert('TCPSocket.gethostbyname') do +#assert('TCPSocket.new') do +#assert('TCPSocket#close') do +#assert('TCPSocket#write') do diff --git a/test/udpsocket.rb b/test/udpsocket.rb new file mode 100644 index 000000000..bb57ed011 --- /dev/null +++ b/test/udpsocket.rb @@ -0,0 +1,16 @@ +assert('UDPSocket.new') do + s = UDPSocket.new + assert_true(s.is_a? UDPSocket) + s.close + s = UDPSocket.new(Socket::AF_INET6) + assert_true(s.is_a? UDPSocket) + s.close + true +end + +#assert('UDPSocket#connect') do +#assert('UDPSocket#send') do +#assert('UDPSocket#recv') do + +#assert('UDPSocket#bind') do +#assert('UDPSocket#recvfrom_nonblock') do -- cgit v1.2.3 From 355723ebcac7bd3cfef53f122f5a139d25954c33 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Fri, 4 Apr 2014 11:27:56 +0900 Subject: Create .travis.yml --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..09fa3368f --- /dev/null +++ b/.travis.yml @@ -0,0 +1,2 @@ +script: + - "ruby run_test.rb" -- cgit v1.2.3 From 572b404935e434a93d6ce5f8e7c49624119265dd Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Fri, 4 Apr 2014 11:32:42 +0900 Subject: Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 09fa3368f..ffe227284 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,2 +1,2 @@ script: - - "ruby run_test.rb" + - "ruby run_test.rb all test" -- cgit v1.2.3 From 9850e6a9d0a827b35fb0e5fb03c708a98c8b7df3 Mon Sep 17 00:00:00 2001 From: Julien Ammous Date: Thu, 10 Apr 2014 19:32:05 +0200 Subject: OpenSolaris/Illumos defines a "sun" constant... --- src/socket.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/socket.c b/src/socket.c index bddb8f163..aded78117 100644 --- a/src/socket.c +++ b/src/socket.c @@ -31,7 +31,7 @@ static mrb_value mrb_addrinfo_getaddrinfo(mrb_state *mrb, mrb_value klass) { struct addrinfo hints, *res0, *res; - struct sockaddr_un sun; + struct sockaddr_un sock_un; mrb_value ai, ary, family, lastai, nodename, protocol, s, sa, service, socktype; mrb_int flags; int arena_idx, error; @@ -40,7 +40,7 @@ mrb_addrinfo_getaddrinfo(mrb_state *mrb, mrb_value klass) ary = mrb_ary_new(mrb); arena_idx = mrb_gc_arena_save(mrb); /* ary must be on arena! */ - s = mrb_str_new(mrb, (void *)&sun, sizeof(sun)); + s = mrb_str_new(mrb, (void *)&sock_un, sizeof(sock_un)); family = socktype = protocol = mrb_nil_value(); flags = 0; -- cgit v1.2.3 From cb84ce30e7a8fabf930b8fc2bcf910da1cdcbd00 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 10 Jun 2014 09:54:23 +0900 Subject: no longer used. --- src/socket.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/socket.c b/src/socket.c index aded78117..2cf7ac385 100644 --- a/src/socket.c +++ b/src/socket.c @@ -21,7 +21,6 @@ #include "mruby/data.h" #include "mruby/string.h" #include "mruby/variable.h" -#include "mruby/ext/io.h" #include "error.h" #define E_SOCKET_ERROR (mrb_class_get(mrb, "SocketError")) -- cgit v1.2.3 From 376af5bac31f1b38554a72d879972d45dfe7cdb7 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 17 Jun 2014 15:41:42 +0900 Subject: re-implement TCPServer.accept. fixes #12. --- mrblib/socket.rb | 18 ++++++++++++++++-- src/socket.c | 14 ++++++++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/mrblib/socket.rb b/mrblib/socket.rb index b8c8b4c18..732a6db8e 100644 --- a/mrblib/socket.rb +++ b/mrblib/socket.rb @@ -224,7 +224,7 @@ end class TCPSocket def initialize(host, service, local_host=nil, local_service=nil) - if self.is_a? TCPServer + if @init_with_fd super(host, service) else s = nil @@ -243,12 +243,20 @@ class TCPSocket end end + def self.new_with_prelude pre, *args + o = self._allocate + o.instance_eval(&pre) + o.initialize(*args) + o + end + #def self.gethostbyname(host) end class TCPServer def initialize(host=nil, service) ai = Addrinfo.getaddrinfo(host, service, nil, nil, nil, Socket::AI_PASSIVE)[0] + @init_with_fd = true super(Socket._socket(ai.afamily, Socket::SOCK_STREAM, 0), "r+") Socket._bind(self.fileno, ai.to_sockaddr) listen(5) @@ -256,7 +264,13 @@ class TCPServer end def accept - TCPSocket.for_fd(self.sysaccept) + fd = self.sysaccept + begin + TCPSocket.new_with_prelude(proc { @init_with_fd = true }, fd, "r+") + rescue + IO._sysclose(fd) rescue nil + raise + end end def accept_nonblock diff --git a/src/socket.c b/src/socket.c index 2cf7ac385..ded5dfa25 100644 --- a/src/socket.c +++ b/src/socket.c @@ -599,6 +599,17 @@ mrb_socket_socket(mrb_state *mrb, mrb_value klass) return mrb_fixnum_value(s); } +static mrb_value +mrb_tcpsocket_allocate(mrb_state *mrb, mrb_value klass) +{ + struct RClass *c = mrb_class_ptr(klass); + enum mrb_vtype ttype = MRB_INSTANCE_TT(c); + + /* copied from mrb_instance_alloc() */ + if (ttype == 0) ttype = MRB_TT_OBJECT; + return mrb_obj_value((struct RObject*)mrb_obj_alloc(mrb, ttype, c)); +} + void mrb_mruby_socket_gem_init(mrb_state* mrb) { @@ -634,8 +645,7 @@ mrb_mruby_socket_gem_init(mrb_state* mrb) mrb_define_method(mrb, ipsock, "recvfrom", mrb_ipsocket_recvfrom, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); tcpsock = mrb_define_class(mrb, "TCPSocket", ipsock); - //mrb_define_class_method(mrb, tcpsock, "open", mrb_tcpsocket_open, MRB_ARGS_REQ(2)|MRB_ARGS_OPT(2)); - //mrb_define_class_method(mrb, tcpsock, "new", mrb_tcpsocket_open, MRB_ARGS_REQ(2)|MRB_ARGS_OPT(2)); + mrb_define_class_method(mrb, tcpsock, "_allocate", mrb_tcpsocket_allocate, MRB_ARGS_NONE()); mrb_define_class(mrb, "TCPServer", tcpsock); udpsock = mrb_define_class(mrb, "UDPSocket", ipsock); -- cgit v1.2.3 From f3c71cf5da380839a15409684dbbb02122f63177 Mon Sep 17 00:00:00 2001 From: dreamedge Date: Wed, 2 Jul 2014 00:30:10 +0900 Subject: Add TCP_* constants included in "netinet/tcp.h". ex: TCP_NODELAY, TCP_CORK, ... --- src/const.cstub | 42 ++++++++++++++++++++++++++++++++++++++++++ src/const.def | 15 +++++++++++++++ src/socket.c | 1 + 3 files changed, 58 insertions(+) diff --git a/src/const.cstub b/src/const.cstub index 8d4f98a61..8581d6163 100644 --- a/src/const.cstub +++ b/src/const.cstub @@ -376,3 +376,45 @@ #ifdef SOL_SOCKET define_const(SOL_SOCKET); #endif +#ifdef TCP_NODELAY + define_const(TCP_NODELAY); +#endif +#ifdef TCP_MAXSEG + define_const(TCP_MAXSEG); +#endif +#ifdef TCP_CORK + define_const(TCP_CORK); +#endif +#ifdef TCP_KEEPIDLE + define_const(TCP_KEEPIDLE); +#endif +#ifdef TCP_KEEPINTVL + define_const(TCP_KEEPINTVL); +#endif +#ifdef TCP_KEEPCNT + define_const(TCP_KEEPCNT); +#endif +#ifdef TCP_SYNCNT + define_const(TCP_SYNCNT); +#endif +#ifdef TCP_LINGER2 + define_const(TCP_LINGER2); +#endif +#ifdef TCP_DEFER_ACCEPT + define_const(TCP_DEFER_ACCEPT); +#endif +#ifdef TCP_WINDOW_CLAMP + define_const(TCP_WINDOW_CLAMP); +#endif +#ifdef TCP_INFO + define_const(TCP_INFO); +#endif +#ifdef TCP_QUICKACK + define_const(TCP_QUICKACK); +#endif +#ifdef TCP_CONGESTION + define_const(TCP_CONGESTION); +#endif +#ifdef TCP_MD5SIG + define_const(TCP_MD5SIG); +#endif diff --git a/src/const.def b/src/const.def index 2899c02cb..d3921e7c9 100644 --- a/src/const.def +++ b/src/const.def @@ -134,3 +134,18 @@ SOCK_SEQPACKET SOCK_STREAM SOL_SOCKET + +TCP_NODELAY +TCP_MAXSEG +TCP_CORK +TCP_KEEPIDLE +TCP_KEEPINTVL +TCP_KEEPCNT +TCP_SYNCNT +TCP_LINGER2 +TCP_DEFER_ACCEPT +TCP_WINDOW_CLAMP +TCP_INFO +TCP_QUICKACK +TCP_CONGESTION +TCP_MD5SIG diff --git a/src/socket.c b/src/socket.c index ded5dfa25..2bf9cd675 100644 --- a/src/socket.c +++ b/src/socket.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From baa40ef2b1330cfe684f8ac6d4f19e879c960016 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Wed, 2 Jul 2014 09:09:58 +0900 Subject: sort. --- src/const.def | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/const.def b/src/const.def index d3921e7c9..a812b94c7 100644 --- a/src/const.def +++ b/src/const.def @@ -135,17 +135,17 @@ SOCK_STREAM SOL_SOCKET -TCP_NODELAY -TCP_MAXSEG +TCP_CONGESTION TCP_CORK +TCP_DEFER_ACCEPT +TCP_INFO +TCP_KEEPCNT TCP_KEEPIDLE TCP_KEEPINTVL -TCP_KEEPCNT -TCP_SYNCNT TCP_LINGER2 -TCP_DEFER_ACCEPT -TCP_WINDOW_CLAMP -TCP_INFO -TCP_QUICKACK -TCP_CONGESTION +TCP_MAXSEG TCP_MD5SIG +TCP_NODELAY +TCP_QUICKACK +TCP_SYNCNT +TCP_WINDOW_CLAMP -- cgit v1.2.3 From 04097348e886c3699f6036c2135f5306f70d1999 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Wed, 2 Jul 2014 09:12:04 +0900 Subject: more TCP options (for NetBSD). --- src/const.def | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/const.def b/src/const.def index a812b94c7..1508a143e 100644 --- a/src/const.def +++ b/src/const.def @@ -135,17 +135,20 @@ SOCK_STREAM SOL_SOCKET +TCP_CONGCTL TCP_CONGESTION TCP_CORK TCP_DEFER_ACCEPT TCP_INFO TCP_KEEPCNT TCP_KEEPIDLE +TCP_KEEPINIT TCP_KEEPINTVL TCP_LINGER2 TCP_MAXSEG TCP_MD5SIG TCP_NODELAY TCP_QUICKACK +TCP_SACK_ENABLE TCP_SYNCNT TCP_WINDOW_CLAMP -- cgit v1.2.3 From 91c285fcfe415a5963de710a4af4c9c70d8bbe27 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Wed, 2 Jul 2014 09:12:27 +0900 Subject: regen. --- src/const.cstub | 49 +++++++++++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/src/const.cstub b/src/const.cstub index 8581d6163..b3a2ee468 100644 --- a/src/const.cstub +++ b/src/const.cstub @@ -376,45 +376,54 @@ #ifdef SOL_SOCKET define_const(SOL_SOCKET); #endif -#ifdef TCP_NODELAY - define_const(TCP_NODELAY); +#ifdef TCP_CONGCTL + define_const(TCP_CONGCTL); #endif -#ifdef TCP_MAXSEG - define_const(TCP_MAXSEG); +#ifdef TCP_CONGESTION + define_const(TCP_CONGESTION); #endif #ifdef TCP_CORK define_const(TCP_CORK); #endif -#ifdef TCP_KEEPIDLE - define_const(TCP_KEEPIDLE); +#ifdef TCP_DEFER_ACCEPT + define_const(TCP_DEFER_ACCEPT); #endif -#ifdef TCP_KEEPINTVL - define_const(TCP_KEEPINTVL); +#ifdef TCP_INFO + define_const(TCP_INFO); #endif #ifdef TCP_KEEPCNT define_const(TCP_KEEPCNT); #endif -#ifdef TCP_SYNCNT - define_const(TCP_SYNCNT); +#ifdef TCP_KEEPIDLE + define_const(TCP_KEEPIDLE); +#endif +#ifdef TCP_KEEPINIT + define_const(TCP_KEEPINIT); +#endif +#ifdef TCP_KEEPINTVL + define_const(TCP_KEEPINTVL); #endif #ifdef TCP_LINGER2 define_const(TCP_LINGER2); #endif -#ifdef TCP_DEFER_ACCEPT - define_const(TCP_DEFER_ACCEPT); +#ifdef TCP_MAXSEG + define_const(TCP_MAXSEG); #endif -#ifdef TCP_WINDOW_CLAMP - define_const(TCP_WINDOW_CLAMP); +#ifdef TCP_MD5SIG + define_const(TCP_MD5SIG); #endif -#ifdef TCP_INFO - define_const(TCP_INFO); +#ifdef TCP_NODELAY + define_const(TCP_NODELAY); #endif #ifdef TCP_QUICKACK define_const(TCP_QUICKACK); #endif -#ifdef TCP_CONGESTION - define_const(TCP_CONGESTION); +#ifdef TCP_SACK_ENABLE + define_const(TCP_SACK_ENABLE); #endif -#ifdef TCP_MD5SIG - define_const(TCP_MD5SIG); +#ifdef TCP_SYNCNT + define_const(TCP_SYNCNT); +#endif +#ifdef TCP_WINDOW_CLAMP + define_const(TCP_WINDOW_CLAMP); #endif -- cgit v1.2.3 From 093f4e2cff04829dfbefe182411f59d4b366c45e Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Wed, 9 Jul 2014 12:24:50 +0900 Subject: mrb_voidp (and other macros) has gone. --- src/socket.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/socket.c b/src/socket.c index 2bf9cd675..b8d9b7613 100644 --- a/src/socket.c +++ b/src/socket.c @@ -26,6 +26,11 @@ #define E_SOCKET_ERROR (mrb_class_get(mrb, "SocketError")) +#if !defined(mrb_cptr) +#define mrb_cptr_value(m,p) mrb_voidp_value((m),(p)) +#define mrb_cptr(o) mrb_voidp(o) +#define mrb_cptr_p(o) mrb_voidp_p(o) +#endif static mrb_value mrb_addrinfo_getaddrinfo(mrb_state *mrb, mrb_value klass) @@ -76,8 +81,8 @@ mrb_addrinfo_getaddrinfo(mrb_state *mrb, mrb_value klass) } lastai = mrb_cv_get(mrb, klass, mrb_intern_lit(mrb, "_lastai")); - if (mrb_voidp_p(lastai)) { - freeaddrinfo(mrb_voidp(lastai)); + if (mrb_cptr_p(lastai)) { + freeaddrinfo(mrb_cptr(lastai)); mrb_cv_set(mrb, klass, mrb_intern_lit(mrb, "_lastai"), mrb_nil_value()); } @@ -85,7 +90,7 @@ mrb_addrinfo_getaddrinfo(mrb_state *mrb, mrb_value klass) if (error) { mrb_raisef(mrb, E_SOCKET_ERROR, "getaddrinfo: %S", mrb_str_new_cstr(mrb, gai_strerror(error))); } - mrb_cv_set(mrb, klass, mrb_intern_lit(mrb, "_lastai"), mrb_voidp_value(mrb, res0)); + mrb_cv_set(mrb, klass, mrb_intern_lit(mrb, "_lastai"), mrb_cptr_value(mrb, res0)); for (res = res0; res != NULL; res = res->ai_next) { sa = mrb_str_new(mrb, (void *)res->ai_addr, res->ai_addrlen); @@ -691,7 +696,7 @@ mrb_mruby_socket_gem_final(mrb_state* mrb) { mrb_value ai; ai = mrb_mod_cv_get(mrb, mrb_class_get(mrb, "Addrinfo"), mrb_intern_lit(mrb, "_lastai")); - if (mrb_voidp_p(ai)) { - freeaddrinfo(mrb_voidp(ai)); + if (mrb_cptr_p(ai)) { + freeaddrinfo(mrb_cptr(ai)); } } -- cgit v1.2.3 From 723db886e158acf85e5f1f9c56ee40607727eeff Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 12 Dec 2014 12:38:43 +0900 Subject: add Socket::Option#inspect without this, mirb dies. https://github.com/mruby/mruby/pull/2666 --- mrblib/socket.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrblib/socket.rb b/mrblib/socket.rb index 732a6db8e..b8f10befd 100644 --- a/mrblib/socket.rb +++ b/mrblib/socket.rb @@ -557,7 +557,7 @@ class Socket end def inspect - # notyet + "#" end def int -- cgit v1.2.3 From 3a22166c67f1d495f617f3ece5524dcdc9d2872c Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 26 Dec 2014 11:16:03 +0900 Subject: debug UNIXSocket and UNIXServer. --- README.md | 1 + mrblib/socket.rb | 63 +++++++++++++++++++++------- src/socket.c | 2 +- test/unix.rb | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 175 insertions(+), 16 deletions(-) create mode 100644 test/unix.rb diff --git a/README.md b/README.md index 2dac85aa6..5f2227e85 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ Date: Tue, 21 May 2013 04:31:30 GMT - add missing methods - write more tests - fix possible descriptor leakage (see XXX comments) +- `UNIXSocket#recv_io` `UNIXSocket#send_io` ## License diff --git a/mrblib/socket.rb b/mrblib/socket.rb index b8f10befd..e3a1487d4 100644 --- a/mrblib/socket.rb +++ b/mrblib/socket.rb @@ -181,6 +181,10 @@ class BasicSocket @do_not_reverse_lookup = @@do_not_reverse_lookup end + def self.for_fd(fd) + super(fd, "r+") + end + #def connect_address def local_address @@ -452,14 +456,24 @@ class Socket end end -class UNIXSocket +class UNIXSocket < BasicSocket def initialize(path, &block) - super(Socket._socket(AF_UNIX, SOCK_STREAM, 0), "r+") - Socket._connect(self.fileno, Socket.sockaddr_un(path)) - if block - block.call(self) + if self.is_a? UNIXServer + super(path, "r") else - self + super(Socket._socket(Socket::AF_UNIX, Socket::SOCK_STREAM, 0), "r+") + Socket._connect(self.fileno, Socket.sockaddr_un(path)) + + if block_given? + begin + yield self + ensure + begin + self.close unless self.closed? + rescue StandardError + end + end + end end end @@ -488,23 +502,42 @@ class UNIXSocket def recvfrom(maxlen, flags=0) msg, sa = _recvfrom(maxlen, flags) - [ msg, [ "AF_UNIX", Addrinfo.new(sa).unix_path ] ] + path = (sa.size > 0) ? Addrinfo.new(sa).unix_path : "" + [ msg, [ "AF_UNIX", path ] ] end #def send_io end -class UNIXServer - def initialize(path, &block) - super(Socket._socket(Socket::AF_UNIX, Socket::SOCK_STREAM, 0), "r") - Socket._bind(self.fileno, Socket.pack_sockaddr_un(path)) - listen(5) - self +class UNIXServer < UNIXSocket + def initialize(path) + fd = Socket._socket(Socket::AF_UNIX, Socket::SOCK_STREAM, 0) + begin + super(fd) + Socket._bind(fd, Socket.pack_sockaddr_un(path)) + self.listen(5) + rescue => e + IO._sysclose(fd) rescue nil + raise e + end + + if block_given? + begin + yield self + ensure + self.close rescue nil unless self.closed? + end + end end def accept - fd, addr = self.sysaccept - [ UNIXSocket.for_fd(fd), addr ] + fd = self.sysaccept + begin + sock = UNIXSocket.for_fd(fd) + rescue + IO._sysclose(fd) rescue nil + end + sock end def accept_nonblock diff --git a/src/socket.c b/src/socket.c index b8d9b7613..ea958f953 100644 --- a/src/socket.c +++ b/src/socket.c @@ -673,7 +673,7 @@ mrb_mruby_socket_gem_init(mrb_state* mrb) mrb_define_class_method(mrb, sock, "socketpair", mrb_socket_socketpair, MRB_ARGS_REQ(3)); //mrb_define_method(mrb, sock, "sysaccept", mrb_socket_accept, MRB_ARGS_NONE()); - usock = mrb_define_class(mrb, "UNIXSocket", io); + usock = mrb_define_class(mrb, "UNIXSocket", bsock); //mrb_define_class_method(mrb, usock, "pair", mrb_unixsocket_open, MRB_ARGS_OPT(2)); //mrb_define_class_method(mrb, usock, "socketpair", mrb_unixsocket_open, MRB_ARGS_OPT(2)); diff --git a/test/unix.rb b/test/unix.rb new file mode 100644 index 000000000..379eb1ec4 --- /dev/null +++ b/test/unix.rb @@ -0,0 +1,125 @@ +def unixserver_test_block + File.unlink SocketTest.tmppath rescue nil + begin + result = yield SocketTest.tmppath + ensure + File.unlink SocketTest.tmppath rescue nil + end + result +end + +def with_unix_server + unixserver_test_block do |path| + UNIXServer.open(path) { |server| + yield path, server + } + end +end + +def with_unix_client + with_unix_server do |path, server| + UNIXSocket.open(path) do |csock| + ssock = server.accept + begin + yield path, server, ssock, csock + ensure + ssock.close unless ssock.closed? rescue nil + end + end + end +end + +assert('UNIXServer.new') do + unixserver_test_block do |path| + server = UNIXServer.new(path) + assert_true server.is_a? UNIXServer + server.close + File.unlink path + + s2 = nil + result = UNIXServer.open(path) { |s1| + assert_true s1.is_a? UNIXServer + s2 = s1 + 1234 + } + assert_equal 1234, result + assert_true s2.is_a? UNIXServer + assert_true s2.closed? + end +end + +# assert('UNIXServer#accept_nonblock') - would block if fails + +assert('UNIXServer#addr') do + with_unix_server do |path, server| + assert_equal [ "AF_UNIX", path], server.addr + end +end + +assert('UNIXServer#path') do + with_unix_server do |path, server| + assert_equal path, server.path + end +end + +# assert('UNIXServer#peeraddr') - will raise a runtime exception + +assert('UNIXServer#listen') do + with_unix_server do |path, server| + assert_equal 0, server.listen(1) + end +end + +assert('UNIXServer#sysaccept') do + with_unix_server do |path, server| + UNIXSocket.open(path) do |csock| + begin + fd = server.sysaccept + assert_true fd.kind_of? Integer + ensure + IO._sysclose(fd) rescue nil + end + end + end +end + +assert('UNIXSocket.new') do + with_unix_server do |path, server| + c = UNIXSocket.new(path) + assert_true c.is_a? UNIXSocket + c.close + true + end +end + +assert('UNIXSocket#addr') do + with_unix_client do |path, server, ssock, csock| + assert_equal [ "AF_UNIX", path ], ssock.addr + assert_equal [ "AF_UNIX", "" ], csock.addr + end +end + +assert('UNIXSocket#path') do + with_unix_client do |path, server, ssock, csock| + assert_equal path, ssock.path + assert_equal "", csock.path + end +end + +assert('UNIXSocket#peeraddr') do + with_unix_client do |path, server, ssock, csock| + assert_equal [ "AF_UNIX", "" ], ssock.peeraddr + assert_equal [ "AF_UNIX", path ], csock.peeraddr + end +end + +assert('UNIXSocket#recvfrom') do + with_unix_client do |path, server, ssock, csock| + str = "0123456789" + ssock.send str, 0 + a = csock.recvfrom(8) + assert_equal str[0, 8], a[0] + assert_equal "AF_UNIX", a[1][0] + # a[1][1] would be "" or something + end +end -- cgit v1.2.3 From a960a6f93184cdf6af839775dbb55022d5fbde8a Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 26 Dec 2014 11:19:53 +0900 Subject: failed to add... --- test/sockettest.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 test/sockettest.c diff --git a/test/sockettest.c b/test/sockettest.c new file mode 100644 index 000000000..9161bc3f3 --- /dev/null +++ b/test/sockettest.c @@ -0,0 +1,16 @@ +#include + +#include "mruby.h" + +mrb_value +mrb_sockettest_tmppath(mrb_state *mrb, mrb_value klass) +{ + return mrb_str_new_cstr(mrb, tempnam(NULL, "mruby-socket")); +} + +void +mrb_mruby_socket_gem_test(mrb_state* mrb) +{ + struct RClass *c = mrb_define_module(mrb, "SocketTest"); + mrb_define_class_method(mrb, c, "tmppath", mrb_sockettest_tmppath, MRB_ARGS_NONE()); +} -- cgit v1.2.3 From a09858af61e63c5b93f5bb858b6fa1c74a3e7dc7 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 26 Dec 2014 13:27:39 +0900 Subject: syscalls may return sockaddr shorter than sizeof(struct sockaddr) on Linux. --- src/socket.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/socket.c b/src/socket.c index ea958f953..f2e4e2e0b 100644 --- a/src/socket.c +++ b/src/socket.c @@ -549,9 +549,15 @@ mrb_socket_sockaddr_family(mrb_state *mrb, mrb_value klass) mrb_value sa; mrb_get_args(mrb, "S", &sa); +#ifdef __linux__ + if (RSTRING_LEN(sa) < offsetof(struct sockaddr, sa_family) + sizeof(sa_family_t)) { + mrb_raisef(mrb, E_SOCKET_ERROR, "invalid sockaddr (too short)"); + } +#else if (RSTRING_LEN(sa) < sizeof(struct sockaddr)) { mrb_raisef(mrb, E_SOCKET_ERROR, "invalid sockaddr (too short)"); } +#endif return mrb_fixnum_value(((struct sockaddr *)RSTRING_PTR(sa))->sa_family); } -- cgit v1.2.3 From 7b17158f88a64c97c34cd4b617bb9a0185e5fb43 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 26 Dec 2014 13:36:11 +0900 Subject: remove unused variables. --- src/socket.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/socket.c b/src/socket.c index f2e4e2e0b..bdfada7b5 100644 --- a/src/socket.c +++ b/src/socket.c @@ -36,8 +36,7 @@ static mrb_value mrb_addrinfo_getaddrinfo(mrb_state *mrb, mrb_value klass) { struct addrinfo hints, *res0, *res; - struct sockaddr_un sock_un; - mrb_value ai, ary, family, lastai, nodename, protocol, s, sa, service, socktype; + mrb_value ai, ary, family, lastai, nodename, protocol, sa, service, socktype; mrb_int flags; int arena_idx, error; const char *hostname = NULL, *servname = NULL; @@ -45,8 +44,6 @@ mrb_addrinfo_getaddrinfo(mrb_state *mrb, mrb_value klass) ary = mrb_ary_new(mrb); arena_idx = mrb_gc_arena_save(mrb); /* ary must be on arena! */ - s = mrb_str_new(mrb, (void *)&sock_un, sizeof(sock_un)); - family = socktype = protocol = mrb_nil_value(); flags = 0; mrb_get_args(mrb, "oo|oooi", &nodename, &service, &family, &socktype, &protocol, &flags); -- cgit v1.2.3 From 0d05a22602a49bdaba3f304ec6eb0808f1e6c286 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 26 Dec 2014 16:00:50 +0900 Subject: don't call undefined method. fixes #15. --- mrblib/socket.rb | 7 ++++--- test/socket.rb | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/mrblib/socket.rb b/mrblib/socket.rb index e3a1487d4..2ff144080 100644 --- a/mrblib/socket.rb +++ b/mrblib/socket.rb @@ -63,9 +63,9 @@ class Addrinfo def inspect if ipv4? or ipv6? - if @protocol == Socket::IPPROTO_TCP + if @protocol == Socket::IPPROTO_TCP or (@socktype == Socket::SOCK_STREAM and @protocol == 0) proto = 'TCP' - elsif @protocol == Socket::IPPROTO_UDP + elsif @protocol == Socket::IPPROTO_UDP or (@socktype == Socket::SOCK_DGRAM and @protocol == 0) proto = 'UDP' else proto = '???' @@ -439,7 +439,8 @@ class Socket def recvfrom(maxlen, flags=0) msg, sa = _recvfrom(maxlen, flags) - [ msg, _ai_to_array(Addrinfo.new(sa)) ] + socktype = self.getsockopt(Socket::SOL_SOCKET, Socket::SO_TYPE).int + [ msg, Addrinfo.new(sa, Socket::PF_UNSPEC, socktype) ] end def recvfrom_nonblock(*args) diff --git a/test/socket.rb b/test/socket.rb index b602cc15d..517f5a00c 100644 --- a/test/socket.rb +++ b/test/socket.rb @@ -15,3 +15,20 @@ assert('Socket::getaddrinfo') do assert_equal Socket::SOCK_DGRAM, a[5] assert_equal Socket::IPPROTO_UDP, a[6] end + +assert('Socket#recvfrom') do + begin + sstr = "abcdefg" + s = Socket.new(Socket::AF_INET, Socket::SOCK_DGRAM, 0) + c = Socket.new(Socket::AF_INET, Socket::SOCK_DGRAM, 0) + s.bind(Socket.sockaddr_in(0, "127.0.0.1")) + c.send sstr, 0, s.getsockname + rstr, ai = s.recvfrom sstr.size + + assert_equal sstr, rstr + assert_true "127.0.0.1", ai.ip_address + ensure + s.close rescue nil + c.close rescue nil + end +end -- cgit v1.2.3 From e4006cb53ab807e0c72466752bdbb550ebca2c99 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 26 Dec 2014 16:12:41 +0900 Subject: Socket::Option requires iij/mruby-pack. --- mrbgem.rake | 1 + run_test.rb | 1 + 2 files changed, 2 insertions(+) diff --git a/mrbgem.rake b/mrbgem.rake index 6bb141061..f9b8e9670 100644 --- a/mrbgem.rake +++ b/mrbgem.rake @@ -5,5 +5,6 @@ MRuby::Gem::Specification.new('mruby-socket') do |spec| spec.cc.include_paths << "#{build.root}/src" spec.add_dependency('mruby-io') + spec.add_dependency('mruby-pack') # spec.add_dependency('mruby-mtest') end diff --git a/run_test.rb b/run_test.rb index bbdfaab90..77e90a467 100644 --- a/run_test.rb +++ b/run_test.rb @@ -21,6 +21,7 @@ MRuby::Build.new do |conf| conf.gem :git => 'https://github.com/iij/mruby-mtest.git' conf.gem :git => 'https://github.com/iij/mruby-io.git' + conf.gem :git => 'https://github.com/iij/mruby-pack.git' conf.gem File.expand_path(File.dirname(__FILE__)) end -- cgit v1.2.3 From 1629e860634ea4fb56644d5dace0ee55e59c3ce4 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 13 Feb 2015 11:35:36 +0900 Subject: add IPv6 constants defined in RFC3493. --- src/const.cstub | 21 +++++++++++++++++++++ src/const.def | 8 ++++++++ 2 files changed, 29 insertions(+) diff --git a/src/const.cstub b/src/const.cstub index b3a2ee468..553e47f8c 100644 --- a/src/const.cstub +++ b/src/const.cstub @@ -175,6 +175,27 @@ #ifdef IP_XFRM_POLICY define_const(IP_XFRM_POLICY); #endif +#ifdef IPV6_JOIN_GROUP + define_const(IPV6_JOIN_GROUP); +#endif +#ifdef IPV6_LEAVE_GROUP + define_const(IPV6_LEAVE_GROUP); +#endif +#ifdef IPV6_MULTICAST_HOPS + define_const(IPV6_MULTICAST_HOPS); +#endif +#ifdef IPV6_MULTICAST_IF + define_const(IPV6_MULTICAST_IF); +#endif +#ifdef IPV6_MULTICAST_LOOP + define_const(IPV6_MULTICAST_LOOP); +#endif +#ifdef IPV6_UNICAST_HOPS + define_const(IPV6_UNICAST_HOPS); +#endif +#ifdef IPV6_V6ONLY + define_const(IPV6_V6ONLY); +#endif #ifdef IPPROTO_AH define_const(IPPROTO_AH); #endif diff --git a/src/const.def b/src/const.def index 1508a143e..e0ee5e2a4 100644 --- a/src/const.def +++ b/src/const.def @@ -60,6 +60,14 @@ IP_TTL IP_UNBLOCK_SOURCE IP_XFRM_POLICY +IPV6_JOIN_GROUP +IPV6_LEAVE_GROUP +IPV6_MULTICAST_HOPS +IPV6_MULTICAST_IF +IPV6_MULTICAST_LOOP +IPV6_UNICAST_HOPS +IPV6_V6ONLY + IPPROTO_AH IPPROTO_DSTOPTS IPPROTO_ESP -- cgit v1.2.3 From dacb8b626b293670567bd3cf7870c3e3c4147a08 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Wed, 20 May 2015 11:38:03 +0900 Subject: failed to remove temporary files! --- test/unix.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/unix.rb b/test/unix.rb index 379eb1ec4..88ad17101 100644 --- a/test/unix.rb +++ b/test/unix.rb @@ -1,9 +1,10 @@ def unixserver_test_block - File.unlink SocketTest.tmppath rescue nil + path = SocketTest.tmppath + File.unlink path rescue nil begin - result = yield SocketTest.tmppath + result = yield path ensure - File.unlink SocketTest.tmppath rescue nil + File.unlink path rescue nil end result end -- cgit v1.2.3 From 7d8cbf1a9c9d88cce977b32cfb8b416901856a98 Mon Sep 17 00:00:00 2001 From: Rubyist Date: Fri, 17 Jul 2015 23:03:34 -0700 Subject: Added Winsock 2 to list of libraries to use when building for Windows targets --- mrbgem.rake | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mrbgem.rake b/mrbgem.rake index f9b8e9670..ef91bdfcb 100644 --- a/mrbgem.rake +++ b/mrbgem.rake @@ -3,6 +3,12 @@ MRuby::Gem::Specification.new('mruby-socket') do |spec| spec.authors = 'Internet Initiative Japan' spec.cc.include_paths << "#{build.root}/src" + + # If Windows, use winsock + if ( /mswin|mingw|win32/ =~ RUBY_PLATFORM ) then + spec.linker.libraries << "wsock32" + spec.linker.libraries << "ws2_32" + end spec.add_dependency('mruby-io') spec.add_dependency('mruby-pack') -- cgit v1.2.3 From 752f7c1526ab2eace3c8d49cc73f963b00e1c3c7 Mon Sep 17 00:00:00 2001 From: Rubyist Date: Fri, 17 Jul 2015 23:45:02 -0700 Subject: Minimal semi-working compile on Windows platforms. --- src/socket.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 62 insertions(+), 15 deletions(-) diff --git a/src/socket.c b/src/socket.c index bdfada7b5..506142f3f 100644 --- a/src/socket.c +++ b/src/socket.c @@ -4,19 +4,28 @@ ** See Copyright Notice in mruby.h */ -#include "mruby.h" -#include -#include -#include -#include -#include -#include -#include -#include +#ifdef _WIN32 + #include + #include + #include + + #define SHUT_RDWR SD_BOTH +#else + #include + #include + #include + #include + #include + #include + #include + #include + #include +#endif + #include #include -#include +#include "mruby.h" #include "mruby/array.h" #include "mruby/class.h" #include "mruby/data.h" @@ -130,6 +139,7 @@ mrb_addrinfo_getnameinfo(mrb_state *mrb, mrb_value self) return ary; } +#ifndef _WIN32 static mrb_value mrb_addrinfo_unix_path(mrb_state *mrb, mrb_value self) { @@ -140,6 +150,7 @@ mrb_addrinfo_unix_path(mrb_state *mrb, mrb_value self) mrb_raise(mrb, E_SOCKET_ERROR, "need AF_UNIX address"); return mrb_str_new_cstr(mrb, ((struct sockaddr_un *)RSTRING_PTR(sastr))->sun_path); } +#endif static mrb_value sa2addrlist(mrb_state *mrb, const struct sockaddr *sa, socklen_t salen) @@ -244,7 +255,8 @@ mrb_basicsocket_getsockname(mrb_state *mrb, mrb_value self) static mrb_value mrb_basicsocket_getsockopt(mrb_state *mrb, mrb_value self) { - int opt, s; + char opt[4]; + int s; mrb_int family, level, optname; mrb_value c, data; socklen_t optlen; @@ -252,11 +264,11 @@ mrb_basicsocket_getsockopt(mrb_state *mrb, mrb_value self) mrb_get_args(mrb, "ii", &level, &optname); s = socket_fd(mrb, self); optlen = sizeof(opt); - if (getsockopt(s, level, optname, &opt, &optlen) == -1) + if (getsockopt(s, level, optname, opt, &optlen) == -1) mrb_sys_fail(mrb, "getsockopt"); c = mrb_const_get(mrb, mrb_obj_value(mrb_class_get(mrb, "Socket")), mrb_intern_lit(mrb, "Option")); family = socket_family(s); - data = mrb_str_new(mrb, (char *)&opt, sizeof(int)); + data = mrb_str_new(mrb, opt, sizeof(int)); return mrb_funcall(mrb, c, "new", 4, mrb_fixnum_value(family), mrb_fixnum_value(level), mrb_fixnum_value(optname), data); } @@ -323,10 +335,17 @@ mrb_basicsocket_setnonblock(mrb_state *mrb, mrb_value self) { int fd, flags; mrb_value bool; +#ifdef _WIN32 + u_long mode = 1; +#endif mrb_get_args(mrb, "o", &bool); fd = socket_fd(mrb, self); - +#ifdef _WIN32 + flags = ioctlsocket(fd, FIONBIO, &mode); + if (flags != NO_ERROR) + mrb_sys_fail(mrb, "ioctlsocket"); +#else flags = fcntl(fd, F_GETFL, 0); if (flags == 1) mrb_sys_fail(mrb, "fcntl"); @@ -336,6 +355,7 @@ mrb_basicsocket_setnonblock(mrb_state *mrb, mrb_value self) flags &= ~O_NONBLOCK; if (fcntl(fd, F_SETFL, flags) == -1) mrb_sys_fail(mrb, "fcntl"); +#endif return mrb_nil_value(); } @@ -561,6 +581,10 @@ mrb_socket_sockaddr_family(mrb_state *mrb, mrb_value klass) static mrb_value mrb_socket_sockaddr_un(mrb_state *mrb, mrb_value klass) { +#ifdef _WIN32 + mrb_sys_fail(mrb, "sockaddr_un unsupported on Windows"); + return mrb_nil_value(); +#else struct sockaddr_un *sunp; mrb_value path, s; @@ -575,11 +599,16 @@ mrb_socket_sockaddr_un(mrb_state *mrb, mrb_value klass) sunp->sun_path[RSTRING_LEN(path)] = '\0'; mrb_str_resize(mrb, s, sizeof(struct sockaddr_un)); return s; +#endif } static mrb_value mrb_socket_socketpair(mrb_state *mrb, mrb_value klass) { +#ifdef _WIN32 + mrb_sys_fail(mrb, "socketpair unsupported on Windows"); + return mrb_nil_value(); +#else mrb_value ary; mrb_int domain, type, protocol; int sv[2]; @@ -593,6 +622,7 @@ mrb_socket_socketpair(mrb_state *mrb, mrb_value klass) mrb_ary_push(mrb, ary, mrb_fixnum_value(sv[0])); mrb_ary_push(mrb, ary, mrb_fixnum_value(sv[1])); return ary; +#endif } static mrb_value @@ -622,14 +652,26 @@ mrb_tcpsocket_allocate(mrb_state *mrb, mrb_value klass) void mrb_mruby_socket_gem_init(mrb_state* mrb) { - struct RClass *io, *ai, *sock, *bsock, *ipsock, *tcpsock, *udpsock, *usock; + struct RClass *io, *ai, *sock, *bsock, *ipsock, *tcpsock, *udpsock; struct RClass *constants; +#ifdef _WIN32 + WSADATA wsaData; + int result; + result = WSAStartup(MAKEWORD(2,2), &wsaData); + if (result != NO_ERROR) + mrb_sys_fail(mrb, "WSAStartup"); +#else + struct RClass *usock; +#endif + ai = mrb_define_class(mrb, "Addrinfo", mrb->object_class); mrb_mod_cv_set(mrb, ai, mrb_intern_lit(mrb, "_lastai"), mrb_nil_value()); mrb_define_class_method(mrb, ai, "getaddrinfo", mrb_addrinfo_getaddrinfo, MRB_ARGS_REQ(2)|MRB_ARGS_OPT(4)); mrb_define_method(mrb, ai, "getnameinfo", mrb_addrinfo_getnameinfo, MRB_ARGS_OPT(1)); +#ifndef _WIN32 mrb_define_method(mrb, ai, "unix_path", mrb_addrinfo_unix_path, MRB_ARGS_NONE()); +#endif io = mrb_class_get(mrb, "IO"); @@ -676,7 +718,9 @@ mrb_mruby_socket_gem_init(mrb_state* mrb) mrb_define_class_method(mrb, sock, "socketpair", mrb_socket_socketpair, MRB_ARGS_REQ(3)); //mrb_define_method(mrb, sock, "sysaccept", mrb_socket_accept, MRB_ARGS_NONE()); +#ifndef _WIN32 usock = mrb_define_class(mrb, "UNIXSocket", bsock); +#endif //mrb_define_class_method(mrb, usock, "pair", mrb_unixsocket_open, MRB_ARGS_OPT(2)); //mrb_define_class_method(mrb, usock, "socketpair", mrb_unixsocket_open, MRB_ARGS_OPT(2)); @@ -702,4 +746,7 @@ mrb_mruby_socket_gem_final(mrb_state* mrb) if (mrb_cptr_p(ai)) { freeaddrinfo(mrb_cptr(ai)); } +#ifdef _WIN32 + WSACleanup(); +#endif } -- cgit v1.2.3 From a426f0e2b580ce4c7335c4040458b1239148b6e2 Mon Sep 17 00:00:00 2001 From: Rubyist Date: Sat, 18 Jul 2015 23:22:57 -0700 Subject: Overrided close and write to work on Win32 platforms --- src/socket.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/socket.c b/src/socket.c index 506142f3f..00f1c6ce4 100644 --- a/src/socket.c +++ b/src/socket.c @@ -649,6 +649,37 @@ mrb_tcpsocket_allocate(mrb_state *mrb, mrb_value klass) return mrb_obj_value((struct RObject*)mrb_obj_alloc(mrb, ttype, c)); } +/* Windows overrides for IO methods on BasicSocket objects. + * This is because sockets on Windows are not the same as file + * descriptors, and thus functions which operate on file descriptors + * will break on socket descriptors. + */ +#ifdef _WIN32 +static mrb_value +mrb_win32_basicsocket_close(mrb_state *mrb, mrb_value self) +{ + if (closesocket(socket_fd(mrb, self)) != NO_ERROR) + mrb_sys_fail(mrb, "closesocket"); + return mrb_nil_value(); +} + +static mrb_value +mrb_win32_basicsocket_write(mrb_state *mrb, mrb_value self) +{ + int n; + SOCKET sd; + mrb_value str; + + sd = socket_fd(mrb, self); + mrb_get_args(mrb, "S", &str); + n = send(sd, RSTRING_PTR(str), RSTRING_LEN(str), 0); + if (n == SOCKET_ERROR) + mrb_sys_fail(mrb, "write"); + return mrb_fixnum_value(n); +} + +#endif + void mrb_mruby_socket_gem_init(mrb_state* mrb) { @@ -728,6 +759,12 @@ mrb_mruby_socket_gem_init(mrb_state* mrb) //mrb_define_method(mrb, usock, "recvfrom", mrb_unixsocket_peeraddr, MRB_ARGS_NONE()); //mrb_define_method(mrb, usock, "send_io", mrb_unixsocket_peeraddr, MRB_ARGS_NONE()); + /* Windows IO Method Overrides on BasicSocket */ +#ifdef _WIN32 + mrb_define_method(mrb, bsock, "close", mrb_win32_basicsocket_close, MRB_ARGS_NONE()); + mrb_define_method(mrb, bsock, "write", mrb_win32_basicsocket_write, MRB_ARGS_REQ(1)); +#endif + constants = mrb_define_module_under(mrb, sock, "Constants"); #define define_const(SYM) \ -- cgit v1.2.3 From 7ee9ab89f9577130fc15e6d0934655aa1f4df124 Mon Sep 17 00:00:00 2001 From: Rubyist Date: Tue, 21 Jul 2015 03:37:28 -0700 Subject: Changed some uses of mrb_sys_fail to instead use mrb_raise where appropriate --- src/socket.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/socket.c b/src/socket.c index 00f1c6ce4..277e221ee 100644 --- a/src/socket.c +++ b/src/socket.c @@ -582,7 +582,7 @@ static mrb_value mrb_socket_sockaddr_un(mrb_state *mrb, mrb_value klass) { #ifdef _WIN32 - mrb_sys_fail(mrb, "sockaddr_un unsupported on Windows"); + mrb_raise(mrb, E_NOTIMP_ERROR, "sockaddr_un unsupported on Windows"); return mrb_nil_value(); #else struct sockaddr_un *sunp; @@ -606,7 +606,7 @@ static mrb_value mrb_socket_socketpair(mrb_state *mrb, mrb_value klass) { #ifdef _WIN32 - mrb_sys_fail(mrb, "socketpair unsupported on Windows"); + mrb_raise(mrb, E_NOTIMP_ERROR, "socketpair unsupported on Windows"); return mrb_nil_value(); #else mrb_value ary; @@ -659,7 +659,7 @@ static mrb_value mrb_win32_basicsocket_close(mrb_state *mrb, mrb_value self) { if (closesocket(socket_fd(mrb, self)) != NO_ERROR) - mrb_sys_fail(mrb, "closesocket"); + mrb_sys_fail(mrb, "close"); return mrb_nil_value(); } @@ -691,7 +691,7 @@ mrb_mruby_socket_gem_init(mrb_state* mrb) int result; result = WSAStartup(MAKEWORD(2,2), &wsaData); if (result != NO_ERROR) - mrb_sys_fail(mrb, "WSAStartup"); + mrb_raise(mrb, E_RUNTIME_ERROR, "WSAStartup failed"); #else struct RClass *usock; #endif -- cgit v1.2.3 From 4ab922044de80da5e6167799d070cec2e73b4204 Mon Sep 17 00:00:00 2001 From: Rubyist Date: Tue, 21 Jul 2015 15:56:27 -0700 Subject: Removed unnecessary/incorrect use of sizeof(int) and corrected more improper usages of mrb_sys_fail --- src/socket.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/socket.c b/src/socket.c index 277e221ee..fc2abed5b 100644 --- a/src/socket.c +++ b/src/socket.c @@ -255,7 +255,7 @@ mrb_basicsocket_getsockname(mrb_state *mrb, mrb_value self) static mrb_value mrb_basicsocket_getsockopt(mrb_state *mrb, mrb_value self) { - char opt[4]; + char opt[8]; int s; mrb_int family, level, optname; mrb_value c, data; @@ -268,7 +268,7 @@ mrb_basicsocket_getsockopt(mrb_state *mrb, mrb_value self) mrb_sys_fail(mrb, "getsockopt"); c = mrb_const_get(mrb, mrb_obj_value(mrb_class_get(mrb, "Socket")), mrb_intern_lit(mrb, "Option")); family = socket_family(s); - data = mrb_str_new(mrb, opt, sizeof(int)); + data = mrb_str_new(mrb, opt, optlen); return mrb_funcall(mrb, c, "new", 4, mrb_fixnum_value(family), mrb_fixnum_value(level), mrb_fixnum_value(optname), data); } @@ -659,7 +659,7 @@ static mrb_value mrb_win32_basicsocket_close(mrb_state *mrb, mrb_value self) { if (closesocket(socket_fd(mrb, self)) != NO_ERROR) - mrb_sys_fail(mrb, "close"); + mrb_raise(mrb, E_SOCKET_ERROR, "closesocket unsuccessful"); return mrb_nil_value(); } @@ -674,7 +674,7 @@ mrb_win32_basicsocket_write(mrb_state *mrb, mrb_value self) mrb_get_args(mrb, "S", &str); n = send(sd, RSTRING_PTR(str), RSTRING_LEN(str), 0); if (n == SOCKET_ERROR) - mrb_sys_fail(mrb, "write"); + mrb_sys_fail(mrb, "send"); return mrb_fixnum_value(n); } -- cgit v1.2.3 From f80a4fd0e8781b78091028aeddfd50042874ea56 Mon Sep 17 00:00:00 2001 From: Rubyist Date: Sat, 25 Jul 2015 00:24:31 -0700 Subject: Added functioning read for Win32 --- src/socket.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/src/socket.c b/src/socket.c index fc2abed5b..7203db979 100644 --- a/src/socket.c +++ b/src/socket.c @@ -663,6 +663,86 @@ mrb_win32_basicsocket_close(mrb_state *mrb, mrb_value self) return mrb_nil_value(); } +static mrb_value +mrb_win32_basicsocket_read(mrb_state *mrb, mrb_value self) +{ +#define BUF_LEN 4096 + char buf[BUF_LEN]; + int sd, bytes_read; + mrb_int read_len; + mrb_value str = mrb_str_new(mrb, NULL, 0); + mrb_value len_arg = mrb_nil_value(); + + /* For compatibility with IO::read, we accept an object instead of just + * an mrb_int. Then we raise an exception if it isn't an mrb_int or nil. + */ + mrb_get_args(mrb, "|o", &len_arg); + if (mrb_fixnum_p(len_arg)) { + read_len = mrb_fixnum(len_arg); + if (read_len < 0) { + mrb_str_cat_cstr(mrb, str, "negative length: "); + mrb_str_append(mrb, str, len_arg); + mrb_str_cat_cstr(mrb, str, " given"); + mrb_raise(mrb, E_ARGUMENT_ERROR, mrb_string_value_cstr(mrb, &str)); + return mrb_nil_value(); + } else if (read_len == 0) { + return str; + } + } else if (mrb_nil_p(len_arg)) { + read_len = 0; + } else { + mrb_str_cat_cstr(mrb, str, "can't convert "); + mrb_str_append(mrb, str, len_arg); + mrb_str_cat_cstr(mrb, str, " into Integer"); + mrb_raise(mrb, E_TYPE_ERROR, mrb_string_value_cstr(mrb, &str)); + return mrb_nil_value(); + } + + sd = socket_fd(mrb, self); + bytes_read = 0; + + /* Behavior of positive integer argument: read until length bytes have been + * read, or until the socket has closed. */ + if (read_len > 0) { + int n = 0; + int max_read_len = BUF_LEN; + int keep_reading = 1; + while (keep_reading) { + if (max_read_len > (read_len - bytes_read)) + max_read_len = read_len - bytes_read; + n = recv(sd, buf, max_read_len, 0); + + if (n == SOCKET_ERROR) { + mrb_sys_fail(mrb, "recv"); + } else if (n == 0) { + keep_reading = 0; + } else { + mrb_str_cat(mrb, str, buf, n); + bytes_read += n; + if (bytes_read >= read_len) + keep_reading = 0; + } + } + } + /* Behavior of nil/default argument: read until socket has closed */ + else { + int keep_reading = 1; + while (keep_reading) { + bytes_read = recv(sd, buf, BUF_LEN, 0); + if (bytes_read == SOCKET_ERROR) { + mrb_sys_fail(mrb, "recv"); + } else if (bytes_read == 0) { + keep_reading = 0; + } else { + mrb_str_cat(mrb, str, buf, bytes_read); + } + } + } + + return str; +#undef BUF_LEN +} + static mrb_value mrb_win32_basicsocket_write(mrb_state *mrb, mrb_value self) { @@ -762,6 +842,7 @@ mrb_mruby_socket_gem_init(mrb_state* mrb) /* Windows IO Method Overrides on BasicSocket */ #ifdef _WIN32 mrb_define_method(mrb, bsock, "close", mrb_win32_basicsocket_close, MRB_ARGS_NONE()); + mrb_define_method(mrb, bsock, "read", mrb_win32_basicsocket_read, MRB_ARGS_OPT(1)); mrb_define_method(mrb, bsock, "write", mrb_win32_basicsocket_write, MRB_ARGS_REQ(1)); #endif -- cgit v1.2.3 From 2929c629d455bf48bf72c6a819ef85f7c626f5aa Mon Sep 17 00:00:00 2001 From: Asmod4n Date: Mon, 27 Jul 2015 18:42:22 +0200 Subject: added SO_NOSIGPIPE --- src/const.cstub | 3 +++ src/const.def | 1 + 2 files changed, 4 insertions(+) diff --git a/src/const.cstub b/src/const.cstub index 553e47f8c..52f9a7813 100644 --- a/src/const.cstub +++ b/src/const.cstub @@ -340,6 +340,9 @@ #ifdef SO_LINGER define_const(SO_LINGER); #endif +#ifdef SO_NOSIGPIPE + define_const(SO_NOSIGPIPE); +#endif #ifdef SO_OOBINLINE define_const(SO_OOBINLINE); #endif diff --git a/src/const.def b/src/const.def index e0ee5e2a4..27d246c13 100644 --- a/src/const.def +++ b/src/const.def @@ -121,6 +121,7 @@ SO_DONTROUTE SO_ERROR SO_KEEPALIVE SO_LINGER +SO_NOSIGPIPE SO_OOBINLINE SO_PEERCRED SO_RCVBUF -- cgit v1.2.3 From c43a08314e58df188708991533143dc86847bda6 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 3 Aug 2015 04:12:10 -0700 Subject: Changed IO overrides to use sysread and syswrite instead of read and write --- src/socket.c | 112 ++++++++++++++++++++++------------------------------------- 1 file changed, 42 insertions(+), 70 deletions(-) diff --git a/src/socket.c b/src/socket.c index 7203db979..aee593cc9 100644 --- a/src/socket.c +++ b/src/socket.c @@ -663,88 +663,59 @@ mrb_win32_basicsocket_close(mrb_state *mrb, mrb_value self) return mrb_nil_value(); } +#define E_EOF_ERROR (mrb_class_get(mrb, "EOFError")) static mrb_value -mrb_win32_basicsocket_read(mrb_state *mrb, mrb_value self) +mrb_win32_basicsocket_sysread(mrb_state *mrb, mrb_value self) { -#define BUF_LEN 4096 - char buf[BUF_LEN]; - int sd, bytes_read; - mrb_int read_len; - mrb_value str = mrb_str_new(mrb, NULL, 0); - mrb_value len_arg = mrb_nil_value(); - - /* For compatibility with IO::read, we accept an object instead of just - * an mrb_int. Then we raise an exception if it isn't an mrb_int or nil. - */ - mrb_get_args(mrb, "|o", &len_arg); - if (mrb_fixnum_p(len_arg)) { - read_len = mrb_fixnum(len_arg); - if (read_len < 0) { - mrb_str_cat_cstr(mrb, str, "negative length: "); - mrb_str_append(mrb, str, len_arg); - mrb_str_cat_cstr(mrb, str, " given"); - mrb_raise(mrb, E_ARGUMENT_ERROR, mrb_string_value_cstr(mrb, &str)); - return mrb_nil_value(); - } else if (read_len == 0) { - return str; - } - } else if (mrb_nil_p(len_arg)) { - read_len = 0; - } else { - mrb_str_cat_cstr(mrb, str, "can't convert "); - mrb_str_append(mrb, str, len_arg); - mrb_str_cat_cstr(mrb, str, " into Integer"); - mrb_raise(mrb, E_TYPE_ERROR, mrb_string_value_cstr(mrb, &str)); + int sd, ret; + mrb_value buf = mrb_nil_value(); + mrb_int maxlen; + + mrb_get_args(mrb, "i|S", &maxlen, &buf); + if (maxlen < 0) { return mrb_nil_value(); } + if (mrb_nil_p(buf)) { + buf = mrb_str_new(mrb, NULL, maxlen); + } + if (RSTRING_LEN(buf) != maxlen) { + buf = mrb_str_resize(mrb, buf, maxlen); + } + sd = socket_fd(mrb, self); - bytes_read = 0; - - /* Behavior of positive integer argument: read until length bytes have been - * read, or until the socket has closed. */ - if (read_len > 0) { - int n = 0; - int max_read_len = BUF_LEN; - int keep_reading = 1; - while (keep_reading) { - if (max_read_len > (read_len - bytes_read)) - max_read_len = read_len - bytes_read; - n = recv(sd, buf, max_read_len, 0); - - if (n == SOCKET_ERROR) { - mrb_sys_fail(mrb, "recv"); - } else if (n == 0) { - keep_reading = 0; + ret = recv(sd, RSTRING_PTR(buf), maxlen, 0); + + switch (ret) { + case 0: /* EOF */ + if (maxlen == 0) { + buf = mrb_str_new_cstr(mrb, ""); } else { - mrb_str_cat(mrb, str, buf, n); - bytes_read += n; - if (bytes_read >= read_len) - keep_reading = 0; + mrb_raise(mrb, E_EOF_ERROR, "sysread failed: End of File"); } - } - } - /* Behavior of nil/default argument: read until socket has closed */ - else { - int keep_reading = 1; - while (keep_reading) { - bytes_read = recv(sd, buf, BUF_LEN, 0); - if (bytes_read == SOCKET_ERROR) { - mrb_sys_fail(mrb, "recv"); - } else if (bytes_read == 0) { - keep_reading = 0; - } else { - mrb_str_cat(mrb, str, buf, bytes_read); + break; + case SOCKET_ERROR: /* Error */ + mrb_sys_fail(mrb, "recv"); + break; + default: + if (RSTRING_LEN(buf) != ret) { + buf = mrb_str_resize(mrb, buf, ret); } - } + break; } - return str; -#undef BUF_LEN + return buf; +} + +static mrb_value +mrb_win32_basicsocket_sysseek(mrb_state *mrb, mrb_value self) +{ + mrb_raise(mrb, E_NOTIMP_ERROR, "sysseek not implemented for windows sockets"); + return mrb_nil_value(); } static mrb_value -mrb_win32_basicsocket_write(mrb_state *mrb, mrb_value self) +mrb_win32_basicsocket_syswrite(mrb_state *mrb, mrb_value self) { int n; SOCKET sd; @@ -842,8 +813,9 @@ mrb_mruby_socket_gem_init(mrb_state* mrb) /* Windows IO Method Overrides on BasicSocket */ #ifdef _WIN32 mrb_define_method(mrb, bsock, "close", mrb_win32_basicsocket_close, MRB_ARGS_NONE()); - mrb_define_method(mrb, bsock, "read", mrb_win32_basicsocket_read, MRB_ARGS_OPT(1)); - mrb_define_method(mrb, bsock, "write", mrb_win32_basicsocket_write, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, bsock, "sysread", mrb_win32_basicsocket_sysread, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); + mrb_define_method(mrb, bsock, "sysseek", mrb_win32_basicsocket_sysseek, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, bsock, "syswrite", mrb_win32_basicsocket_syswrite, MRB_ARGS_REQ(1)); #endif constants = mrb_define_module_under(mrb, sock, "Constants"); -- cgit v1.2.3 From 02daa2509dac1b1631f06842b258cd08b31e3a63 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 8 Sep 2015 10:44:08 +0900 Subject: try to fix failure on travis. --- test/addrinfo.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/addrinfo.rb b/test/addrinfo.rb index 8720eb0ae..085498cfd 100644 --- a/test/addrinfo.rb +++ b/test/addrinfo.rb @@ -19,10 +19,10 @@ end assert('Addrinfo.foreach') do # assume Addrinfo.getaddrinfo works well - a = Addrinfo.getaddrinfo("localhost", "domain") + a = Addrinfo.getaddrinfo("localhost.", "domain") b = [] - Addrinfo.foreach("localhost", "domain") { |ai| b << ai } - assert_equal(a.size, b.size) + Addrinfo.foreach("localhost.", "domain") { |ai| b << ai } + assert_equal(a.sort, b.sort) end assert('Addrinfo.ip') do -- cgit v1.2.3 From ecd7ef5924199439a2d872f8779374fc39efc93c Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 8 Sep 2015 11:57:08 +0900 Subject: Revert "try to fix failure on travis." This reverts commit 02daa2509dac1b1631f06842b258cd08b31e3a63. --- test/addrinfo.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/addrinfo.rb b/test/addrinfo.rb index 085498cfd..8720eb0ae 100644 --- a/test/addrinfo.rb +++ b/test/addrinfo.rb @@ -19,10 +19,10 @@ end assert('Addrinfo.foreach') do # assume Addrinfo.getaddrinfo works well - a = Addrinfo.getaddrinfo("localhost.", "domain") + a = Addrinfo.getaddrinfo("localhost", "domain") b = [] - Addrinfo.foreach("localhost.", "domain") { |ai| b << ai } - assert_equal(a.sort, b.sort) + Addrinfo.foreach("localhost", "domain") { |ai| b << ai } + assert_equal(a.size, b.size) end assert('Addrinfo.ip') do -- cgit v1.2.3 From f3016752bdc19f0f816a273b75a266ef4701eca2 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 8 Sep 2015 13:23:46 +0900 Subject: build in container-based environment. --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index ffe227284..6476289bd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,2 +1,4 @@ +language: c +sudo: false script: - "ruby run_test.rb all test" -- cgit v1.2.3 From 625995424c9cf32b339a4a7d167a0c5fdd11ac00 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 8 Sep 2015 13:25:05 +0900 Subject: To run test, we need "conf.enable_test" in build_config.rb. --- run_test.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/run_test.rb b/run_test.rb index 77e90a467..87a222f16 100644 --- a/run_test.rb +++ b/run_test.rb @@ -24,4 +24,5 @@ MRuby::Build.new do |conf| conf.gem :git => 'https://github.com/iij/mruby-pack.git' conf.gem File.expand_path(File.dirname(__FILE__)) + conf.enable_test end -- cgit v1.2.3 From c8a2c636e0d760458c22916a6ad1c549424be3a7 Mon Sep 17 00:00:00 2001 From: Zachary Scott Date: Mon, 18 Jan 2016 15:27:32 +0900 Subject: Fix warning: variable 'udpsock' set but not used --- src/socket.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/socket.c b/src/socket.c index aee593cc9..0a4efcd87 100644 --- a/src/socket.c +++ b/src/socket.c @@ -734,7 +734,7 @@ mrb_win32_basicsocket_syswrite(mrb_state *mrb, mrb_value self) void mrb_mruby_socket_gem_init(mrb_state* mrb) { - struct RClass *io, *ai, *sock, *bsock, *ipsock, *tcpsock, *udpsock; + struct RClass *io, *ai, *sock, *bsock, *ipsock, *tcpsock; struct RClass *constants; #ifdef _WIN32 @@ -781,7 +781,7 @@ mrb_mruby_socket_gem_init(mrb_state* mrb) mrb_define_class_method(mrb, tcpsock, "_allocate", mrb_tcpsocket_allocate, MRB_ARGS_NONE()); mrb_define_class(mrb, "TCPServer", tcpsock); - udpsock = mrb_define_class(mrb, "UDPSocket", ipsock); + mrb_define_class(mrb, "UDPSocket", ipsock); //#recvfrom_nonblock sock = mrb_define_class(mrb, "Socket", bsock); -- cgit v1.2.3 From bdc118304c6076f1e338201d4c2b410f21894f93 Mon Sep 17 00:00:00 2001 From: Zachary Scott Date: Mon, 18 Jan 2016 15:34:26 +0900 Subject: Port inet_ntop and inet_pton for WIN32 Without these functions, compilation fails on MinGW --- src/socket.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/socket.c b/src/socket.c index aee593cc9..61409db9b 100644 --- a/src/socket.c +++ b/src/socket.c @@ -41,6 +41,59 @@ #define mrb_cptr_p(o) mrb_voidp_p(o) #endif +#ifdef _WIN32 +const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt) +{ + if (af == AF_INET) + { + struct sockaddr_in in; + memset(&in, 0, sizeof(in)); + in.sin_family = AF_INET; + memcpy(&in.sin_addr, src, sizeof(struct in_addr)); + getnameinfo((struct sockaddr *)&in, sizeof(struct + sockaddr_in), dst, cnt, NULL, 0, NI_NUMERICHOST); + return dst; + } + else if (af == AF_INET6) + { + struct sockaddr_in6 in; + memset(&in, 0, sizeof(in)); + in.sin6_family = AF_INET6; + memcpy(&in.sin6_addr, src, sizeof(struct in_addr6)); + getnameinfo((struct sockaddr *)&in, sizeof(struct + sockaddr_in6), dst, cnt, NULL, 0, NI_NUMERICHOST); + return dst; + } + return NULL; +} + +int inet_pton(int af, const char *src, void *dst) +{ + struct addrinfo hints, *res, *ressave; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = af; + + if (getaddrinfo(src, NULL, &hints, &res) != 0) + { + printf("Couldn't resolve host %s\n", src); + return -1; + } + + ressave = res; + + while (res) + { + memcpy(dst, res->ai_addr, res->ai_addrlen); + res = res->ai_next; + } + + freeaddrinfo(ressave); + return 0; +} + +#endif + static mrb_value mrb_addrinfo_getaddrinfo(mrb_state *mrb, mrb_value klass) { -- cgit v1.2.3 From be2ec608e2bdba4aa918806d558e171ff0e3c7c4 Mon Sep 17 00:00:00 2001 From: rmalizia44 Date: Thu, 28 Jan 2016 03:28:05 -0200 Subject: Add _WIN32_WINNT definition to Avoid Windows Compilation Errors the line #define _WIN32_WINNT 0x0501 will cause ws2tcpip.h to implement the missing functions freeaddrinfo, getaddrinfo and getnameinfo on windows --- src/socket.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/socket.c b/src/socket.c index 142562de2..e28d7cd5d 100644 --- a/src/socket.c +++ b/src/socket.c @@ -5,6 +5,8 @@ */ #ifdef _WIN32 + #define _WIN32_WINNT 0x0501 + #include #include #include -- cgit v1.2.3 From 2a80cccf30bd43ddc9a64188ada1593d1bd57d68 Mon Sep 17 00:00:00 2001 From: rhykw Date: Mon, 23 May 2016 21:44:34 +0900 Subject: TCPServer use SO_REUSEADDR --- mrblib/socket.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/mrblib/socket.rb b/mrblib/socket.rb index 2ff144080..d5dbda806 100644 --- a/mrblib/socket.rb +++ b/mrblib/socket.rb @@ -262,6 +262,7 @@ class TCPServer ai = Addrinfo.getaddrinfo(host, service, nil, nil, nil, Socket::AI_PASSIVE)[0] @init_with_fd = true super(Socket._socket(ai.afamily, Socket::SOCK_STREAM, 0), "r+") + self.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true) Socket._bind(self.fileno, ai.to_sockaddr) listen(5) self -- cgit v1.2.3 From 4f6703203b73c2dcec29b1bd851ae938177fee02 Mon Sep 17 00:00:00 2001 From: rhykw Date: Sat, 28 May 2016 09:33:53 +0900 Subject: TCPServer use SO_REUSEADDR if possible --- mrblib/socket.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mrblib/socket.rb b/mrblib/socket.rb index d5dbda806..a32a3334d 100644 --- a/mrblib/socket.rb +++ b/mrblib/socket.rb @@ -262,7 +262,9 @@ class TCPServer ai = Addrinfo.getaddrinfo(host, service, nil, nil, nil, Socket::AI_PASSIVE)[0] @init_with_fd = true super(Socket._socket(ai.afamily, Socket::SOCK_STREAM, 0), "r+") - self.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true) + if Socket.const_defined?(:SO_REUSEADDR) + self.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true) + end Socket._bind(self.fileno, ai.to_sockaddr) listen(5) self -- cgit v1.2.3 From 3dad125a1cd93e70a1762e9c6a1d5e01554ad71c Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Wed, 8 Feb 2017 19:04:11 +0900 Subject: TCPSocket.new supports "local_host" and "local_service". --- mrblib/socket.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mrblib/socket.rb b/mrblib/socket.rb index a32a3334d..f7d4ce3a8 100644 --- a/mrblib/socket.rb +++ b/mrblib/socket.rb @@ -236,6 +236,12 @@ class TCPSocket Addrinfo.foreach(host, service) { |ai| begin s = Socket._socket(ai.afamily, Socket::SOCK_STREAM, 0) + if local_host or local_service + local_host ||= (ai.afamily == Socket::AF_INET) ? "0.0.0.0" : "::" + local_service ||= "0" + bi = Addrinfo.getaddrinfo(local_host, local_service, ai.afamily, ai.socktype)[0] + Socket._bind(s, bi.to_sockaddr) + end Socket._connect(s, ai.to_sockaddr) super(s, "r+") return -- cgit v1.2.3 From 81a0dcdb7a83f618e572d0dd7be3e99587d1a84d Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 13 Jun 2017 12:13:04 +0900 Subject: sizeof(optval) must be 1 for IP_MULTICAST_TTL & IP_MULTICAST_LOOP. fixes #34. --- src/socket.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/socket.c b/src/socket.c index e28d7cd5d..44534827a 100644 --- a/src/socket.c +++ b/src/socket.c @@ -433,8 +433,13 @@ mrb_basicsocket_setsockopt(mrb_state *mrb, mrb_value self) mrb_int i = mrb_test(optval) ? 1 : 0; optval = mrb_str_new(mrb, (char *)&i, sizeof(i)); } else if (mrb_fixnum_p(optval)) { - mrb_int i = mrb_fixnum(optval); - optval = mrb_str_new(mrb, (char *)&i, sizeof(i)); + if (optname == IP_MULTICAST_TTL || optname == IP_MULTICAST_LOOP) { + char uc = mrb_fixnum(optval); + optval = mrb_str_new(mrb, &uc, sizeof(uc)); + } else { + mrb_int i = mrb_fixnum(optval); + optval = mrb_str_new(mrb, (char *)&i, sizeof(i)); + } } else { mrb_raise(mrb, E_ARGUMENT_ERROR, "optval should be true, false, an integer, or a string"); } -- cgit v1.2.3 From 5b6e4eda2a008e7c075c3b0b1bf26c769cd0b2fa Mon Sep 17 00:00:00 2001 From: Uchio KONDO Date: Mon, 4 Sep 2017 16:33:57 +0900 Subject: Fix type int to mrb_int - mruby's default int size is changed after: https://github.com/mruby/mruby/commit/f0f4a1088a270e339407a24ffe8be748f4764fc2 - implicit cast causes some errors --- src/socket.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/socket.c b/src/socket.c index 44534827a..19cfc509c 100644 --- a/src/socket.c +++ b/src/socket.c @@ -611,10 +611,10 @@ mrb_socket_connect(mrb_state *mrb, mrb_value klass) static mrb_value mrb_socket_listen(mrb_state *mrb, mrb_value klass) { - int backlog, s; + mrb_int backlog, s; mrb_get_args(mrb, "ii", &s, &backlog); - if (listen(s, backlog) == -1) { + if (listen((int)s, (int)backlog) == -1) { mrb_sys_fail(mrb, "listen"); } return mrb_nil_value(); -- cgit v1.2.3 From a809d42f5aaf093a5667e505c512adadb74ce34a Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 12 Sep 2017 11:43:21 +0900 Subject: remove whitespaces at the end of line. --- README.md | 24 ++++++++++++------------ mrbgem.rake | 2 +- mrblib/socket.rb | 2 +- src/socket.c | 38 +++++++++++++++++++------------------- 4 files changed, 33 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 5f2227e85..7428cfa6c 100644 --- a/README.md +++ b/README.md @@ -36,20 +36,20 @@ Date: Tue, 21 May 2013 04:31:30 GMT Copyright (c) 2013 Internet Initiative Japan Inc. -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/mrbgem.rake b/mrbgem.rake index ef91bdfcb..7ae914925 100644 --- a/mrbgem.rake +++ b/mrbgem.rake @@ -3,7 +3,7 @@ MRuby::Gem::Specification.new('mruby-socket') do |spec| spec.authors = 'Internet Initiative Japan' spec.cc.include_paths << "#{build.root}/src" - + # If Windows, use winsock if ( /mswin|mingw|win32/ =~ RUBY_PLATFORM ) then spec.linker.libraries << "wsock32" diff --git a/mrblib/socket.rb b/mrblib/socket.rb index f7d4ce3a8..53c20e3cc 100644 --- a/mrblib/socket.rb +++ b/mrblib/socket.rb @@ -154,7 +154,7 @@ class Addrinfo [ s, port.to_i, addr, addr ] end - def to_sockaddr + def to_sockaddr @sockaddr end diff --git a/src/socket.c b/src/socket.c index 19cfc509c..3f4ef8a4c 100644 --- a/src/socket.c +++ b/src/socket.c @@ -6,7 +6,7 @@ #ifdef _WIN32 #define _WIN32_WINNT 0x0501 - + #include #include #include @@ -260,13 +260,13 @@ socket_family(int s) static mrb_value mrb_basicsocket_getpeereid(mrb_state *mrb, mrb_value self) -{ +{ #ifdef HAVE_GETPEEREID mrb_value ary; gid_t egid; uid_t euid; int s; - + s = socket_fd(mrb, self); if (getpeereid(s, &euid, &egid) != 0) mrb_sys_fail(mrb, "getpeereid"); @@ -283,10 +283,10 @@ mrb_basicsocket_getpeereid(mrb_state *mrb, mrb_value self) static mrb_value mrb_basicsocket_getpeername(mrb_state *mrb, mrb_value self) -{ +{ struct sockaddr_storage ss; socklen_t salen; - + salen = sizeof(ss); if (getpeername(socket_fd(mrb, self), (struct sockaddr *)&ss, &salen) != 0) mrb_sys_fail(mrb, "getpeername"); @@ -296,10 +296,10 @@ mrb_basicsocket_getpeername(mrb_state *mrb, mrb_value self) static mrb_value mrb_basicsocket_getsockname(mrb_state *mrb, mrb_value self) -{ +{ struct sockaddr_storage ss; socklen_t salen; - + salen = sizeof(ss); if (getsockname(socket_fd(mrb, self), (struct sockaddr *)&ss, &salen) != 0) mrb_sys_fail(mrb, "getsockname"); @@ -309,7 +309,7 @@ mrb_basicsocket_getsockname(mrb_state *mrb, mrb_value self) static mrb_value mrb_basicsocket_getsockopt(mrb_state *mrb, mrb_value self) -{ +{ char opt[8]; int s; mrb_int family, level, optname; @@ -329,7 +329,7 @@ mrb_basicsocket_getsockopt(mrb_state *mrb, mrb_value self) static mrb_value mrb_basicsocket_recv(mrb_state *mrb, mrb_value self) -{ +{ int n; mrb_int maxlen, flags = 0; mrb_value buf; @@ -345,7 +345,7 @@ mrb_basicsocket_recv(mrb_state *mrb, mrb_value self) static mrb_value mrb_basicsocket_recvfrom(mrb_state *mrb, mrb_value self) -{ +{ int n; mrb_int maxlen, flags = 0; mrb_value ary, buf, sa; @@ -368,7 +368,7 @@ mrb_basicsocket_recvfrom(mrb_state *mrb, mrb_value self) static mrb_value mrb_basicsocket_send(mrb_state *mrb, mrb_value self) -{ +{ int n; mrb_int flags; mrb_value dest, mesg; @@ -387,7 +387,7 @@ mrb_basicsocket_send(mrb_state *mrb, mrb_value self) static mrb_value mrb_basicsocket_setnonblock(mrb_state *mrb, mrb_value self) -{ +{ int fd, flags; mrb_value bool; #ifdef _WIN32 @@ -416,7 +416,7 @@ mrb_basicsocket_setnonblock(mrb_state *mrb, mrb_value self) static mrb_value mrb_basicsocket_setsockopt(mrb_state *mrb, mrb_value self) -{ +{ int argc, s; mrb_int level = 0, optname; mrb_value optval, so; @@ -461,7 +461,7 @@ mrb_basicsocket_setsockopt(mrb_state *mrb, mrb_value self) static mrb_value mrb_basicsocket_shutdown(mrb_state *mrb, mrb_value self) -{ +{ mrb_int how = SHUT_RDWR; mrb_get_args(mrb, "|i", &how); @@ -472,7 +472,7 @@ mrb_basicsocket_shutdown(mrb_state *mrb, mrb_value self) static mrb_value mrb_ipsocket_ntop(mrb_state *mrb, mrb_value klass) -{ +{ mrb_int af, n; char *addr, buf[50]; @@ -486,7 +486,7 @@ mrb_ipsocket_ntop(mrb_state *mrb, mrb_value klass) static mrb_value mrb_ipsocket_pton(mrb_state *mrb, mrb_value klass) -{ +{ mrb_int af, n; char *bp, buf[50]; @@ -516,7 +516,7 @@ invalid: static mrb_value mrb_ipsocket_recvfrom(mrb_state *mrb, mrb_value self) -{ +{ struct sockaddr_storage ss; socklen_t socklen; mrb_value a, buf, pair; @@ -546,7 +546,7 @@ mrb_socket_gethostname(mrb_state *mrb, mrb_value cls) { mrb_value buf; size_t bufsize; - + #ifdef HOST_NAME_MAX bufsize = HOST_NAME_MAX + 1; #else @@ -647,7 +647,7 @@ mrb_socket_sockaddr_un(mrb_state *mrb, mrb_value klass) #else struct sockaddr_un *sunp; mrb_value path, s; - + mrb_get_args(mrb, "S", &path); if (RSTRING_LEN(path) > sizeof(sunp->sun_path) - 1) { mrb_raisef(mrb, E_ARGUMENT_ERROR, "too long unix socket path (max: %ubytes)", (unsigned int)sizeof(sunp->sun_path) - 1); -- cgit v1.2.3 From ab54185005ec87fe4f5b10df95ad29659884141b Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 12 Sep 2017 12:32:12 +0900 Subject: receiver variables must be "mrb_int" for mrb_get_args("i"). Otherwise, it can cause a segfault on the platforms where the size of "int" and "mrb_int" differs. --- src/socket.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/socket.c b/src/socket.c index 3f4ef8a4c..758d3a311 100644 --- a/src/socket.c +++ b/src/socket.c @@ -586,10 +586,10 @@ static mrb_value mrb_socket_bind(mrb_state *mrb, mrb_value klass) { mrb_value sastr; - int s; + mrb_int s; mrb_get_args(mrb, "iS", &s, &sastr); - if (bind(s, (struct sockaddr *)RSTRING_PTR(sastr), (socklen_t)RSTRING_LEN(sastr)) == -1) { + if (bind((int)s, (struct sockaddr *)RSTRING_PTR(sastr), (socklen_t)RSTRING_LEN(sastr)) == -1) { mrb_sys_fail(mrb, "bind"); } return mrb_nil_value(); @@ -599,10 +599,10 @@ static mrb_value mrb_socket_connect(mrb_state *mrb, mrb_value klass) { mrb_value sastr; - int s; + mrb_int s; mrb_get_args(mrb, "iS", &s, &sastr); - if (connect(s, (struct sockaddr *)RSTRING_PTR(sastr), (socklen_t)RSTRING_LEN(sastr)) == -1) { + if (connect((int)s, (struct sockaddr *)RSTRING_PTR(sastr), (socklen_t)RSTRING_LEN(sastr)) == -1) { mrb_sys_fail(mrb, "connect"); } return mrb_nil_value(); -- cgit v1.2.3