network-facade 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: