oversip 0.9.0

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.
Files changed (121) hide show
  1. data/AUTHORS.txt +11 -0
  2. data/LICENSE.txt +22 -0
  3. data/README.md +16 -0
  4. data/Rakefile +55 -0
  5. data/bin/oversip +182 -0
  6. data/ext/common/c_util.h +74 -0
  7. data/ext/common/ruby_c_util.h +88 -0
  8. data/ext/sip_parser/common_headers.h +209 -0
  9. data/ext/sip_parser/ext_help.h +18 -0
  10. data/ext/sip_parser/extconf.rb +3 -0
  11. data/ext/sip_parser/sip_parser.c +29649 -0
  12. data/ext/sip_parser/sip_parser.h +227 -0
  13. data/ext/sip_parser/sip_parser_ruby.c +1292 -0
  14. data/ext/stud/extconf.rb +27 -0
  15. data/ext/stud/stud.tar.gz +0 -0
  16. data/ext/stun/ext_help.h +16 -0
  17. data/ext/stun/extconf.rb +3 -0
  18. data/ext/stun/stun_ruby.c +391 -0
  19. data/ext/utils/ext_help.h +14 -0
  20. data/ext/utils/extconf.rb +3 -0
  21. data/ext/utils/haproxy_protocol.c +6163 -0
  22. data/ext/utils/haproxy_protocol.h +27 -0
  23. data/ext/utils/ip_utils.c +5952 -0
  24. data/ext/utils/ip_utils.h +61 -0
  25. data/ext/utils/outbound_utils.c +3227 -0
  26. data/ext/utils/outbound_utils.h +27 -0
  27. data/ext/utils/utils_ruby.c +384 -0
  28. data/ext/utils/utils_ruby.h +75 -0
  29. data/ext/websocket_framing_utils/ext_help.h +18 -0
  30. data/ext/websocket_framing_utils/extconf.rb +3 -0
  31. data/ext/websocket_framing_utils/ws_framing_utils.h +46 -0
  32. data/ext/websocket_framing_utils/ws_framing_utils_ruby.c +135 -0
  33. data/ext/websocket_http_parser/ext_help.h +18 -0
  34. data/ext/websocket_http_parser/extconf.rb +3 -0
  35. data/ext/websocket_http_parser/ws_http_parser.c +2598 -0
  36. data/ext/websocket_http_parser/ws_http_parser.h +86 -0
  37. data/ext/websocket_http_parser/ws_http_parser_ruby.c +630 -0
  38. data/lib/oversip/config.rb +541 -0
  39. data/lib/oversip/config_validators.rb +126 -0
  40. data/lib/oversip/errors.rb +7 -0
  41. data/lib/oversip/fiber_pool.rb +56 -0
  42. data/lib/oversip/launcher.rb +507 -0
  43. data/lib/oversip/logger.rb +170 -0
  44. data/lib/oversip/master_process.rb +67 -0
  45. data/lib/oversip/posix_mq.rb +121 -0
  46. data/lib/oversip/proxies_config.rb +169 -0
  47. data/lib/oversip/ruby_ext/eventmachine.rb +38 -0
  48. data/lib/oversip/sip/client_transaction.rb +587 -0
  49. data/lib/oversip/sip/constants.rb +87 -0
  50. data/lib/oversip/sip/grammar/name_addr.rb +27 -0
  51. data/lib/oversip/sip/grammar/uri.rb +116 -0
  52. data/lib/oversip/sip/launcher.rb +180 -0
  53. data/lib/oversip/sip/listeners/ipv4_tcp_client.rb +21 -0
  54. data/lib/oversip/sip/listeners/ipv4_tcp_server.rb +21 -0
  55. data/lib/oversip/sip/listeners/ipv4_tls_client.rb +21 -0
  56. data/lib/oversip/sip/listeners/ipv4_tls_server.rb +21 -0
  57. data/lib/oversip/sip/listeners/ipv4_tls_tunnel_server.rb +21 -0
  58. data/lib/oversip/sip/listeners/ipv4_udp_server.rb +20 -0
  59. data/lib/oversip/sip/listeners/ipv6_tcp_client.rb +21 -0
  60. data/lib/oversip/sip/listeners/ipv6_tcp_server.rb +21 -0
  61. data/lib/oversip/sip/listeners/ipv6_tls_client.rb +21 -0
  62. data/lib/oversip/sip/listeners/ipv6_tls_server.rb +21 -0
  63. data/lib/oversip/sip/listeners/ipv6_tls_tunnel_server.rb +21 -0
  64. data/lib/oversip/sip/listeners/ipv6_udp_server.rb +20 -0
  65. data/lib/oversip/sip/listeners/reactor.rb +39 -0
  66. data/lib/oversip/sip/listeners/tcp_client.rb +73 -0
  67. data/lib/oversip/sip/listeners/tcp_reactor.rb +185 -0
  68. data/lib/oversip/sip/listeners/tcp_server.rb +71 -0
  69. data/lib/oversip/sip/listeners/tls_client.rb +117 -0
  70. data/lib/oversip/sip/listeners/tls_server.rb +70 -0
  71. data/lib/oversip/sip/listeners/tls_tunnel_reactor.rb +113 -0
  72. data/lib/oversip/sip/listeners/tls_tunnel_server.rb +61 -0
  73. data/lib/oversip/sip/listeners/udp_reactor.rb +213 -0
  74. data/lib/oversip/sip/listeners.rb +28 -0
  75. data/lib/oversip/sip/logic.rb +14 -0
  76. data/lib/oversip/sip/message.rb +168 -0
  77. data/lib/oversip/sip/message_processor.rb +202 -0
  78. data/lib/oversip/sip/modules/core.rb +200 -0
  79. data/lib/oversip/sip/modules/registrar_without_path.rb +75 -0
  80. data/lib/oversip/sip/modules/user_assertion.rb +123 -0
  81. data/lib/oversip/sip/proxy.rb +460 -0
  82. data/lib/oversip/sip/request.rb +128 -0
  83. data/lib/oversip/sip/response.rb +30 -0
  84. data/lib/oversip/sip/rfc3263.rb +646 -0
  85. data/lib/oversip/sip/server_transaction.rb +295 -0
  86. data/lib/oversip/sip/sip.rb +74 -0
  87. data/lib/oversip/sip/tags.rb +39 -0
  88. data/lib/oversip/sip/timers.rb +55 -0
  89. data/lib/oversip/sip/transport_manager.rb +129 -0
  90. data/lib/oversip/syslogger_process.rb +119 -0
  91. data/lib/oversip/tls.rb +179 -0
  92. data/lib/oversip/utils.rb +25 -0
  93. data/lib/oversip/version.rb +23 -0
  94. data/lib/oversip/websocket/constants.rb +56 -0
  95. data/lib/oversip/websocket/default_policy.rb +19 -0
  96. data/lib/oversip/websocket/http_request.rb +63 -0
  97. data/lib/oversip/websocket/launcher.rb +207 -0
  98. data/lib/oversip/websocket/listeners/ipv4_tcp_server.rb +15 -0
  99. data/lib/oversip/websocket/listeners/ipv4_tls_server.rb +15 -0
  100. data/lib/oversip/websocket/listeners/ipv4_tls_tunnel_server.rb +15 -0
  101. data/lib/oversip/websocket/listeners/ipv6_tcp_server.rb +15 -0
  102. data/lib/oversip/websocket/listeners/ipv6_tls_server.rb +15 -0
  103. data/lib/oversip/websocket/listeners/ipv6_tls_tunnel_server.rb +15 -0
  104. data/lib/oversip/websocket/listeners/tcp_server.rb +265 -0
  105. data/lib/oversip/websocket/listeners/tls_server.rb +69 -0
  106. data/lib/oversip/websocket/listeners/tls_tunnel_server.rb +100 -0
  107. data/lib/oversip/websocket/listeners.rb +12 -0
  108. data/lib/oversip/websocket/ws_app.rb +75 -0
  109. data/lib/oversip/websocket/ws_apps/ipv4_ws_sip_app.rb +21 -0
  110. data/lib/oversip/websocket/ws_apps/ipv4_wss_sip_app.rb +21 -0
  111. data/lib/oversip/websocket/ws_apps/ipv6_ws_sip_app.rb +21 -0
  112. data/lib/oversip/websocket/ws_apps/ipv6_wss_sip_app.rb +22 -0
  113. data/lib/oversip/websocket/ws_apps/ws_autobahn_app.rb +23 -0
  114. data/lib/oversip/websocket/ws_apps/ws_sip_app.rb +156 -0
  115. data/lib/oversip/websocket/ws_apps.rb +9 -0
  116. data/lib/oversip/websocket/ws_framing.rb +597 -0
  117. data/lib/oversip.rb +59 -0
  118. data/test/oversip_test_helper.rb +20 -0
  119. data/test/test_http_parser.rb +73 -0
  120. data/test/test_sip_parser.rb +139 -0
  121. metadata +256 -0
