Add 'mrbgems/mruby-socket/' from commit 'ab54185005ec87fe4f5b10df95ad29659884141b'

git-subtree-dir: mrbgems/mruby-socket
git-subtree-mainline: d75266dd1b
git-subtree-split: ab54185005
This commit is contained in:
Yukihiro "Matz" Matsumoto
2017-12-07 18:11:13 +09:00
17 changed files with 2600 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
language: c
sudo: false
script:
- "ruby run_test.rb all test"
+55
View File
@@ -0,0 +1,55 @@
mruby-socket
============
"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
- [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...
## TODO
- add missing methods
- write more tests
- fix possible descriptor leakage (see XXX comments)
- `UNIXSocket#recv_io` `UNIXSocket#send_io`
## 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.
+16
View File
@@ -0,0 +1,16 @@
MRuby::Gem::Specification.new('mruby-socket') do |spec|
spec.license = 'MIT'
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')
# spec.add_dependency('mruby-mtest')
end
+620
View File
@@ -0,0 +1,620 @@
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.getaddrinfo(host, port, nil, Socket::SOCK_STREAM, Socket::IPPROTO_TCP)[0]
end
def self.udp(host, port)
Addrinfo.getaddrinfo(host, port, nil, Socket::SOCK_DGRAM, Socket::IPPROTO_UDP)[0]
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 or (@socktype == Socket::SOCK_STREAM and @protocol == 0)
proto = 'TCP'
elsif @protocol == Socket::IPPROTO_UDP or (@socktype == Socket::SOCK_DGRAM and @protocol == 0)
proto = 'UDP'
else
proto = '???'
end
"#<Addrinfo: #{inspect_sockaddr} #{proto}>"
else
"#<Addrinfo: #{self.unix_path} SOCK_STREAM>"
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_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
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 self.for_fd(fd)
super(fd, "r+")
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.getaddress(host)
Addrinfo.ip(host).ip_address
end
def addr
Addrinfo.new(self.getsockname)._to_array
end
def peeraddr
Addrinfo.new(self.getpeername)._to_array
end
def recvfrom(maxlen, flags=0)
msg, sa = _recvfrom(maxlen, flags)
[ msg, Addrinfo.new(sa)._to_array ]
end
end
class TCPSocket
def initialize(host, service, local_host=nil, local_service=nil)
if @init_with_fd
super(host, service)
else
s = nil
e = SocketError
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
rescue => e0
e = e0
end
}
raise e
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+")
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
end
def accept
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
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)
super(Socket._socket(af, Socket::SOCK_DGRAM, 0), "r+")
@af = af
self
end
def bind(host, port)
Socket._bind(self.fileno, _sockaddr_in(port, host))
0
end
def connect(host, port)
Socket._connect(self.fileno, _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, _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
def initialize(domain, type, protocol=0)
super(Socket._socket(domain, type, protocol), "r+")
end
#def self.accept_loop
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
def self.open(*args)
new(args)
end
def self.sockaddr_in(port, host)
ai = Addrinfo.getaddrinfo(host, port, nil, Socket::SOCK_DGRAM)[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._connect(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)
socktype = self.getsockopt(Socket::SOL_SOCKET, Socket::SO_TYPE).int
[ msg, Addrinfo.new(sa, Socket::PF_UNSPEC, socktype) ]
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 < BasicSocket
def initialize(path, &block)
if self.is_a? UNIXServer
super(path, "r")
else
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
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)
path = (sa.size > 0) ? Addrinfo.new(sa).unix_path : ""
[ msg, [ "AF_UNIX", path ] ]
end
#def send_io
end
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 = self.sysaccept
begin
sock = UNIXSocket.for_fd(fd)
rescue
IO._sysclose(fd) rescue nil
end
sock
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
"#<Socket::Option: family:#{@family} level:#{@level} optname:#{@optname} #{@data.inspect}>"
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
+28
View File
@@ -0,0 +1,28 @@
#!/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 :git => 'https://github.com/iij/mruby-pack.git'
conf.gem File.expand_path(File.dirname(__FILE__))
conf.enable_test
end
+453
View File
@@ -0,0 +1,453 @@
#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 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 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
#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
#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
#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_NOSIGPIPE
define_const(SO_NOSIGPIPE);
#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
#ifdef TCP_CONGCTL
define_const(TCP_CONGCTL);
#endif
#ifdef TCP_CONGESTION
define_const(TCP_CONGESTION);
#endif
#ifdef TCP_CORK
define_const(TCP_CORK);
#endif
#ifdef TCP_DEFER_ACCEPT
define_const(TCP_DEFER_ACCEPT);
#endif
#ifdef TCP_INFO
define_const(TCP_INFO);
#endif
#ifdef TCP_KEEPCNT
define_const(TCP_KEEPCNT);
#endif
#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_MAXSEG
define_const(TCP_MAXSEG);
#endif
#ifdef TCP_MD5SIG
define_const(TCP_MD5SIG);
#endif
#ifdef TCP_NODELAY
define_const(TCP_NODELAY);
#endif
#ifdef TCP_QUICKACK
define_const(TCP_QUICKACK);
#endif
#ifdef TCP_SACK_ENABLE
define_const(TCP_SACK_ENABLE);
#endif
#ifdef TCP_SYNCNT
define_const(TCP_SYNCNT);
#endif
#ifdef TCP_WINDOW_CLAMP
define_const(TCP_WINDOW_CLAMP);
#endif
+163
View File
@@ -0,0 +1,163 @@
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
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
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
IPPROTO_FRAGMENT
IPPROTO_ICMP
IPPROTO_ICMPV6
IPPROTO_IP
IPPROTO_IPV6
IPPROTO_NONE
IPPROTO_RAW
IPPROTO_ROUTING
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
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_NOSIGPIPE
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
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
+17
View File
@@ -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 <<CODE
#ifdef #{name}
define_const(#{name});
#endif
CODE
}
+902
View File
@@ -0,0 +1,902 @@
/*
** socket.c - Socket module
**
** See Copyright Notice in mruby.h
*/
#ifdef _WIN32
#define _WIN32_WINNT 0x0501
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#define SHUT_RDWR SD_BOTH
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <netdb.h>
#include <unistd.h>
#endif
#include <stddef.h>
#include <string.h>
#include "mruby.h"
#include "mruby/array.h"
#include "mruby/class.h"
#include "mruby/data.h"
#include "mruby/string.h"
#include "mruby/variable.h"
#include "error.h"
#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
#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)
{
struct addrinfo hints, *res0, *res;
mrb_value ai, ary, family, lastai, nodename, protocol, 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! */
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(service)) {
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_lit(mrb, "_lastai"));
if (mrb_cptr_p(lastai)) {
freeaddrinfo(mrb_cptr(lastai));
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_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);
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_lit(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_lit(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;
}
#ifndef _WIN32
static mrb_value
mrb_addrinfo_unix_path(mrb_state *mrb, mrb_value self)
{
mrb_value sastr;
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);
}
#endif
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)
{
#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");
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;
#else
mrb_raise(mrb, E_RUNTIME_ERROR, "getpeereid is not avaialble on this system");
return mrb_nil_value();
#endif
}
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)
{
char opt[8];
int 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_lit(mrb, "Option"));
family = socket_family(s);
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);
}
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 {
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;
#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");
if (mrb_test(bool))
flags |= O_NONBLOCK;
else
flags &= ~O_NONBLOCK;
if (fcntl(fd, F_SETFL, flags) == -1)
mrb_sys_fail(mrb, "fcntl");
#endif
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)) {
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");
}
} 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_socket_gethostname(mrb_state *mrb, mrb_value cls)
{
mrb_value buf;
size_t bufsize;
#ifdef HOST_NAME_MAX
bufsize = HOST_NAME_MAX + 1;
#else
bufsize = 256;
#endif
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;
}
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;
mrb_int s;
mrb_get_args(mrb, "iS", &s, &sastr);
if (bind((int)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;
mrb_int s;
mrb_get_args(mrb, "iS", &s, &sastr);
if (connect((int)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)
{
mrb_int backlog, s;
mrb_get_args(mrb, "ii", &s, &backlog);
if (listen((int)s, (int)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);
#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);
}
static mrb_value
mrb_socket_sockaddr_un(mrb_state *mrb, mrb_value klass)
{
#ifdef _WIN32
mrb_raise(mrb, E_NOTIMP_ERROR, "sockaddr_un unsupported on Windows");
return mrb_nil_value();
#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);
}
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;
#endif
}
static mrb_value
mrb_socket_socketpair(mrb_state *mrb, mrb_value klass)
{
#ifdef _WIN32
mrb_raise(mrb, E_NOTIMP_ERROR, "socketpair unsupported on Windows");
return mrb_nil_value();
#else
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;
#endif
}
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);
}
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));
}
/* 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_raise(mrb, E_SOCKET_ERROR, "closesocket unsuccessful");
return mrb_nil_value();
}
#define E_EOF_ERROR (mrb_class_get(mrb, "EOFError"))
static mrb_value
mrb_win32_basicsocket_sysread(mrb_state *mrb, mrb_value self)
{
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);
ret = recv(sd, RSTRING_PTR(buf), maxlen, 0);
switch (ret) {
case 0: /* EOF */
if (maxlen == 0) {
buf = mrb_str_new_cstr(mrb, "");
} else {
mrb_raise(mrb, E_EOF_ERROR, "sysread failed: End of File");
}
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 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_syswrite(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, "send");
return mrb_fixnum_value(n);
}
#endif
void
mrb_mruby_socket_gem_init(mrb_state* mrb)
{
struct RClass *io, *ai, *sock, *bsock, *ipsock, *tcpsock;
struct RClass *constants;
#ifdef _WIN32
WSADATA wsaData;
int result;
result = WSAStartup(MAKEWORD(2,2), &wsaData);
if (result != NO_ERROR)
mrb_raise(mrb, E_RUNTIME_ERROR, "WSAStartup failed");
#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");
bsock = mrb_define_class(mrb, "BasicSocket", io);
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, MRB_ARGS_REQ(2)|MRB_ARGS_OPT(1));
// #sendmsg
// #sendmsg_nonblock
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, 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, "_allocate", mrb_tcpsocket_allocate, MRB_ARGS_NONE());
mrb_define_class(mrb, "TCPServer", tcpsock);
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, 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());
#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));
//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());
/* 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, "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");
#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_lit(mrb, "_lastai"));
if (mrb_cptr_p(ai)) {
freeaddrinfo(mrb_cptr(ai));
}
#ifdef _WIN32
WSACleanup();
#endif
}
+89
View File
@@ -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
+17
View File
@@ -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
+40
View File
@@ -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
+34
View File
@@ -0,0 +1,34 @@
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
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
+16
View File
@@ -0,0 +1,16 @@
#include <stdio.h>
#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());
}
+4
View File
@@ -0,0 +1,4 @@
#assert('TCPSocket.gethostbyname') do
#assert('TCPSocket.new') do
#assert('TCPSocket#close') do
#assert('TCPSocket#write') do
+16
View File
@@ -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
+126
View File
@@ -0,0 +1,126 @@
def unixserver_test_block
path = SocketTest.tmppath
File.unlink path rescue nil
begin
result = yield path
ensure
File.unlink path 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