net-proto 1.0.6 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,3 +1,12 @@
1
+ == 1.1.0 - 18-Jan-2012
2
+ * Switched to FFI instead of C backend. Now works with JRuby, too.
3
+ * Added the generic get_protocol instance method that accepts either a
4
+ string or an integer and does the right thing. This method should be
5
+ preferred going forward.
6
+ * Documentation updates.
7
+ * Refactored the test suite to use features of test-unit 2.x.
8
+ * Added a default rake task.
9
+
1
10
  == 1.0.6 - 22-Oct-2010
2
11
  * Refactored the test suite and removed one test that was implementation
3
12
  dependent and not useful.
data/MANIFEST CHANGED
@@ -2,12 +2,12 @@
2
2
  * MANIFEST
3
3
  * README
4
4
  * Rakefile
5
- * net-proto.gemspec
6
5
  * doc/netproto.txt
6
+ * net-proto.gemspec
7
+ * lib/net/proto.rb
8
+ * lib/net/proto/common.rb
9
+ * lib/generic/net/proto.rb
10
+ * lib/linux/net/proto.rb
11
+ * lib/sunos/net/proto.rb
7
12
  * examples/example_net_proto.rb
8
- * ext/version.h
9
- * ext/generic/generic.c
10
- * ext/linux/linux.c
11
- * ext/sunos/sunos.c
12
- * ext/windows/windows.c
13
13
  * test/test_net_proto.rb
data/README CHANGED
@@ -1,34 +1,41 @@
1
- = Description
1
+ == Description
2
2
  The net-proto package provides a way to get protocol information.
3
3
 
4
- = Installation
4
+ This is a wrapper for the getprotobyname(), getprotobynumber() and
5
+ the getprotoent() functions.
6
+
7
+ == Installation
5
8
  gem install net-proto
6
9
 
7
- = Synopsis
8
- require 'net/proto'
10
+ == Prerequisites
11
+ ffi 1.0.0 or later.
9
12
 
10
- Net::Proto.getprotobyname('tcp') # => 6
11
- Net::Proto.getprotobynumber(0) # => 'ip'
13
+ == Synopsis
14
+ require 'net/proto'
12
15
 
13
- Net::Proto.getprotoent{ |entry| p entry }
16
+ # Using generic method
17
+ Net::Proto.get_protocol(1) # => 'icmp'
18
+ Net::Proto.get_protocol('icmp') # => 1
14
19
 
15
- = Notes
16
- This library is a wrapper for the getprotobyname(), getprotobynumber() and
17
- the getprotoent() functions.
20
+ # Using type specific methods
21
+ Net::Proto.getprotobynumber(6) # => 'tcp'
22
+ Net::Proto.getprotobyname('tcp') # => 6
18
23
 
19
- The net-proto package uses reentrant code for sunos and linux. Otherwise, the
20
- generic form of the functions are used (which may be reentrant by default
21
- anway - check the man pages on your platform).
24
+ # Iterating over all protocols
25
+ Net::Proto.getprotoent do |ent|
26
+ p ent
27
+ end
22
28
 
29
+ == MS Windows
23
30
  The Proto.getprotoent method is not supported on MS Windows because the
24
31
  underlying function isn't supported by the MS Windows API.
25
32
 
26
- = Why should I use this?
33
+ == Why should I use this?
27
34
  Ruby has a predefined set of constants in socket.c in the general form of
28
35
  IPPROTO_XXX, Y. However, using constants in this fashion can be unreliable
29
36
  because it's easy to define your own protocols (I set 'echo' to 7, for
30
37
  example), or to modify/delete entries in /etc/protocols.
31
38
 
32
- = Further Documentation
39
+ == Further Documentation
33
40
  See the 'netproto.txt' file under the 'doc' directory for more details. There
34
41
  is also an example under the 'examples' directory.
data/Rakefile CHANGED
@@ -1,80 +1,29 @@
1
1
  require 'rake'
2
- require 'rake/clean'
3
2
  require 'rake/testtask'
4
- require 'rbconfig'
5
- include Config
6
-
7
- desc 'Clean the build files for the net-proto source'
8
- task :clean do
9
- Dir['*.gem'].each{ |f| File.delete(f) }
10
- Dir['**/*.rbc'].each{ |f| File.delete(f) }
11
-
12
- make = RUBY_PLATFORM.match('mswin') ? 'nmake' : 'make'
13
-
14
- Dir.chdir('ext') do
15
- proto_file = 'proto.' + Config::CONFIG['DLEXT']
16
- if File.exists?('proto.o') || File.exists?(proto_file)
17
- sh "#{make} distclean"
18
- end
19
- rm_rf('proto.c') if File.exists?('proto.c')
20
- rm_rf('net') if File.exists?('net')
21
- end
22
-
23
- rm_rf('net') if File.exists?('net')
24
- rm_rf('lib') if File.exists?('lib')
25
- end
3
+ require 'rake/clean'
26
4
 
27
- desc 'Build the net-proto library'
28
- task :build => [:clean] do
29
- make = RUBY_PLATFORM.match('mswin') ? 'nmake' : 'make'
30
- Dir.chdir('ext') do
31
- ruby 'extconf.rb'
32
- sh make
33
- build_file = 'proto.' + Config::CONFIG['DLEXT']
34
- Dir.mkdir('net') unless File.exists?('net')
35
- FileUtils.cp(build_file, 'net')
36
- end
37
- end
5
+ CLEAN.include('**/*.gem', '**/*.rbx', '**/*.rbc')
38
6
 
39
- namespace :gem do
40
- desc 'Build a standard gem'
7
+ namespace 'gem' do
8
+ desc 'Create the net-proto gem'
41
9
  task :create => :clean do
42
- rm_rf('lib') if File.exists?('lib')
43
- spec = eval(IO.read('net-proto.gemspec'))
44
- Gem::Builder.new(spec).build
45
- end
46
-
47
- desc 'Build a binary gem'
48
- task :create_binary => [:build] do
49
- file = 'ext/net/proto.' + CONFIG['DLEXT']
50
- mkdir_p('lib/net')
51
- mv(file, 'lib/net')
52
-
53
10
  spec = eval(IO.read('net-proto.gemspec'))
54
- spec.extensions = nil
55
- spec.files = spec.files.reject{ |f| f.include?('ext/') }
56
- spec.platform = Gem::Platform::CURRENT
57
-
58
11
  Gem::Builder.new(spec).build
59
12
  end
60
13
 
61
- desc 'Install the net-proto library (gem)'
14
+ desc 'Install the net-proto gem'
62
15
  task :install => [:create] do
63
- ruby 'net-proto.gemspec'
64
16
  file = Dir["net-proto*.gem"].last
65
17
  sh "gem install #{file}"
66
18
  end
67
19
  end
68
20
 
69
21
  desc 'Run the example net-proto program'
70
- task :example => [:build] do
71
- Dir.mkdir('net') unless File.exists?('net')
72
- ruby '-Iext examples/example_net_proto.rb'
22
+ task :example do
23
+ ruby '-Ilib examples/example_net_proto.rb'
73
24
  end
74
25
 
75
26
  Rake::TestTask.new do |t|
76
- task :test => :build
77
- t.libs << 'ext'
78
27
  t.warning = true
79
28
  t.verbose = true
80
29
  end
@@ -44,39 +44,36 @@ Proto.getprotoent{ |struct| ... }
44
44
 
45
45
  == Notes
46
46
  This module uses the reentrant (i.e. thread safe) functions on those