@@ -0,0 +1,170 @@
1
+ module OverSIP
2
+
3
+ # Logging client module. Any class desiring to log messages must include (or extend) this module.
4
+ # In order to identify itself in the logs, the class can define log_ig() method or set @log_id
5
+ # attribute.
6
+ module Logger
7
+
8
+ SYSLOG_POSIXMQ_MAPPING = {
9
+ "debug" => 0,
10
+ "info" => 1,
11
+ "notice" => 2,
12
+ "warn" => 3,
13
+ "error" => 4,
14
+ "crit" => 5,
15
+ "alert" => 6,
16
+ "emerg" => 7
17
+ }
18
+
19
+ def self.init_logger_mq(group = nil)
20
+ OverSIP.syslogger_mq_name = "/#{OverSIP.master_name}_syslogger"
21
+
22
+ @@logger_mq = ::OverSIP::PosixMQ.create_queue({
23
+ :name => ::OverSIP.syslogger_mq_name,
24
+ :mode => :write,
25
+ :maxmsg => 1000,
26
+ :msgsize => 2000,
27
+ :group => group
28
+ })
29
+ end
30
+
31
+
32
+ def self.load_methods
33
+ begin
34
+ @@threshold = SYSLOG_POSIXMQ_MAPPING[::OverSIP.configuration[:core][:syslog_level]]
35
+ rescue
36
+ @@threshold = 0 # debug.
37
+ end
38
+
39
+ $oversip_debug = ( @@threshold == 0 ? true : false )
40
+
41
+ @@congested = false
42
+
43
+ SYSLOG_POSIXMQ_MAPPING.each do |level, level_value|
44
+ method_str = "
45
+ def log_system_#{level}(msg)
46
+ "
47
+
48
+ if ::OverSIP.syslogger_ready?
49
+ method_str << "
50
+ return false if @@threshold > #{level_value} || @@congested
51
+ begin
52
+ unless @@logger_mq.trysend ::OverSIP::Logger.syslog_system_msg2str(#{level_value}, msg, log_id), 0
53
+ @@congested = true
54
+ EM.add_timer(1) do
55
+ @@logger_mq.trysend ::OverSIP::Logger.syslog_system_msg2str(4, \"logger message queue was full, some logs have been lost\", log_id), 1
56
+ @@congested = false
57
+ end
58
+ end
59
+ rescue Errno::EMSGSIZE
60
+ @@logger_mq.trysend ::OverSIP::Logger.syslog_system_msg2str(4, \"too long message could not be logged\", log_id), 1 rescue nil
61
+ rescue => e
62
+ @@logger_mq.trysend ::OverSIP::Logger.syslog_system_msg2str(4, \"unexpected logging error (\#{e.class}: \#{e.message})\", log_id), 1 rescue nil
63
+ end
64
+ "
65
+ end
66
+
67
+ unless ::OverSIP.daemonized?
68
+ if %w{debug info notice}.include? level
69
+ method_str << "
70
+ puts ::OverSIP::Logger.fg_system_msg2str('#{level}', msg, log_id)
71
+ "
72
+ else
73
+ method_str << "
74
+ $stderr.puts ::OverSIP::Logger.fg_system_msg2str('#{level}', msg, log_id)
75
+ "
76
+ end
77
+ end
78
+
79
+ method_str << "end"
80
+
81
+ self.module_eval method_str
82
+
83
+
84
+ if ::OverSIP.syslogger_ready?
85
+ # User/script logs.
86
+ method_str = "
87
+ def log_#{level}(msg)
88
+ return false if @@threshold > #{level_value} || @@congested
89
+ begin
90
+ unless @@logger_mq.trysend ::OverSIP::Logger.syslog_user_msg2str(#{level_value}, msg, log_id), 0
91
+ @@congested = true
92
+ EM.add_timer(1) do
93
+ @@logger_mq.trysend ::OverSIP::Logger.syslog_user_msg2str(4, \"logger message queue was full, some logs have been lost\", log_id), 1
94
+ @@congested = false
95
+ end
96
+ end
97
+ rescue Errno::EMSGSIZE
98
+ @@logger_mq.trysend ::OverSIP::Logger.syslog_user_msg2str(4, \"too long message could not be logged\", log_id), 1 rescue nil
99
+ rescue => e
100
+ @@logger_mq.trysend ::OverSIP::Logger.syslog_user_msg2str(4, \"unexpected logging error (\#{e.class}: \#{e.message})\", log_id), 1 rescue nil
101
+ end
102
+ end
103
+ "
104
+
105
+ self.module_eval method_str
106
+ end
107
+
108
+ end # .each
109
+
110
+ # A convenient method to ensure that fatal logs are properly logged and program
111
+ # exited with error status.
112
+ def fatal msg
113
+ log_system_crit msg
114
+ log_system_crit "exiting with error status"
115
+
116
+ ::OverSIP::Launcher.terminate error=true
117
+ end
118
+ end
119
+
120
+ # Generate nice log messages. It accepst three parameters:
121
+ # - level_value: Integer representing the log level.
122
+ # - msg: the String or Exception to be logged.
123
+ # - log_id: a String helping to identify the generator of this log message.
124
+ def self.syslog_system_msg2str(level_value, msg, log_id)
125
+ case msg
126
+ when ::String
127
+ level_value.to_s << "<" << log_id << "> " << msg
128
+ when ::Exception
129
+ "#{level_value}<#{log_id}> #{msg.message} (#{msg.class })\n#{(msg.backtrace || [])[0..3].join("\n")}"
130
+ else
131
+ level_value.to_s << "<" << log_id << "> " << msg.inspect
132
+ end
133
+ end
134
+
135
+ def self.syslog_user_msg2str(level_value, msg, log_id)
136
+ case msg
137
+ when ::String
138
+ level_value.to_s << "<" << log_id << "> script: " << msg
139
+ when ::Exception
140
+ "#{level_value}<#{log_id}> script: #{msg.message} (#{msg.class })\n#{(msg.backtrace || [])[0..3].join("\n")}"
141
+ else
142
+ level_value.to_s << "<" << log_id << "> script: " << msg.inspect
143
+ end
144
+ end
145
+
146
+ def self.fg_system_msg2str(level, msg, log_id)
147
+ case msg
148
+ when ::String
149
+ "#{level.upcase}: <#{log_id}> " << msg
150
+ when ::Exception
151
+ "#{level.upcase}: <#{log_id}> #{msg.message} (#{msg.class })\n#{(msg.backtrace || [])[0..3].join("\n")}"
152
+ else
153
+ "#{level.upcase}: <#{log_id}> " << msg.inspect
154
+ end
155
+ end
156
+
157
+ def self.close
158
+ @@logger_mq.close rescue nil
159
+ @@logger_mq.unlink rescue nil
160
+ end
161
+
162
+ # Default logging identifier is the class name. If log_id() method is redefined by the
163
+ # class including this module, or it sets @log_id, then such value takes preference.
164
+ def log_id
165
+ @log_id ||= self.class.name
166
+ end
167
+
168
+ end # module Logger
169
+
170
+ end
@@ -0,0 +1,67 @@
1
+ # Ruby built-in libraries.
2
+
3
+ require "base64"
4
+ require "digest/md5"
5
+ require "digest/sha1"
6
+ require "securerandom"
7
+ require "fiber"
8
+ require "openssl"
9
+
10
+
11
+ # Ruby external gems.
12
+
13
+ gem "eventmachine-le", ">= 1.1.0"
14
+ require "eventmachine-le"
15
+
16
+ gem "iobuffer", ">= 1.1.2"
17
+ require "iobuffer"
18
+ gem "em-udns", ">= 0.3.6"
19
+ require "em-udns"
20
+ gem "escape_utils", ">= 0.2.4"
21
+ require "escape_utils"
22
+ gem "posix-spawn", ">= 0.3.6"
23
+ require "posix-spawn"
24
+
25
+
26
+ # OverSIP files.
27
+
28
+ require "oversip/ruby_ext/eventmachine.rb"
29
+
30
+ require "oversip/sip/sip.rb"
31
+ require "oversip/sip/sip_parser.so"
32
+ require "oversip/sip/constants.rb"
33
+ require "oversip/sip/message.rb"
34
+ require "oversip/sip/request.rb"
35
+ require "oversip/sip/response.rb"
36
+ require "oversip/sip/grammar/uri.rb"
37
+ require "oversip/sip/grammar/name_addr.rb"
38
+ require "oversip/sip/message_processor.rb"
39
+ require "oversip/sip/listeners.rb"
40
+ require "oversip/sip/launcher.rb"
41
+ require "oversip/sip/server_transaction.rb"
42
+ require "oversip/sip/client_transaction.rb"
43
+ require "oversip/sip/transport_manager.rb"
44
+ require "oversip/sip/timers.rb"
45
+ require "oversip/sip/tags.rb"
46
+ require "oversip/sip/rfc3263.rb"
47
+ require "oversip/sip/logic.rb"
48
+ require "oversip/sip/proxy.rb"
49
+
50
+ require "oversip/websocket/ws_http_parser.so"
51
+ require "oversip/websocket/constants.rb"
52
+ require "oversip/websocket/http_request.rb"
53
+ require "oversip/websocket/default_policy.rb"
54
+ require "oversip/websocket/listeners.rb"
55
+ require "oversip/websocket/launcher.rb"
56
+ require "oversip/websocket/ws_framing_utils.so"
57
+ require "oversip/websocket/ws_framing.rb"
58
+ require "oversip/websocket/ws_app.rb"
59
+ require "oversip/websocket/ws_apps.rb"
60
+
61
+ require "oversip/fiber_pool.rb"
62
+ require "oversip/tls.rb"
63
+ require "oversip/stun.so"
64
+
65
+ require "oversip/sip/modules/core.rb"
66
+ require "oversip/sip/modules/user_assertion.rb"
67
+ require "oversip/sip/modules/registrar_without_path.rb"
@@ -0,0 +1,121 @@
1
+ module OverSIP
2
+
3
+ class PosixMQ
4
+
5
+ extend ::OverSIP::Logger
6
+
7
+ def self.create_queue options={}
8
+ @log_id = "PosixMQ #{options[:name]}"
9
+ @total_size ||= 0
10
+
11
+ # Queue attributes.
12
+ mq_name = options[:name]
13
+ mq_mode = case options[:mode]
14
+ when :read then IO::RDONLY
15
+ when :write then IO::WRONLY
16
+ when :read_write then IO::RDWR
17
+ end
18
+ mq_group = options[:group]
19
+ mq_attr = ::POSIX_MQ::Attr.new
20
+ # NOTE: maximun value for maxmsg is 65536.
21
+ mq_attr.maxmsg = options[:maxmsg]
22
+ mq_attr.msgsize = options[:msgsize]
23
+ mq_attr.flags = 0
24
+ mq_attr.curmsgs = 0
25
+
26
+ # Delete the queue if it exists.
27
+ begin
28
+ ::POSIX_MQ.unlink mq_name
29
+ rescue ::Errno::ENOENT
30
+ rescue ::Errno::EACCES => e
31
+ fatal "queue already exists and cannot remove it due file permissions"
32
+ end
33
+
34
+ # Set the UMASK in a way that the group has permission to delete the queue.
35
+ orig_umask = File.umask(0007)
36
+
37
+ # Change the effective group for the Posix queue. Keep the original
38
+ # group.
39
+ orig_gid = Process::GID.eid
40
+ if mq_group
41
+ gid = Etc.getgrnam(mq_group).gid
42
+ Process::GID.change_privilege(gid)
43
+ end
44
+
45
+ ### TODO: Este tamaño debe multiplicarse por el num de queues!
46
+ # System limits required size (ulimit -q).
47
+ mq_size = case 1.size
48
+ # 32 bits OS.
49
+ when 4 then mq_attr.maxmsg * 4 + mq_attr.maxmsg * mq_attr.msgsize
50
+ # 64 bits OS.
51
+ when 8 then mq_attr.maxmsg * 8 + mq_attr.maxmsg * mq_attr.msgsize
52
+ end
53
+ log_system_debug "queue requires #{mq_size} bytes" if $oversip_debug
54
+
55
+ # Set RLIMIT_MSGQUEUE (ulimit) in order to create the queue with required
56
+ # ammount of memory.
57
+ @total_size += mq_size
58
+ if ( current_rlimit = ::Process.getrlimit(12)[1] ) < @total_size
59
+ log_system_debug "incrementing rlimits (currently #{current_rlimit} bytes) to #{@total_size} bytes (ulimit -q)" if $oversip_debug
60
+ begin
61
+ ::Process.setrlimit(12, @total_size)
62
+ rescue Errno::EPERM
63
+ fatal "current user has no permissions to increase rlimits to #{@total_size} bytes (ulimit -q)"
64
+ end
65
+ end
66
+
67
+ # Create the Posix message queue to write into it.
68
+ # - IO::WRONLY => Just write.
69
+ # - IO::CREAT => Create if it doesn't exist.
70
+ # - IO::EXCL => Raise if the queue already exists.
71
+ # - IO::NONBLOCK => Don't block when sending (instead raise Errno::EAGAIN).
72
+ # - mode: 00660 => User and group can write and read.
73
+ # - mq_attr => Set maxmsg and msgsize.
74
+ begin
75
+ mq = ::POSIX_MQ.new mq_name, mq_mode | IO::CREAT | IO::EXCL | IO::NONBLOCK, 00660, mq_attr
76
+
77
+ # Kernel has no support for posix message queues.
78
+ rescue Errno::ENOSYS => e
79
+ fatal "the kernel has no support for posix messages queues, enable it (#{e.class}: #{e.message})"
80
+
81
+ # http://linux.die.net/man/3/mq_open
82
+ #
83
+ # O_CREAT was specified in oflag, and attr was not NULL, but attr->mq_maxmsg or attr->mq_msqsize was
84
+ # invalid. Both of these fields must be greater than zero. In a process that is unprivileged (does not
85
+ # have the CAP_SYS_RESOURCE capability), attr->mq_maxmsg must be less than or equal to the msg_max
86
+ # limit, and attr->mq_msgsize must be less than or equal to the msgsize_max limit. In addition, even
87
+ # in a privileged process, attr->mq_maxmsg cannot exceed the HARD_MAX limit. (See mq_overview(7) for
88
+ # details of these limits.)
89
+ rescue Errno::EINVAL
90
+ log_system_warn "cannot set queue attributes due to user permissions, using system default values"
91
+ mq = ::POSIX_MQ.new mq_name, mq_mode | IO::CREAT | IO::NONBLOCK, 00660
92
+ rescue Errno::ENOMEM => e
93
+ fatal "insufficient memory (#{e.class}: #{e.message})"
94
+ rescue Errno::EMFILE => e
95
+ fatal "the process already has the maximum number of files and message queues open (#{e.class}: #{e.message})"
96
+ rescue Errno::ENFILE => e
97
+ fatal "the system limit on the total number of open files and message queues has been reached (#{e.class}: #{e.message})"
98
+ rescue Errno::ENOSPC => e
99
+ fatal "insufficient space for the creation of a new message queue, probably occurred because the queues_max limit was encountered (#{e.class}: #{e.message})"
100
+
101
+ end
102
+
103
+ # Recover the original Umask settings.
104
+ File.umask(orig_umask)
105
+
106
+ # Recover the original effective group.
107
+ Process::GID.change_privilege(orig_gid) if mq_group
108
+
109
+ if mq.attr.maxmsg == mq_attr.maxmsg and mq.attr.msgsize == mq_attr.msgsize
110
+ log_system_debug "maxmsg=#{mq.attr.maxmsg}, msgsize=#{mq.attr.msgsize}" if $oversip_debug
111
+ else
112
+ log_system_warn "maxmsg=#{mq.attr.maxmsg}, msgsize=#{mq.attr.msgsize}, " \
113
+ "but recommended values are maxmsg=#{mq_attr.maxmsg}, msgsize=#{mq_attr.msgsize}"
114
+ end
115
+
116
+ mq
117
+ end # self.create_queue
118
+
119
+ end # class PosixMQ
120
+
121
+ end
@@ -0,0 +1,169 @@
1
+ module OverSIP
2
+
3
+ module ProxiesConfig
4
+
5
+ extend ::OverSIP::Logger
6
+ extend ::OverSIP::Config::Validators
7
+
8
+ def self.log_id
9
+ @log_id ||= "ProxiesConfig"
10
+ end
11
+
12
+ @proxies = {}
13
+
14
+ @proxy_configuration = {
15
+ :do_loose_routing => true,
16
+ :use_dns => true,
17
+ :use_dns_cache => true,
18
+ :dns_cache_time => 300,
19
+ :use_naptr => true,
20
+ :use_srv => true,
21
+ :transport_preference => ["tls", "tcp", "udp"],
22
+ :force_transport_preference => false,
23
+ :ip_type_preference => ["ipv6", "ipv4"],
24
+ :dns_failover_on_503 => true,
25
+ :timer_B => 32,
26
+ :timer_C => 120,
27
+ :timer_F => 32,
28
+ :tls_validation => false
29
+ }
30
+
31
+ PROXY_CONFIG_VALIDATIONS = {
32
+ :do_loose_routing => :boolean,
33
+ :use_dns => :boolean,
34
+ :use_dns_cache => :boolean,
35
+ :dns_cache_time => [ :fixnum, [ :greater_equal_than, 300 ] ],
36
+ :use_naptr => :boolean,
37
+ :use_srv => :boolean,
38
+ :transport_preference => [ [ :choices, %w{tls tcp udp}], :multi_value, :non_empty ],
39
+ :force_transport_preference => :boolean,
40
+ :ip_type_preference => [ [ :choices, %w{ipv4 ipv6}], :multi_value, :non_empty ],
41
+ :dns_failover_on_503 => :boolean,
42
+ :timer_B => [ :fixnum, [ :greater_equal_than, 2 ], [ :minor_equal_than, 64 ] ],
43
+ :timer_C => [ :fixnum, [ :greater_equal_than, 8 ], [ :minor_equal_than, 180 ] ],
44
+ :timer_F => [ :fixnum, [ :greater_equal_than, 2 ], [ :minor_equal_than, 64 ] ],
45
+ :tls_validation => :boolean
46
+ }
47
+
48
+ def self.load proxies_yaml
49
+ unless proxies_yaml.is_a? Hash
50
+ fatal "invalid proxies configuration file, it is not a collection"
51
+ end
52
+
53
+ begin
54
+ proxies_yaml.each do |proxy, conf|
55
+ unless proxy.is_a? String
56
+ fatal "proxy name is not a string (#{proxy.inspect})"
57
+ end
58
+
59
+ @proxies[proxy.to_sym] = @proxy_configuration.dup
60
+ @proxies[proxy.to_sym].each do |parameter, default_value|
61
+ @proxies[proxy.to_sym][parameter] = default_value.clone rescue default_value
62
+ end
63
+
64
+ PROXY_CONFIG_VALIDATIONS.each do |parameter, validations|
65
+ values = proxies_yaml[proxy][parameter.to_s]
66
+ validations = [ validations ] unless validations.is_a?(Array)
67
+
68
+ if values == nil
69
+ if validations.include? :required
70
+ fatal "#{proxy}[#{parameter}] requires a value"
71
+ end
72
+ next
73
+ end
74
+
75
+ if values.is_a? Array
76
+ unless validations.include? :multi_value
77
+ fatal "#{proxy}[#{parameter}] does not allow multiple values"
78
+ end
79
+
80
+ if validations.include? :non_empty and values.empty?
81
+ fatal "#{proxy}[#{parameter}] does not allow empty values"
82
+ end
83
+ end
84
+
85
+ values = ( values.is_a?(Array) ? values : [ values ] )
86
+
87
+ values.each do |value|
88
+ validations.each do |validation|
89
+
90
+ if validation.is_a? Symbol
91
+ args = []
92
+ elsif validation.is_a? Array
93
+ args = validation[1..-1]
94
+ validation = validation[0]
95
+ end
96
+
97
+ next if [:required, :multi_value, :non_empty].include? validation
98
+
99
+ unless send validation, value, *args
100
+ fatal "#{proxy}[#{parameter}] has invalid value '#{::OverSIP::Config.humanize_value value}' (does not satisfy '#{validation}' validation requirement)"
101
+ end
102
+ end
103
+
104
+ @proxies[proxy.to_sym][parameter] = ( validations.include?(:multi_value) ? values : values[0] )
105
+ end
106
+
107
+ end # PROXY_CONFIG_VALIDATIONS[section].each
108
+ end # proxies_yaml.each
109
+
110
+ post_process
111
+
112
+ rescue OverSIP::ConfigurationError => e
113
+ fatal "proxies configuration error: #{e.message}"
114
+ rescue => e
115
+ fatal e
116
+ end
117
+
118
+ ::OverSIP.proxies = @proxies
119
+ end
120
+
121
+
122
+ def self.post_process
123
+ @proxies.each_key do |proxy|
124
+ # Add a string parameter with the proxy name itself.
125
+ @proxies[proxy][:name] = proxy.to_s
126
+
127
+ # If use_srv is not set then ensure use_naptr is also not set.
128
+ @proxies[proxy][:use_naptr] = false unless @proxies[proxy][:use_srv]
129
+
130
+ # Convert transport values into Symbols.
131
+ @proxies[proxy][:transport_preference] = @proxies[proxy][:transport_preference].map do |transport|
132
+ transport.to_sym
133
+ end
134
+
135
+ # Ensure there are not duplicate transports.
136
+ @proxies[proxy][:transport_preference].uniq!
137
+
138
+ # Remove transports that are not supported.
139
+ @proxies[proxy][:transport_preference].delete :tls unless ::OverSIP.configuration[:sip][:sip_tls]
140
+ @proxies[proxy][:transport_preference].delete :tcp unless ::OverSIP.configuration[:sip][:sip_tcp]
141
+ @proxies[proxy][:transport_preference].delete :udp unless ::OverSIP.configuration[:sip][:sip_udp]
142
+
143
+ # Convert IP type values into Symbols.
144
+ @proxies[proxy][:ip_type_preference] = @proxies[proxy][:ip_type_preference].map do |ip_type|
145
+ ip_type.to_sym
146
+ end
147
+
148
+ # Ensure there are not duplicate IP types.
149
+ @proxies[proxy][:ip_type_preference].uniq!
150
+
151
+ # Remove IP types that are not supported.
152
+ @proxies[proxy][:ip_type_preference].delete :ipv4 unless ::OverSIP.configuration[:sip][:listen_ipv4]
153
+ @proxies[proxy][:ip_type_preference].delete :ipv6 unless ::OverSIP.configuration[:sip][:listen_ipv6]
154
+
155
+ # Add new parameters for fast access.
156
+ @proxies[proxy][:has_sip_ipv4] = @proxies[proxy][:ip_type_preference].include?(:ipv4)
157
+ @proxies[proxy][:has_sip_ipv6] = @proxies[proxy][:ip_type_preference].include?(:ipv6)
158
+ @proxies[proxy][:has_sip_udp] = @proxies[proxy][:transport_preference].include?(:udp)
159
+ @proxies[proxy][:has_sip_tcp] = @proxies[proxy][:transport_preference].include?(:tcp)
160
+ @proxies[proxy][:has_sip_tls] = @proxies[proxy][:transport_preference].include?(:tls)
161
+
162
+ # Add a hash for the DNS cache.
163
+ @proxies[proxy][:dns_cache] = {} if @proxies[proxy][:use_dns_cache]
164
+ end
165
+ end
166
+
167
+ end
168
+
169
+ end
@@ -0,0 +1,38 @@
1
+ module EventMachine
2
+
3
+ # Fast method for setting an outgoing TCP connection.
4
+ def self.oversip_connect_tcp_server bind_addr, server, port, klass, *args
5
+ s = bind_connect_server bind_addr, 0, server, port
6
+ c = klass.new s, *args
7
+ @conns[s] = c
8
+ block_given? and yield c
9
+ c
10
+ end
11
+
12
+
13
+ class Connection
14
+
15
+ # We require Ruby 1.9 so don't check String#bytesize method.
16
+ def send_data data
17
+ ::EventMachine::send_data @signature, data, data.bytesize
18
+ end
19
+
20
+ def send_datagram data, address, port
21
+ ::EventMachine::send_datagram @signature, data, data.bytesize, address, port
22
+ end
23
+
24
+ # Rewrite close_connection so it set an internal attribute (which can be
25
+ # inspected when unbind() callback is called).
26
+ alias _em_close_connection close_connection
27
+ def close_connection after_writing=false
28
+ @local_closed = true
29
+ _em_close_connection after_writing
30
+ end
31
+
32
+ def close_connection_after_writing
33
+ close_connection true
34
+ end
35
+
36
+ end
37
+
38
+ end