From 10aa1221f6c1160404ee4835a7e8ff1109091ef6 Mon Sep 17 00:00:00 2001 From: Wilson Bilkovich Date: Wed, 19 Sep 2007 22:17:52 -0400 Subject: [PATCH] Interim commit of Socket work so I can generate a patch --- lib/socket.rb | 38 +++++++++++++++- shotgun/lib/ffi_util.c | 10 ++++ spec/library/socket_spec.rb | 100 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 spec/library/socket_spec.rb diff --git a/lib/socket.rb b/lib/socket.rb index ea7b275..ceb3b80 100644 --- a/lib/socket.rb +++ b/lib/socket.rb @@ -38,6 +38,8 @@ class Socket < IO SOCK_RAW = 3 SOCK_RDM = 4 SOCK_SEQPACKET = 5 + + AI_PASSIVE = 1 end module Foreign @@ -45,6 +47,7 @@ class Socket < IO attach_function nil, "ffi_pack_sockaddr_un", :pack_sa_unix, [:state, :string], :object attach_function nil, "ffi_pack_sockaddr_in", :pack_sa_ip, [:state, :string, :string, :int, :int], :object attach_function nil, "connect", :connect_socket, [:int, :pointer, :int], :int + attach_function nil, "ffi_bind", :bind_socket, [:int, :pointer, :int], :int end def initialize(domain, type, protocol) @@ -87,9 +90,10 @@ class TCPSocket < IPSocket @host = host @port = port - @sockaddr, @sockaddr_size = Socket::Foreign.pack_sa_ip(nil, host.to_s, port.to_s, @type, 0) + @sockaddr, @sockaddr_size = Socket::Foreign.pack_sa_ip(host.to_s, port.to_s, @type, 0) - if Socket::Foreign.connect_socket(descriptor(), @sockaddr, @sockaddr_size) != 0 + sock = Socket::Foreign.connect_socket(descriptor, @sockaddr, @sockaddr_size) + if sock != 0 Errno.handle "Unable to connect to #{host}:#{port}" end end @@ -100,5 +104,35 @@ class TCPSocket < IPSocket end class TCPServer < TCPSocket + ivar_as_index :descriptor => 1 + def initialize(host, port = nil) + if host.kind_of?(Fixnum) then + port = host + host = '0.0.0.0' # TODO - Do this in a portable way + end + @host = host + @port = port + + @domain = Socket::Constants::AF_INET + @type = Socket::Constants::SOCK_STREAM + @protocol = 0 + fd = Socket::Foreign.create_socket(@domain, @type, @protocol) + if fd < 0 + Errno.handle "Unable to create socket" + end + @descriptor = fd + + @sockaddr, @sockaddr_size = Socket::Foreign.pack_sa_ip(@host.to_s, @port.to_s, @type, Socket::Constants::AI_PASSIVE) + bind = Socket::Foreign.bind_socket(descriptor, @sockaddr, @sockaddr_size) + if bind != 0 + Errno.handle "Unable to bind to #{@host}:#{@port}" + end + + sock = Socket::Foreign.connect_socket(descriptor, @sockaddr, @sockaddr_size) + if sock != 0 + Errno.handle "Unable to connect to #{host}:#{port}" + end + end + end diff --git a/shotgun/lib/ffi_util.c b/shotgun/lib/ffi_util.c index f621829..2bbbf1c 100644 --- a/shotgun/lib/ffi_util.c +++ b/shotgun/lib/ffi_util.c @@ -4,6 +4,7 @@ #include #include #include +#include //remove me #include #include "shotgun.h" @@ -89,3 +90,12 @@ int ffi_connect(int fd, struct sockaddr *name, int len) { return ret; } + +int ffi_bind(int s, struct sockaddr *name, int len) { + int ret; + struct stat sb; + ret = fstat(s, &sb); + assert(sb.st_mode & S_IFSOCK && "trying to bind something that isn't a socket!"); + ret = bind(s, name, len); + return ret; +} diff --git a/spec/library/socket_spec.rb b/spec/library/socket_spec.rb new file mode 100644 index 0000000..efb9223 --- /dev/null +++ b/spec/library/socket_spec.rb @@ -0,0 +1,100 @@ +require File.dirname(__FILE__) + '/../spec_helper' +require 'socket' +@port = 40000 + +=begin +describe "Socket" do + it "should inherit from BasicSocket and IO" do + Socket.superclass.should == BasicSocket + BasicSocket.superclass.should == IO + end +end + +describe "Socket's class hierarchy" do + it "should have an IPSocket in parallel to Socket" do + Socket.ancestors.include?(IPSocket).should == false + IPSocket.ancestors.include?(Socket).should == false + IPSocket.superclass.should == BasicSocket + TCPSocket.superclass.should == IPSocket + UDPSocket.superclass.should == IPSocket + end + + it "should have a UNIXSocket in parallel to Socket" do + Socket.ancestors.include?(UNIXSocket).should == false + UNIXSocket.ancestors.include?(Socket).should == false + UNIXSocket.superclass.should == BasicSocket + end +end + +describe "Server class hierarchy" do + it "should contain UNIXServer" do + UNIXServer.superclass.should == UNIXSocket + end +end +=end + +describe "TCPServer.new" do + after(:each) do + @server.close if @server + end + it "should bind to a host and a port" do + @server = TCPServer.new('127.0.0.1', @port) + end +end + +=begin +describe "TCPServer#accept" do + before(:each) do + @server = TCPServer.new('127.0.0.1', @port) + @server.listen 1 + end + after(:each) do + @server.close + end +end + +describe "TCPServer#accept_nonblock" do +end + +describe "TCPServer#listen" do + before(:each) do + @server = TCPServer.new('127.0.0.1', @port) + end + after(:each) do + @server.close + end + it "should always return zero" do + @server.listen(1).should == 0 + end +end +=end + +=begin +describe "TCPServer receiving data" do + before(:each) do + @data = [] + @read = false + @thread = Thread.new do + @server = TCPServer.new('127.0.0.1', @port) + while (client = @server.accept) do + @data << client.read(5) + @read = true + client.close + end + end + end + after(:each) do + @server.close + end + + it "should accept what is written by the client" do + @client = TCPSocket.new('127.0.0.1', @port) + @client.write('hello') + nil until @read + @data.should == ['hello'] + end +end +=end + +describe "TCPServer#sysaccept" do +end -- 1.5.3.1