47
- platforms that support them. In some cases, e.g. FreeBSD and HP-UX, the
47
+ platforms that support them. In some cases, e.g. FreeBSD and HP-UX, the
48
48
  standard function names are reentrant by default (i.e. there is no '_r'
49
- version, or it's not needed), so you will not see specific .c files for
50
- all platforms.
49
+ version, or it's not needed).
51
50
 
52
51
  The 'setprotoent()' and 'endprotoent()' functions are not implemented as
53
- separate method calls. Rather, these are called internally by the various
52
+ separate method calls. Rather, these are called internally by the various
54
53
  methods, except on Windows, which does not support them.
55
54
 
56
55
  The 'getprotoent()' method is not supported on the MS Windows platform.
57
56
  It's not part of the API as of Windows XP.
58
57
 
59
58
  == Known Bugs
60
- None that I'm aware of. Please log any bug reports on the project page
61
- at http://ruby-netutils.sf.net.
59
+ None that I'm aware of. Please log any bug reports on the project page
60
+ at https://github.com/djberg96/net-proto.
62
61
 
63
62
  == Future Plans
64
- Use the asynchronous calls (WSAAsyncGetProtoByName and
65
- WSAAsyncGetProtoByNumber) on MS Windows systems.
63
+ Use the asynchronous calls (WSAAsyncGetProtoByName and
64
+ WSAAsyncGetProtoByNumber) on MS Windows systems.
66
65
 
67
66
  == Copyright
68
- (C) 2003-2007 Daniel J. Berger
69
- All rights reserved.
67
+ (C) 2003-2012 Daniel J. Berger
68
+ All rights reserved.
70
69
 
71
70
  == Warranty
72
- This package is provided "as is" and without any express or
73
- implied warranties, including, without limitation, the implied
74
- warranties of merchantability and fitness for a particular purpose.
71
+ This package is provided "as is" and without any express or
72
+ implied warranties, including, without limitation, the implied
73
+ warranties of merchantability and fitness for a particular purpose.
75
74
 
76
75
  == License
77
- Ruby's
76
+ Artistic 2.0
78
77
 
79
78
  == Author
80
- Daniel J. Berger
81
- djberg96 at gmail dot com
82
- imperator on IRC (Freenode)
79
+ Daniel J. Berger
@@ -4,7 +4,7 @@
4
4
  # A generic test program for general futzing. You cna run this example
5
5
  # code via the 'rake example' task.
6
6
  #########################################################################
7
- require 'net/proto''
7
+ require 'net/proto'
8
8
  include Net
9
9
 
10
10
  puts "VERSION: " + Proto::VERSION
@@ -12,14 +12,14 @@ puts "VERSION: " + Proto::VERSION
12
12
  puts "UDP port: " + Proto.getprotobyname("udp").to_s
13
13
 
14
14
  unless File::ALT_SEPARATOR
15
- puts "Name\t\tProto\tAliases"
16
- puts "=========================="
15
+ puts "Name\t\tProto\tAliases"
16
+ puts "=========================="
17
17
 
18
- Proto.getprotoent.each{ |s|
19
- if s.name.length > 7
20
- puts s.name + "\t" + s.proto.to_s + "\t" + s.aliases.join(", ")
21
- else
22
- puts s.name + "\t\t" + s.proto.to_s + "\t" + s.aliases.join(", ")
23
- end
24
- }
25
- end
18
+ Proto.getprotoent.each{ |s|
19
+ if s.name.length > 7
20
+ puts s.name + "\t" + s.proto.to_s + "\t" + s.aliases.join(", ")
21
+ else
22
+ puts s.name + "\t\t" + s.proto.to_s + "\t" + s.aliases.join(", ")
23
+ end
24
+ }
25
+ end
@@ -0,0 +1,145 @@
1
+ require 'net/proto/common'
2
+
3
+ # The Net module serves as a namespace only.
4
+ module Net
5
+ # The Proto class serves as the base class for the various protocol methods.
6
+ class Proto
7
+ extend FFI::Library
8
+
9
+ ffi_lib FFI::Library::LIBC
10
+
11
+ if File::ALT_SEPARATOR
12
+ ffi_lib 'ws2_32'
13
+ ffi_convention :stdcall
14
+ end
15
+
16
+ private
17
+
18
+ # These should exist on every platform.
19
+ attach_function :getprotobyname_c, :getprotobyname, [:string], :pointer
20
+ attach_function :getprotobynumber_c, :getprotobynumber, [:int], :pointer
21
+
22
+ # These are defined on most platforms, but not all.
23
+ begin
24
+ attach_function :setprotoent, [:int], :void
25
+ attach_function :endprotoent, [], :void
26
+ attach_function :getprotoent_c, :getprotoent, [], :pointer
27
+ rescue FFI::NotFoundError
28
+ # Ignore, not supported. Probably Windows.
29
+ else
30
+ private_class_method :setprotoent
31
+ private_class_method :endprotoent
32
+ private_class_method :getprotoent_c
33
+ end
34
+
35
+ private_class_method :getprotobyname_c
36
+ private_class_method :getprotobynumber_c
37
+
38
+ public
39
+
40
+ # If given a protocol string, returns the corresponding number. If
41
+ # given a protocol number, returns the corresponding string.
42
+ #
43
+ # Returns nil if not found in either case.
44
+ #
45
+ # Examples:
46
+ #
47
+ # Net::Proto.get_protocol('tcp') # => 6
48
+ # Net::Proto.get_protocol(1) # => 'icmp'
49
+ #
50
+ def self.get_protocol(arg)
51
+ if arg.is_a?(String)
52
+ getprotobyname(arg)
53
+ else
54
+ getprotobynumber(arg)
55
+ end
56
+ end
57
+
58
+ # Given a protocol string, returns the corresponding number, or nil if
59
+ # not found.
60
+ #
61
+ # Examples:
62
+ #
63
+ # Net::Proto.getprotobyname('tcp') # => 6
64
+ # Net::Proto.getprotobyname('bogus') # => nil
65
+ #
66
+ def self.getprotobyname(protocol)
67
+ raise TypeError unless protocol.is_a?(String)
68
+
69
+ begin
70
+ setprotoent(0) if respond_to?(:setprotoent, true)
71
+ ptr = getprotobyname_c(protocol)
72
+ struct = ProtocolStruct.new(ptr) unless ptr.null?
73
+ ensure
74
+ endprotoent() if respond_to?(:endprotoent, true)
75
+ end
76
+
77
+ ptr.null? ? nil : struct[:p_proto]
78
+ end
79
+
80
+ # Given a protocol number, returns the corresponding string, or nil if
81
+ # not found.
82
+ #
83
+ # Examples:
84
+ #
85
+ # Net::Proto.getprotobynumber(6) # => 'tcp'
86
+ # Net::Proto.getprotobynumber(999) # => nil
87
+ #
88
+ def self.getprotobynumber(protocol)
89
+ raise TypeError unless protocol.is_a?(Integer)
90
+
91
+ begin
92
+ setprotoent(0) if respond_to?(:setprotoent, true)
93
+ ptr = getprotobynumber_c(protocol)
94
+ struct = ProtocolStruct.new(ptr) unless ptr.null?
95
+ ensure
96
+ endprotoent() if respond_to?(:endprotoent, true)
97
+ end
98
+
99
+ ptr.null? ? nil: struct[:p_name]
100
+ end
101
+
102
+ # In block form, yields each entry from /etc/protocols as a struct of type
103
+ # Proto::ProtoStruct. In non-block form, returns an array of structs.
104
+ #
105
+ # The fields are 'name' (a string), 'aliases' (an array of strings,
106
+ # though often only one element), and 'proto' (a number).
107
+ #
108
+ # Example:
109
+ #
110
+ # Net::Proto.getprotoent.each{ |prot|
111
+ # p prot.name
112
+ # p prot.aliases
113
+ # p prot.proto
114
+ # }
115
+ #
116
+ def self.getprotoent
117
+ raise NoMethodError unless respond_to?(:getprotoent, true)
118
+
119
+ structs = block_given? ? nil : []
120
+
121
+ begin
122
+ setprotoent(0)
123
+ until (ptr = getprotoent_c()).null?
124
+ ffi_struct = ProtocolStruct.new(ptr)
125
+
126
+ ruby_struct = ProtoStruct.new(
127
+ ffi_struct[:p_name],
128
+ ffi_struct[:p_aliases].read_array_of_string,
129
+ ffi_struct[:p_proto]
130
+ ).freeze
131
+
132
+ if block_given?
133
+ yield ruby_struct
134
+ else
135
+ structs << ruby_struct
136
+ end
137
+ end
138
+ ensure
139
+ endprotoent()
140
+ end
141
+
142
+ structs
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,140 @@
1
+ require 'net/proto/common'
2
+
3
+ # The Net module serves as a namespace only.
4
+ module Net
5
+
6
+ # The Proto class serves as the base class for the various protocol methods.
7
+ class Proto
8
+ ffi_lib FFI::Library::LIBC
9
+
10
+ private
11
+
12
+ attach_function :setprotoent, [:int], :void
13
+ attach_function :endprotoent, [], :void
14
+ attach_function :getprotobyname_r, [:string, :pointer, :pointer, :long, :pointer], :int
15
+ attach_function :getprotobynumber_r, [:int, :pointer, :pointer, :long, :pointer], :int
16
+ attach_function :getprotoent_r, [:pointer, :pointer, :long, :pointer], :int
17
+
18
+ private_class_method :setprotoent, :endprotoent, :getprotobyname_r
19
+ private_class_method :getprotobynumber_r, :getprotoent_r
20
+
21
+ public
22
+
23
+ # If given a protocol string, returns the corresponding number. If
24
+ # given a protocol number, returns the corresponding string.
25
+ #
26
+ # Returns nil if not found in either case.
27
+ #
28
+ # Examples:
29
+ #
30
+ # Net::Proto.get_protocol('tcp') # => 6
31
+ # Net::Proto.get_protocol(1) # => 'icmp'
32
+ #
33
+ def self.get_protocol(argument)
34
+ if argument.is_a?(String)
35
+ getprotobyname(argument)
36
+ else
37
+ getprotobynumber(argument)
38
+ end
39
+ end
40
+
41
+ # Given a protocol string, returns the corresponding number, or nil if
42
+ # not found.
43
+ #
44
+ # Examples:
45
+ #
46
+ # Net::Proto.getprotobyname('tcp') # => 6
47
+ # Net::Proto.getprotobyname('bogus') # => nil
48
+ #
49
+ def self.getprotobyname(protocol)
50
+ raise TypeError unless protocol.is_a?(String)
51
+
52
+ pptr = FFI::MemoryPointer.new(ProtocolStruct.size)
53
+ qptr = FFI::MemoryPointer.new(ProtocolStruct.size)
54
+ buf = FFI::MemoryPointer.new(:char, 1024)
55
+
56
+ begin
57
+ setprotoent(0)
58
+ int = getprotobyname_r(protocol, pptr, buf, buf.size, qptr)
59
+ ensure
60
+ endprotoent()
61
+ end
62
+
63
+ int > 0 || qptr.get_pointer(0).null? ? nil : ProtocolStruct.new(pptr)[:p_proto]
64
+ end
65
+
66
+ # Given a protocol number, returns the corresponding string, or nil if
67
+ # not found.
68
+ #
69
+ # Examples:
70
+ #
71
+ # Net::Proto.getprotobynumber(6) # => 'tcp'
72
+ # Net::Proto.getprotobynumber(999) # => nil
73
+ #
74
+ def self.getprotobynumber(protocol)
75
+ raise TypeError unless protocol.is_a?(Integer)
76
+
77
+ pptr = FFI::MemoryPointer.new(ProtocolStruct.size)
78
+ qptr = FFI::MemoryPointer.new(ProtocolStruct.size)
79
+ buf = FFI::MemoryPointer.new(:char, 1024)
80
+
81
+ begin
82
+ setprotoent(0)
83
+ int = getprotobynumber_r(protocol, pptr, buf, buf.size, qptr)
84
+ ensure
85
+ endprotoent()
86
+ end
87
+
88
+ int > 0 || qptr.get_pointer(0).null? ? nil : ProtocolStruct.new(pptr)[:p_name]
89
+ end
90
+
91
+ # In block form, yields each entry from /etc/protocols as a struct of type
92
+ # Proto::ProtoStruct. In non-block form, returns an array of structs.
93
+ #
94
+ # The fields are 'name' (a string), 'aliases' (an array of strings,
95
+ # though often only one element), and 'proto' (a number).
96
+ #
97
+ # Example:
98
+ #
99
+ # Net::Proto.getprotoent.each{ |prot|
100
+ # p prot.name
101
+ # p prot.aliases
102
+ # p prot.proto
103
+ # }
104
+ #
105
+ def self.getprotoent
106
+ structs = block_given? ? nil : []
107
+
108
+ pptr = FFI::MemoryPointer.new(ProtocolStruct.size)
109
+ qptr = FFI::MemoryPointer.new(ProtocolStruct.size)
110
+ buf = FFI::MemoryPointer.new(1024)
111
+
112
+ begin
113
+ setprotoent(0)
114
+
115
+ while int = getprotoent_r(pptr, buf, buf.size, qptr)
116
+ break if int > 0 || qptr.null?
117
+ buf = FFI::MemoryPointer.new(1024)
118
+
119
+ ffi_struct = ProtocolStruct.new(pptr)
120
+
121
+ ruby_struct = ProtoStruct.new(
122
+ ffi_struct[:p_name],
123
+ ffi_struct[:p_aliases].read_array_of_string,
124
+ ffi_struct[:p_proto]
125
+ ).freeze
126
+
127
+ if block_given?
128
+ yield ruby_struct
129
+ else
130
+ structs << ruby_struct
131
+ end
132
+ end
133
+ ensure
134
+ endprotoent
135
+ end
136
+
137
+ structs
138
+ end
139
+ end
140
+ end