source: EcnlProtoTool/trunk/mrbgems/mruby-socket/mrblib/socket.rb@ 279

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

ファイルを追加、更新。

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-ruby
File size: 12.3 KB
Line 
1class Addrinfo
2 def initialize(sockaddr, family=Socket::PF_UNSPEC, socktype=0, protocol=0)
3 @hostname = nil
4 if sockaddr.is_a? Array
5 sary = sockaddr
6 if sary[0] == 'AF_INET' || sary[0] == 'AF_INET6'
7 @sockaddr = Socket.sockaddr_in(sary[1], sary[3])
8 @hostname = sary[2]
9 elsif sary[0] == 'AF_UNIX'
10 @sockaddr = Socket.sockaddr_un(sary[1])
11 end
12 else
13 @sockaddr = sockaddr.dup
14 end
15 if family == Socket::PF_UNSPEC or family == nil
16 @family = Socket._sockaddr_family(@sockaddr)
17 else
18 @family = family
19 end
20 @socktype = socktype
21 @protocol = protocol
22 @canonname = nil
23 end
24
25 def self.foreach(nodename, service, family=nil, socktype=nil, protocol=nil, flags=0, &block)
26 a = self.getaddrinfo(nodename, service, family, socktype, protocol, flags)
27 a.each { |ai| block.call(ai) }
28 a
29 end
30
31 def self.ip(host)
32 Addrinfo.new(Socket.sockaddr_in(0, host))
33 end
34
35 def self.tcp(host, port)
36 Addrinfo.getaddrinfo(host, port, nil, Socket::SOCK_STREAM, Socket::IPPROTO_TCP)[0]
37 end
38
39 def self.udp(host, port)
40 Addrinfo.getaddrinfo(host, port, nil, Socket::SOCK_DGRAM, Socket::IPPROTO_UDP)[0]
41 end
42
43 def self.unix(path, socktype=Socket::SOCK_STREAM)
44 Addrinfo.new(Socket.sockaddr_un(path), Socket::AF_UNIX, socktype)
45 end
46
47 def afamily
48 @family
49 end
50
51 #def bind
52
53 attr_reader :canonname
54
55 #def connect
56 #def connect_from
57 #def connect_to
58
59 #def family_addrinfo(host, port=nil)
60 #def getnameinfo(flags=0)
61 # Socket.getnameinfo
62 #end
63
64 def inspect
65 if ipv4? or ipv6?
66 if @protocol == Socket::IPPROTO_TCP or (@socktype == Socket::SOCK_STREAM and @protocol == 0)
67 proto = 'TCP'
68 elsif @protocol == Socket::IPPROTO_UDP or (@socktype == Socket::SOCK_DGRAM and @protocol == 0)
69 proto = 'UDP'
70 else
71 proto = '???'
72 end
73 "#<Addrinfo: #{inspect_sockaddr} #{proto}>"
74 else
75 "#<Addrinfo: #{self.unix_path} SOCK_STREAM>"
76 end
77 end
78
79 def inspect_sockaddr
80 if ipv4?
81 a, p = ip_unpack
82 "#{a}:#{p}"
83 elsif ipv6?
84 a, p = ip_unpack
85 "[#{a}]:#{p}"
86 elsif unix?
87 unix_path
88 else
89 '???'
90 end
91 end
92
93 def ip?
94 ipv4? or ipv6?
95 end
96
97 def ip_address
98 ip_unpack[0]
99 end
100
101 def ip_port
102 ip_unpack[1]
103 end
104
105 def ip_unpack
106 h, p = getnameinfo(Socket::NI_NUMERICHOST|Socket::NI_NUMERICSERV)
107 [ h, p.to_i ]
108 end
109
110 def ipv4?
111 @family == Socket::AF_INET
112 end
113
114 #def ipv4_loopback?
115 #def ipv4_multicast?
116 #def ipv4_private?
117
118 def ipv6?
119 @family == Socket::AF_INET6
120 end
121
122 #def ipv6_loopback?
123 #def ipv6_mc_global?
124 #def ipv6_mc_linklocal?
125 #def ipv6_mc_nodelocal?
126 #def ipv6_mc_orilocal?
127 #def ipv6_mc_sitelocal?
128 #def ipv6_multicast?
129 #def ipv6_to_ipv4
130 #def ipv6_unspecified
131 #def ipv6_v4compat?
132 #def ipv6_v4mapped?
133 #def listen(backlog=5)
134
135 def pfamily
136 @family
137 end
138
139 attr_reader :protocol
140 attr_reader :socktype
141
142 def _to_array
143 case @family
144 when Socket::AF_INET
145 s = "AF_INET"
146 when Socket::AF_INET6
147 s = "AF_INET6"
148 when Socket::AF_UNIX
149 s = "AF_UNIX"
150 else
151 s = "(unknown AF)"
152 end
153 addr, port = self.getnameinfo(Socket::NI_NUMERICHOST|Socket::NI_NUMERICSERV)
154 [ s, port.to_i, addr, addr ]
155 end
156
157 def to_sockaddr
158 @sockaddr
159 end
160
161 alias to_s to_sockaddr
162
163 def unix?
164 @family == Socket::AF_UNIX
165 end
166end
167
168class BasicSocket
169 @@do_not_reverse_lookup = true
170
171 def self.do_not_reverse_lookup
172 @@do_not_reverse_lookup
173 end
174
175 def self.do_not_reverse_lookup=(val)
176 @@do_not_reverse_lookup = val ? true : false
177 end
178
179 def initialize(*args)
180 super(*args)
181 @do_not_reverse_lookup = @@do_not_reverse_lookup
182 end
183
184 def self.for_fd(fd)
185 super(fd, "r+")
186 end
187
188 #def connect_address
189
190 def local_address
191 Addrinfo.new self.getsockname
192 end
193
194 def recv_nonblock(maxlen, flags=0)
195 begin
196 _setnonblock(true)
197 recv(maxlen, flags)
198 ensure
199 _setnonblock(false)
200 end
201 end
202
203 def remote_address
204 Addrinfo.new self.getpeername
205 end
206
207 attr_accessor :do_not_reverse_lookup
208end
209
210class IPSocket
211 def self.getaddress(host)
212 Addrinfo.ip(host).ip_address
213 end
214
215 def addr
216 Addrinfo.new(self.getsockname)._to_array
217 end
218
219 def peeraddr
220 Addrinfo.new(self.getpeername)._to_array
221 end
222
223 def recvfrom(maxlen, flags=0)
224 msg, sa = _recvfrom(maxlen, flags)
225 [ msg, Addrinfo.new(sa)._to_array ]
226 end
227end
228
229class TCPSocket
230 def initialize(host, service, local_host=nil, local_service=nil)
231 if @init_with_fd
232 super(host, service)
233 else
234 s = nil
235 e = SocketError
236 Addrinfo.foreach(host, service) { |ai|
237 begin
238 s = Socket._socket(ai.afamily, Socket::SOCK_STREAM, 0)
239 if local_host or local_service
240 local_host ||= (ai.afamily == Socket::AF_INET) ? "0.0.0.0" : "::"
241 local_service ||= "0"
242 bi = Addrinfo.getaddrinfo(local_host, local_service, ai.afamily, ai.socktype)[0]
243 Socket._bind(s, bi.to_sockaddr)
244 end
245 Socket._connect(s, ai.to_sockaddr)
246 super(s, "r+")
247 return
248 rescue => e0
249 e = e0
250 end
251 }
252 raise e
253 end
254 end
255
256 def self.new_with_prelude pre, *args
257 o = self._allocate
258 o.instance_eval(&pre)
259 o.initialize(*args)
260 o
261 end
262
263 #def self.gethostbyname(host)
264end
265
266class TCPServer
267 def initialize(host=nil, service)
268 ai = Addrinfo.getaddrinfo(host, service, nil, nil, nil, Socket::AI_PASSIVE)[0]
269 @init_with_fd = true
270 super(Socket._socket(ai.afamily, Socket::SOCK_STREAM, 0), "r+")
271 if Socket.const_defined?(:SO_REUSEADDR)
272 self.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true)
273 end
274 Socket._bind(self.fileno, ai.to_sockaddr)
275 listen(5)
276 self
277 end
278
279 def accept
280 fd = self.sysaccept
281 begin
282 proc = Proc.new { @init_with_fd = true }
283 TCPSocket.new_with_prelude(proc, fd, "r+")
284 rescue
285 IO._sysclose(fd) rescue nil
286 raise
287 end
288 end
289
290 def accept_nonblock
291 begin
292 self._setnonblock(true)
293 self.accept
294 ensure
295 self._setnonblock(false)
296 end
297 end
298
299 def listen(backlog)
300 Socket._listen(self.fileno, backlog)
301 0
302 end
303
304 def sysaccept
305 Socket._accept(self.fileno)[0]
306 end
307end
308
309class UDPSocket
310 def initialize(af=Socket::AF_INET)
311 super(Socket._socket(af, Socket::SOCK_DGRAM, 0), "r+")
312 @af = af
313 self
314 end
315
316 def bind(host, port)
317 Socket._bind(self.fileno, _sockaddr_in(port, host))
318 0
319 end
320
321 def connect(host, port)
322 Socket._connect(self.fileno, _sockaddr_in(port, host))
323 0
324 end
325
326 def recvfrom_nonblock(*args)
327 s = self
328 begin
329 self._setnonblock(true)
330 self.recvfrom(*args)
331 ensure
332 # XXX: self is a SystemcallException here! (should be bug)
333 s._setnonblock(false)
334 end
335 end
336
337 def send(mesg, flags, host=nil, port=nil)
338 if port
339 super(mesg, flags, _sockaddr_in(port, host))
340 elsif host
341 super(mesg, flags, host)
342 else
343 super(mesg, flags)
344 end
345 end
346
347 def _sockaddr_in(port, host)
348 ai = Addrinfo.getaddrinfo(host, port, @af, Socket::SOCK_DGRAM)[0]
349 ai.to_sockaddr
350 end
351end
352
353class Socket
354 def initialize(domain, type, protocol=0)
355 super(Socket._socket(domain, type, protocol), "r+")
356 end
357
358 #def self.accept_loop
359
360 def self.getaddrinfo(nodename, servname, family=nil, socktype=nil, protocol=nil, flags=0)
361 Addrinfo.getaddrinfo(nodename, servname, family, socktype, protocol, flags).map { |ai|
362 ary = ai._to_array
363 ary[2] = nodename
364 ary[4] = ai.afamily
365 ary[5] = ai.socktype
366 ary[6] = ai.protocol
367 ary
368 }
369 end
370
371 #def self.getnameinfo
372 #def self.ip_address_list
373
374 def self.open(*args)
375 new(args)
376 end
377
378 def self.sockaddr_in(port, host)
379 ai = Addrinfo.getaddrinfo(host, port, nil, Socket::SOCK_DGRAM)[0]
380 ai.to_sockaddr
381 end
382
383 #def self.tcp
384 #def self.tcp_server_loop
385 #def self.tcp_server_sockets
386 #def self.udp_server_loop
387 #def self.udp_server_loop_on
388 #def self.udp_server_recv
389 #def self.udp_server_sockets
390 #def self.unix(path)
391 #def self.unix_server_loop
392 #def self.unix_server_socket
393
394 def self.unpack_sockaddr_in(sa)
395 Addrinfo.new(sa).ip_unpack.reverse
396 end
397
398 def self.unpack_sockaddr_un(sa)
399 Addrinfo.new(sa).unix_path
400 end
401
402 class << self
403 alias pack_sockaddr_in sockaddr_in
404 alias pack_sockaddr_un sockaddr_un
405 alias pair socketpair
406 end
407
408 def accept
409 fd, addr = self.sysaccept
410 [ Socket.for_fd(fd), addr ]
411 end
412
413 def accept_nonblock
414 begin
415 self._setnonblock(true)
416 self.accept
417 ensure
418 self._setnonblock(false)
419 end
420 end
421
422 def bind(sockaddr)
423 sockaddr = sockaddr.to_sockaddr if sockaddr.is_a? Addrinfo
424 Socket._bind(self.fileno, sockaddr)
425 0
426 end
427
428 def connect(sockaddr)
429 sockaddr = sockaddr.to_sockaddr if sockaddr.is_a? Addrinfo
430 Socket._connect(self.fileno, sockaddr)
431 0
432 end
433
434 def connect_nonblock(sockaddr)
435 begin
436 self._setnonblock(true)
437 self.connect(sockaddr)
438 ensure
439 self._setnonblock(false)
440 end
441 end
442
443 #def ipv6only!
444
445 def listen(backlog)
446 Socket._listen(self.fileno, backlog)
447 0
448 end
449
450 def recvfrom(maxlen, flags=0)
451 msg, sa = _recvfrom(maxlen, flags)
452 socktype = self.getsockopt(Socket::SOL_SOCKET, Socket::SO_TYPE).int
453 [ msg, Addrinfo.new(sa, Socket::PF_UNSPEC, socktype) ]
454 end
455
456 def recvfrom_nonblock(*args)
457 begin
458 self._setnonblock(true)
459 self._recvfrom(*args)
460 ensure
461 self._setnonblock(false)
462 end
463 end
464
465 def sysaccept
466 Socket._accept(self.fileno)[0]
467 end
468end
469
470class UNIXSocket < BasicSocket
471 def initialize(path, &block)
472 if self.is_a? UNIXServer
473 super(path, "r")
474 else
475 super(Socket._socket(Socket::AF_UNIX, Socket::SOCK_STREAM, 0), "r+")
476 Socket._connect(self.fileno, Socket.sockaddr_un(path))
477
478 if block_given?
479 begin
480 yield self
481 ensure
482 begin
483 self.close unless self.closed?
484 rescue StandardError
485 end
486 end
487 end
488 end
489 end
490
491 def self.socketpair(type=Socket::SOCK_STREAM, protocol=0)
492 a = Socket.socketpair(Socket::AF_UNIX, type, protocol)
493 [ UNIXSocket.for_fd(a[0]), UNIXSocket.for_fd(a[1]) ]
494 end
495
496 class << self
497 alias pair socketpair
498 end
499
500 def addr
501 [ "AF_UNIX", path ]
502 end
503
504 def path
505 Addrinfo.new(self.getsockname).unix_path
506 end
507
508 def peeraddr
509 [ "AF_UNIX", Addrinfo.new(self.getpeername).unix_path ]
510 end
511
512 #def recv_io
513
514 def recvfrom(maxlen, flags=0)
515 msg, sa = _recvfrom(maxlen, flags)
516 path = (sa.size > 0) ? Addrinfo.new(sa).unix_path : ""
517 [ msg, [ "AF_UNIX", path ] ]
518 end
519
520 #def send_io
521end
522
523class UNIXServer < UNIXSocket
524 def initialize(path)
525 fd = Socket._socket(Socket::AF_UNIX, Socket::SOCK_STREAM, 0)
526 begin
527 super(fd)
528 Socket._bind(fd, Socket.pack_sockaddr_un(path))
529 self.listen(5)
530 rescue => e
531 IO._sysclose(fd) rescue nil
532 raise e
533 end
534
535 if block_given?
536 begin
537 yield self
538 ensure
539 self.close rescue nil unless self.closed?
540 end
541 end
542 end
543
544 def accept
545 fd = self.sysaccept
546 begin
547 sock = UNIXSocket.for_fd(fd)
548 rescue
549 IO._sysclose(fd) rescue nil
550 end
551 sock
552 end
553
554 def accept_nonblock
555 begin
556 self._setnonblock(true)
557 self.accept
558 ensure
559 self._setnonblock(false)
560 end
561 end
562
563 def listen(backlog)
564 Socket._listen(self.fileno, backlog)
565 0
566 end
567
568 def sysaccept
569 Socket._accept(self.fileno)[0]
570 end
571end
572
573class Socket
574 include Constants
575end
576
577class Socket
578 class Option
579 def initialize(family, level, optname, data)
580 @family = family
581 @level = level
582 @optname = optname
583 @data = data
584 end
585
586 def self.bool(family, level, optname, bool)
587 self.new(family, level, optname, [(bool ? 1 : 0)].pack('i'))
588 end
589
590 def self.int(family, level, optname, integer)
591 self.new(family, level, optname, [integer].pack('i'))
592 end
593
594 #def self.linger(family, level, optname, integer)
595 #end
596
597 attr_reader :data, :family, :level, :optname
598
599 def bool
600 @data.unpack('i')[0] != 0
601 end
602
603 def inspect
604 "#<Socket::Option: family:#{@family} level:#{@level} optname:#{@optname} #{@data.inspect}>"
605 end
606
607 def int
608 @data.unpack('i')[0]
609 end
610
611 def linger
612 raise NotImplementedError.new
613 end
614
615 def unpack(template)
616 raise NotImplementedError.new
617 end
618 end
619end
620
621class SocketError < StandardError; end
Note: See TracBrowser for help on using the repository browser.