@JRubyMethod(name = "initialize", required = 1, optional = 1, visibility = Visibility.PRIVATE) public IRubyObject initialize(ThreadContext context, IRubyObject[] args) { Ruby runtime = context.runtime; IRubyObject _host = args[0]; IRubyObject _port = args.length > 1 ? args[1] : context.nil; String host; if (_host.isNil() || ((_host instanceof RubyString) && ((RubyString) _host).isEmpty())) { host = "0.0.0.0"; } else if (_host instanceof RubyFixnum) { // numeric host, use it for port _port = _host; host = "0.0.0.0"; } else { host = _host.convertToString().toString(); } int port = SocketUtils.getPortFrom(context, _port); try { InetAddress addr = InetAddress.getByName(host); ssc = ServerSocketChannel.open(); socket_address = new InetSocketAddress(addr, port); ssc.socket().bind(socket_address); initSocket(runtime, new ChannelDescriptor(ssc, newModeFlags(runtime, ModeFlags.RDWR))); } catch (UnknownHostException e) { throw SocketUtils.sockerr(runtime, "initialize: name or service not known"); } catch (BindException e) { throw runtime.newErrnoEADDRFromBindException(e); } catch (SocketException e) { String msg = e.getMessage(); if (msg.indexOf("Permission denied") != -1) { throw runtime.newErrnoEACCESError("bind(2)"); } else { throw SocketUtils.sockerr(runtime, "initialize: name or service not known"); } } catch (IOException e) { throw SocketUtils.sockerr(runtime, "initialize: name or service not known"); } catch (IllegalArgumentException iae) { throw SocketUtils.sockerr(runtime, iae.getMessage()); } return this; }
@JRubyMethod(name = "accept_nonblock") public IRubyObject accept_nonblock(ThreadContext context) { Ruby runtime = context.runtime; RubyTCPSocket socket = new RubyTCPSocket(runtime, runtime.getClass("TCPSocket")); Selector selector = null; synchronized (ssc.blockingLock()) { boolean oldBlocking = ssc.isBlocking(); try { ssc.configureBlocking(false); selector = SelectorFactory.openWithRetryFrom(runtime, SelectorProvider.provider()); boolean ready = context.getThread().select(this, SelectionKey.OP_ACCEPT, 0); if (!ready) { // no connection immediately accepted, let them try again throw runtime.newErrnoEAGAINError("Resource temporarily unavailable"); } else { // otherwise one key has been selected (ours) so we get the channel and hand it off socket.initSocket( context.runtime, new ChannelDescriptor(ssc.accept(), newModeFlags(runtime, ModeFlags.RDWR))); return socket; } } catch (IOException e) { throw SocketUtils.sockerr(context.runtime, "problem when accepting"); } finally { try { if (selector != null) selector.close(); } catch (Exception e) { } try { ssc.configureBlocking(oldBlocking); } catch (IOException ioe) { } } } }
private void doBind( ThreadContext context, Channel channel, InetSocketAddress iaddr, int backlog) { Ruby runtime = context.runtime; try { if (channel instanceof ServerSocketChannel) { ServerSocket socket = ((ServerSocketChannel) channel).socket(); socket.bind(iaddr, backlog); } else { throw runtime.newErrnoENOPROTOOPTError(); } } catch (UnknownHostException e) { throw SocketUtils.sockerr(runtime, "bind(2): unknown host"); } catch (SocketException e) { handleSocketException(runtime, e, "bind(2)", iaddr); } catch (IOException e) { throw sockerr(runtime, "bind(2): name or service not known", e); } catch (IllegalArgumentException e) { throw sockerr(runtime, e.getMessage(), e); } }
@JRubyMethod(name = "accept") public IRubyObject accept(ThreadContext context) { Ruby runtime = context.runtime; RubyTCPSocket socket = new RubyTCPSocket(runtime, runtime.getClass("TCPSocket")); try { RubyThread thread = context.getThread(); while (true) { boolean ready = thread.select(this, SelectionKey.OP_ACCEPT); if (!ready) { // we were woken up without being selected...poll for thread events and go back to sleep context.pollThreadEvents(); } else { SocketChannel connected = ssc.accept(); if (connected == null) continue; connected.finishConnect(); // Force the client socket to be blocking synchronized (connected.blockingLock()) { connected.configureBlocking(false); connected.configureBlocking(true); } // otherwise one key has been selected (ours) so we get the channel and hand it off socket.initSocket( runtime, new ChannelDescriptor(connected, newModeFlags(runtime, ModeFlags.RDWR))); return socket; } } } catch (IOException e) { throw SocketUtils.sockerr(runtime, "problem when accepting"); } }
@JRubyMethod(notImplemented = true) public IRubyObject connect(ThreadContext context, IRubyObject arg) { throw SocketUtils.sockerr(context.runtime, "server socket cannot connect"); }