network-facade 0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,117 @@
1
+ #!/usr/bin/ruby
2
+ require 'network-facade'
3
+
4
+ def create_ca(opts = {})
5
+ [ :country, :hostname, :domainname ].each do |o|
6
+ raise "Missing option #{o}" if opts[o].nil?
7
+ end
8
+
9
+ name = [
10
+ [ 'C', opts[:country], OpenSSL::ASN1::PRINTABLESTRING ],
11
+ [ 'O', opts[:domainname], OpenSSL::ASN1::UTF8STRING ],
12
+ [ 'OU', opts[:hostname], OpenSSL::ASN1::UTF8STRING ],
13
+ [ 'CN', 'CA' ]
14
+ ]
15
+
16
+ cert_opts = {
17
+ :is_ca => true,
18
+ :name => name,
19
+ :comment => 'NetworkFacade Certification Authority',
20
+ :period => 3650
21
+ }
22
+
23
+ create(cert_opts)
24
+ end
25
+
26
+ def create_cert(opts)
27
+ [ :country, :hostname, :domainname, :ca_cert, :ca_key ].each do |o|
28
+ raise "Missing option #{o}" if opts[o].nil?
29
+ end
30
+
31
+ name = [
32
+ [ 'C', opts[:country], OpenSSL::ASN1::PRINTABLESTRING ],
33
+ [ 'O', opts[:domainname], OpenSSL::ASN1::UTF8STRING ],
34
+ [ 'OU', opts[:hostname], OpenSSL::ASN1::UTF8STRING ]
35
+ ]
36
+
37
+ opts[:ca_cert] = OpenSSL::X509::Certificate.new(File.read(opts[:ca_cert])) if opts[:ca_cert].is_a?(String)
38
+ opts[:ca_key] = OpenSSL::PKey::RSA.new(File.read(opts[:ca_key])) if opts[:ca_key].is_a?(String)
39
+
40
+ cert_opts = {
41
+ :name => name,
42
+ :ca_cert => opts[:ca_cert],
43
+ :ca_key => opts[:ca_key],
44
+ :comment => opts[:comment] || 'NetworkFacade Generated Certificate',
45
+ :period => 365
46
+ }
47
+
48
+ create(cert_opts)
49
+ end
50
+
51
+ def create(opts)
52
+ key = OpenSSL::PKey::RSA.new(1024)
53
+
54
+ cert = OpenSSL::X509::Certificate.new
55
+ cert.subject = ::OpenSSL::X509::Name.new(opts[:name])
56
+ cert.issuer = opts[:is_ca] ? cert.subject : opts[:ca_cert].subject
57
+ cert.not_before = Time.now
58
+ cert.not_after = Time.now + (opts[:period] * 24 * 60 * 60)
59
+ cert.public_key = key.public_key
60
+ cert.serial = opts[:is_ca] ? 0x0 : 0x2
61
+ cert.version = 2
62
+
63
+ ef = OpenSSL::X509::ExtensionFactory.new
64
+ ef.subject_certificate = cert
65
+ ef.issuer_certificate = opts[:is_ca] ? cert : opts[:ca_cert]
66
+
67
+ if opts[:is_ca]
68
+ cert.extensions = [
69
+ ef.create_extension('basicConstraints','CA:TRUE', true),
70
+ ef.create_extension('nsComment', opts[:comment]),
71
+ ef.create_extension('subjectKeyIdentifier', 'hash'),
72
+ ef.create_extension('keyUsage', 'cRLSign,keyCertSign', true)
73
+ ]
74
+ cert.add_extension(ef.create_extension('authorityKeyIdentifier', 'keyid:always,issuer:always'))
75
+ else
76
+ cert.extensions = [
77
+ ef.create_extension('basicConstraints','CA:FALSE', true),
78
+ ef.create_extension('nsComment', opts[:comment]),
79
+ ef.create_extension('subjectKeyIdentifier', 'hash'),
80
+ ]
81
+ cert.add_extension(ef.create_extension('authorityKeyIdentifier', 'keyid:always,issuer:always'))
82
+ end
83
+
84
+ cert.sign(opts[:is_ca] ? key : opts[:ca_key], OpenSSL::Digest::SHA1.new)
85
+
86
+ { :key => key, :cert => cert }
87
+ end
88
+
89
+ # Authority
90
+
91
+ CA = {
92
+ :country => 'FR',
93
+ :hostname => 'demo',
94
+ :domainname => 'example.com'
95
+ }
96
+
97
+ cert = create_ca(CA)
98
+ File.open('ca.key', 'w') { |fd| fd.puts cert[:key] }
99
+ File.open('ca.cert', 'w') { |fd| fd.puts cert[:cert].to_pem }
100
+
101
+ # Client / Server
102
+
103
+ OPTS = {
104
+ :country => CA[:country],
105
+ :hostname => CA[:hostname],
106
+ :domainname => CA[:domainname],
107
+ :ca_cert => 'ca.cert',
108
+ :ca_key => 'ca.key'
109
+ }
110
+
111
+ cert = create_cert(OPTS)
112
+ File.open('client.key', 'w') { |fd| fd.puts cert[:key] }
113
+ File.open('client.cert', 'w') { |fd| fd.puts cert[:cert].to_pem }
114
+
115
+ cert = create_cert(OPTS)
116
+ File.open('server.key', 'w') { |fd| fd.puts cert[:key] }
117
+ File.open('server.cert', 'w') { |fd| fd.puts cert[:cert].to_pem }
@@ -0,0 +1,150 @@
1
+ module NetworkFacade
2
+ def self.log=(log)
3
+ @@log = log.is_a?(IO) ? Logger.new(log) : log
4
+ end
5
+
6
+ def self.log(level, msg, context = nil)
7
+ return unless defined? @@log
8
+ if msg.is_a? Array
9
+ msg.each { |l| @@log << " #{l}\n"}
10
+ elsif msg.is_a? Exception
11
+ @@log << " #{msg.message} (#{msg.class})\n"
12
+ msg.backtrace.each { |l| @@log << " #{l}\n"}
13
+ else
14
+ if context.nil?
15
+ @@log.send(level, msg)
16
+ else
17
+ @@log.send(level, context, &Proc.new { msg })
18
+ end
19
+ end
20
+ end
21
+
22
+ module Base
23
+
24
+ class Client
25
+ def self.uri=(uri)
26
+ @@uri = uri
27
+ end
28
+
29
+ def self.inherited(klass)
30
+ @@klass ||= {}
31
+ if defined? @@uri and not @@uri.nil?
32
+ @@klass[klass] = URI.parse(@@uri)
33
+ @@klass[klass].path = '/' + klass.name.downcase
34
+ NetworkFacade.log(:debug, "#{klass} is bound to #{@@klass[klass]}")
35
+ end
36
+ @@uri = nil
37
+ end
38
+
39
+ def initialize(options = {})
40
+ @options = options
41
+ @uri ||= @options[:uri] || @@klass[self.class] ||
42
+ URI::Generic.new('nf', nil, nil, nil, nil, '/' + self.class.name.downcase, nil, nil, nil)
43
+ @uri.host = @options[:host] if @options[:host]
44
+ @uri.port = @options[:port] if @options[:port]
45
+ @uri.path = @options[:path] if @options[:path]
46
+ @uri.query = @options[:query] if @options[:query]
47
+ @uri.userinfo = @options[:userinfo] if @options[:userinfo]
48
+ @mutex = Mutex.new
49
+ end
50
+
51
+ def method_missing(name, *args)
52
+ NetworkFacade.log(:debug, "Method called with #{args.inspect}", "#{self.class}##{name}")
53
+ begin
54
+ data = Marshal.dump([@uri.path[1..-1], name, args])
55
+ size = [data.size].pack('N')
56
+ @client.write(size)
57
+ @client.write(data)
58
+ size = @client.read(4).unpack('N').first
59
+ data = @client.read(size)
60
+ result = Marshal.load(data)
61
+ if result.is_a? Exception
62
+ NetworkFacade.log(:info, "Exception occured : #{result.inspect}", "#{self.class}##{name}")
63
+ result.backtrace.collect! do |line|
64
+ @uri.to_s + '/' + line
65
+ end
66
+ raise result
67
+ end
68
+ result
69
+ rescue Errno::EPIPE, EOFError, Errno::EINVAL, Errno::ECONNRESET
70
+ NetworkFacade.log(:warn, "#{$!.inspect} occured, re-connecting...", "#{self.class}##{name}")
71
+ connect
72
+ retry
73
+ end
74
+ end
75
+ end
76
+
77
+ class Server
78
+ def initialize(options = {})
79
+ @options = options
80
+ @fd = [@options[:server]]
81
+ @objs = {}
82
+ end
83
+
84
+ def accept
85
+ NetworkFacade.log(:info, "Accepting new client")
86
+ raise "Default Server#accept method"
87
+ end
88
+
89
+ def add(obj)
90
+ id = obj.class.name.downcase
91
+ NetworkFacade.log(:info, "Adding new object #{obj.inspect} at /#{id}")
92
+ @objs[id] = obj
93
+ self
94
+ end
95
+
96
+ def client_id(client)
97
+ "0x%08x" % client.object_id
98
+ end
99
+
100
+ def start
101
+ loop do
102
+ readable, writable, errors, timeout = IO.select(@fd)
103
+ begin
104
+ if readable.include?(@options[:server])
105
+ accept
106
+ readable.delete(@options[:server])
107
+ end
108
+ rescue Exception
109
+ NetworkFacade.log(:warn, "An error occured when accapting new client")
110
+ NetworkFacade.log(:warn, $!)
111
+ next
112
+ end
113
+
114
+ readable.each do |client|
115
+ size = nil
116
+ data = nil
117
+ begin
118
+ size = client.read(4)
119
+ raise EOFError if size.nil?
120
+ size = size.unpack('N').first
121
+ data = Marshal.load(client.read(size))
122
+ result = nil
123
+ begin
124
+ if @objs[data[0]].respond_to? data[1]
125
+ NetworkFacade.log(:info, "Call method #{data[1].inspect} with #{data[2].inspect}", client_id(client))
126
+ result = @objs[data[0]].send(data[1], *data[2])
127
+ else
128
+ NetworkFacade.log(:info, "Call unknown method #{data[1].inspect}", client_id(client))
129
+ end
130
+ rescue Exception
131
+ result = $!
132
+ NetworkFacade.log(:info, "Error occured when executing #{data[1].inspect} with #{data[2].inspect}", client_id(client))
133
+ NetworkFacade.log(:info, $!)
134
+ end
135
+ result = Marshal.dump(result)
136
+ client.write([result.size].pack('N'))
137
+ client.write(result)
138
+ rescue Exception
139
+ NetworkFacade.log(:info, "Close connection", client_id(client))
140
+ client.close
141
+ @fd.delete(client)
142
+ GC.start
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end
148
+
149
+ end
150
+ end
@@ -0,0 +1,10 @@
1
+ module NetworkFacade
2
+ NAME = 'Network-Facade'
3
+ VERSION = '0.1'
4
+ COPYRIGHT = 'Copyright (C) 2007 Florent Solt'
5
+ DESC = 'Object-oriented netwotk facade'
6
+ AUTHOR = 'Florent Solt'
7
+ EMAIL = 'florent@solt.biz'
8
+ HOMEPAGE = 'http://network-facade.rubyforge.org'
9
+ LICENSE = 'BSD'
10
+ end
@@ -0,0 +1,14 @@
1
+ module NetworkFacade
2
+
3
+ def self.Client(uri = nil)
4
+ TCP::Client.uri = uri
5
+ TCP::Client
6
+ end
7
+
8
+ class Client < TCP::Client
9
+ end
10
+
11
+ class Server < TCP::Server
12
+ end
13
+
14
+ end
@@ -0,0 +1,55 @@
1
+ require 'openssl'
2
+
3
+ module NetworkFacade
4
+ class SSL
5
+
6
+ def self.Client(uri = nil)
7
+ Client.uri = uri
8
+ Client
9
+ end
10
+
11
+ PORT = 5043
12
+
13
+ class Client < Base::Client
14
+ def initialize(options = {})
15
+ [:key, :cert, :ca].each do |o|
16
+ raise "Missing option #{o}" if options[o].nil?
17
+ raise "File does not exists #{options[o]}" unless File.exists?(options[o])
18
+ end
19
+ super
20
+ @ctx = OpenSSL::SSL::SSLContext.new
21
+ @ctx.key = OpenSSL::PKey::RSA.new File.read(@options[:key])
22
+ @ctx.cert = OpenSSL::X509::Certificate.new File.read(@options[:cert])
23
+ @ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
24
+ @ctx.ca_file = @options[:ca]
25
+ @client = TCPSocket.new(@uri.host || 'localhost', @uri.port || PORT)
26
+ @client = OpenSSL::SSL::SSLSocket.new(@client, @ctx)
27
+ end
28
+ end
29
+
30
+ class Server < TCP::Server
31
+ def initialize(options = {})
32
+ if options[:server].nil?
33
+ [:key, :cert, :ca].each do |o|
34
+ raise "Missing option #{o}" if options[o].nil?
35
+ raise "File does not exists #{options[o]}" unless File.exists?(options[o])
36
+ end
37
+ options[:port] ||= PORT
38
+ options[:host] ||= '0.0.0.0'
39
+ @ctx = OpenSSL::SSL::SSLContext.new
40
+ @ctx.key = OpenSSL::PKey::RSA.new File.read(options[:key])
41
+ @ctx.cert = OpenSSL::X509::Certificate.new File.read(options[:cert])
42
+ @ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
43
+ @ctx.ca_file = options[:ca]
44
+ options[:server] = TCPServer.new(options[:host], options[:port])
45
+ @ssl = OpenSSL::SSL::SSLSocket.new(options[:server], @ctx)
46
+ options[:server] = @ssl.to_io
47
+ end
48
+ super(options)
49
+ end
50
+ end
51
+
52
+ end
53
+ end
54
+
55
+
@@ -0,0 +1,44 @@
1
+ module NetworkFacade
2
+ module TCP
3
+
4
+ def self.Client(uri = nil)
5
+ Client.uri = uri
6
+ Client
7
+ end
8
+
9
+ PORT = 5042
10
+
11
+ class Client < Base::Client
12
+ def initialize(options = {})
13
+ super
14
+ @options[:no_delay] ||= true
15
+ @client ||= TCPSocket.new(@uri.host || 'localhost', @uri.port || PORT)
16
+ @client.setsockopt(Socket::SOL_TCP, Socket::TCP_NODELAY, 1) if @options[:no_delay]
17
+ end
18
+ end
19
+
20
+ class Server < Base::Server
21
+ def initialize(options = {})
22
+ options[:port] ||= PORT
23
+ options[:host] ||= '0.0.0.0'
24
+ options[:no_delay] ||= true
25
+ options[:close_exec] ||= true
26
+ options[:server] ||= TCPServer.new(options[:host], options[:port])
27
+ super(options)
28
+ end
29
+
30
+ def accept
31
+ client = @options[:server].accept
32
+ NetworkFacade.log(:info, "Accept", client.peeraddr[2])
33
+ client.setsockopt(Socket::SOL_TCP, Socket::TCP_NODELAY, 1) if @options[:no_delay]
34
+ client.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if @options[:close_exec]
35
+ @fd << client
36
+ end
37
+
38
+ def client_id(client)
39
+ client.peeraddr[2]
40
+ end
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,31 @@
1
+ module NetworkFacade
2
+ module Unix
3
+
4
+ PATH = '/tmp/nf-socket'
5
+
6
+ class Client < Base::Client
7
+ def initialize(options = {})
8
+ super
9
+ options[:path] ||= PATH
10
+ @client = UNIXSocket.open(options[:path])
11
+ end
12
+ end
13
+
14
+ class Server < Base::Server
15
+ def initialize(options = {})
16
+ options[:path] ||= PATH
17
+ options[:close_exec] ||= true
18
+ File.unlink(PATH)
19
+ options[:server] ||= UNIXServer.open(options[:path])
20
+ super(options)
21
+ end
22
+
23
+ def accept
24
+ client = @options[:server].accept
25
+ client.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if @options[:close_exec]
26
+ @fd << client
27
+ end
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,66 @@
1
+ require 'socket'
2
+ require 'uri'
3
+ require 'fcntl'
4
+ require 'thread'
5
+ require 'logger'
6
+ require 'network-facade/config'
7
+ require 'network-facade/base'
8
+ require 'network-facade/tcp'
9
+ require 'network-facade/unix'
10
+ require 'network-facade/ssl'
11
+ require 'network-facade/defaults'
12
+
13
+ if __FILE__ == $0
14
+ NetworkFacade.log = STDERR
15
+
16
+ case ARGV.first
17
+ #=======================<client>==============================#
18
+ when 'client-tcp-uri'
19
+ class Foo < NetworkFacade::Client 'nf://backoffice:5042/?hu=dtc'
20
+ end
21
+ f = Foo.new
22
+ p f.bar
23
+ when 'client-tcp-class'
24
+ class Foo < NetworkFacade::Client
25
+ end
26
+ f = Foo.new(:host => 'dev', :port => 5042)
27
+ p f.bar
28
+ when 'client-unix'
29
+ class Foo < NetworkFacade::Unix::Client
30
+ end
31
+ f = Foo.new
32
+ p f.bar
33
+ when 'client-ssl'
34
+ class Foo < NetworkFacade::SSL::Client 'nf://installclick:5044'
35
+ end
36
+ f = Foo.new(:ca => '../cert/ca.cert',
37
+ :cert => '../cert/client.cert',
38
+ :key => '../cert/client.key')
39
+ p f.bar
40
+ #=======================</client>=============================#
41
+ else
42
+ class Foo
43
+ def bar
44
+ 42
45
+ end
46
+ def error
47
+ raise "Error"
48
+ end
49
+ end
50
+ case ARGV.first
51
+ #=======================<server>==============================#
52
+ when 'server-tcp'
53
+ NetworkFacade::Server.new.add(Foo.new).start
54
+ when 'server-unix'
55
+ NetworkFacade::Unix::Server.new.add(Foo.new).start
56
+ when 'server-ssl'
57
+ s = NetworkFacade::SSL::Server.new(
58
+ :port => 5044,
59
+ :ca => '../cert/ca.cert',
60
+ :cert => '../cert/server.cert',
61
+ :key => '../cert/server.key')
62
+ s.add(Foo.new).start
63
+ #=======================</server>=============================#
64
+ end
65
+ end
66
+ end
metadata ADDED
@@ -0,0 +1,60 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.2
3
+ specification_version: 1
4
+ name: network-facade
5
+ version: !ruby/object:Gem::Version
6
+ version: "0.1"
7
+ date: 2007-05-02 00:00:00 +02:00
8
+ summary: Object-oriented netwotk facade
9
+ require_paths:
10
+ - lib
11
+ email: florent@solt.biz
12
+ homepage: http://network-facade.rubyforge.org
13
+ rubyforge_project:
14
+ description:
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: false
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Florent Solt
31
+ files:
32
+ - lib/network-facade/unix.rb
33
+ - lib/network-facade/tcp.rb
34
+ - lib/network-facade/config.rb
35
+ - lib/network-facade/base.rb
36
+ - lib/network-facade/defaults.rb
37
+ - lib/network-facade/ssl.rb
38
+ - lib/network-facade.rb
39
+ test_files: []
40
+
41
+ rdoc_options: []
42
+
43
+ extra_rdoc_files: []
44
+
45
+ executables:
46
+ - network-facade-ssl
47
+ extensions: []
48
+
49
+ requirements: []
50
+
51
+ dependencies:
52
+ - !ruby/object:Gem::Dependency
53
+ name: xmlobject
54
+ version_requirement:
55
+ version_requirements: !ruby/object:Gem::Version::Requirement
56
+ requirements:
57
+ - - ">"
58
+ - !ruby/object:Gem::Version
59
+ version: 0.0.0
60
+ version: