module ServerEngine::SocketManagerWin::ServerModule

Constants

TCP_OPTIONS
UDP_OPTIONS

Private Instance Methods

htons(h) click to toggle source
# File lib/serverengine/socket_manager_win.rb, line 106
def htons(h)
  [h].pack("S").unpack("n")[0]
end
listen_new(proto, bind_ip, port) click to toggle source
# File lib/serverengine/socket_manager_win.rb, line 66
def listen_new(proto, bind_ip, port)
  protocol, proto_info, klass, listen = case proto
                                        when :tcp then TCP_OPTIONS
                                        when :udp then UDP_OPTIONS
                                        else
                                          raise ArgumentError, "invalid protocol: #{proto}"
                                        end
  family = bind_ip.ipv6? ? Socket::AF_INET6 : Socket::AF_INET

  sock_addr = Socket.pack_sockaddr_in(port, bind_ip.to_s)

  handle = WinSock.WSASocketA(family, protocol, proto_info, nil, 0, 1)
  if handle == WinSock::INVALID_SOCKET
    RbWinSock.raise_last_error("WSASocketA(2)")
  end

  # wrap in TCPServer/UDPSocket immediately so that its finalizer safely closes the handle
  sock = RbWinSock.wrap_io_handle(klass, handle, 0)

  unless WinSock.bind(sock.handle, sock_addr, sock_addr.bytesize) == 0
    RbWinSock.raise_last_error("bind(2)")
  end

  if listen
    unless WinSock.listen(sock.handle, Socket::SOMAXCONN) == 0
      RbWinSock.raise_last_error("listen(2)")
    end
  end

  sock
end
listen_tcp_new(bind_ip, port) click to toggle source
# File lib/serverengine/socket_manager_win.rb, line 98
def listen_tcp_new(bind_ip, port)
  listen_new(:tcp, bind_ip, port)
end
listen_udp_new(bind_ip, port) click to toggle source
# File lib/serverengine/socket_manager_win.rb, line 102
def listen_udp_new(bind_ip, port)
  listen_new(:udp, bind_ip, port)
end
send_socket(peer, pid, method, bind, port) click to toggle source
# File lib/serverengine/socket_manager_win.rb, line 136
def send_socket(peer, pid, method, bind, port)
  case method
  when :listen_tcp
    sock = listen_tcp(bind, port)
    type = Socket::SOCK_STREAM
  when :listen_udp
    sock = listen_udp(bind, port)
    type = Socket::SOCK_DGRAM
  else
    raise ArgumentError, "Unknown method: #{method.inspect}"
  end

  proto = WinSock::WSAPROTOCOL_INFO.malloc
  unless WinSock.WSADuplicateSocketA(sock.handle, pid, proto) == 0
    RbWinSock.raise_last_error("WSADuplicateSocketA(3)")
  end

  SocketManager.send_peer(peer, proto.to_bin)
end
start_server(addr) click to toggle source
# File lib/serverengine/socket_manager_win.rb, line 110
def start_server(addr)
  # TODO: use TCPServer, but this is risky because using not conflict path is easy,
  # but using not conflict port is difficult. Then We had better implement using NamedPipe.
  @server = TCPServer.new("127.0.0.1", addr)
  @thread = Thread.new do
    begin
      while peer = @server.accept
        Thread.new(peer, &method(:process_peer))  # process_peer calls send_socket
      end
    rescue => e
      unless @server.closed?
        ServerEngine.dump_uncaught_error(e)
      end
    end
  end

  return path
end
stop_server() click to toggle source
# File lib/serverengine/socket_manager_win.rb, line 129
def stop_server
  @tcp_sockets.reject! {|key,lsock| lsock.close; true }
  @udp_sockets.reject! {|key,usock| usock.close; true }
  @server.close unless @server.closed?
  @thread.join
end