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,213 @@
1
+ module OverSIP::SIP
2
+
3
+ class UdpReactor < Reactor
4
+
5
+ def receive_data data
6
+ @buffer << data
7
+
8
+ while (case @state
9
+ when :init
10
+ @parser.reset
11
+ @parser_nbytes = 0
12
+ @state = :message
13
+
14
+ when :message
15
+ parse_message
16
+
17
+ when :finished
18
+ # Invoke the custom logic for requests.
19
+ if @msg.request?
20
+ process_request
21
+ else
22
+ process_response
23
+ end
24
+ @state = :init
25
+ false
26
+ end)
27
+ end # while
28
+ end
29
+
30
+ def parse_message
31
+ return false if @buffer.empty?
32
+
33
+ buffer_str = @buffer.to_str
34
+
35
+ # Quikly ignore single CRLF (widely used by SIP UDP clients as keep-alive.
36
+ if buffer_str == CRLF
37
+ @buffer.clear
38
+ @state = :init
39
+ return false
40
+ end
41
+
42
+ begin
43
+ source_port, source_ip = ::Socket.unpack_sockaddr_in(get_peername)
44
+ rescue => e
45
+ log_system_crit "error obtaining remote IP/port (#{e.class}: #{e.message})"
46
+ @buffer.clear
47
+ @state = :init
48
+ return false
49
+ end
50
+
51
+ case stun_res = ::OverSIP::Stun.parse_request(buffer_str, source_ip, source_port)
52
+ # Not a STUN request so continue with SIP parsing.
53
+ when nil
54
+ # An invalid STUN request, log it and drop it.
55
+ when false
56
+ log_system_debug "invalid STUN message received (not a valid STUN Binding Request)" if $oversip_debug
57
+ @buffer.clear
58
+ @state = :init
59
+ return false
60
+ # A valid STUN Binding Request so we get a response to be sent.
61
+ when String
62
+ log_system_debug "STUN Binding Request received, replying to it" if $oversip_debug
63
+ send_data stun_res
64
+ @buffer.clear
65
+ @state = :init
66
+ return false
67
+ end
68
+
69
+ # Parse the currently buffered data. If parsing fails @parser_nbytes gets nil value.
70
+ unless @parser_nbytes = @parser.execute(buffer_str, @parser_nbytes)
71
+ # The parsed data is invalid, however some data could be parsed so @parsed.parsed
72
+ # can be:
73
+ # - SIP::Request
74
+ # - SIP::Response
75
+ # - nil (the message is so wrong that cannot be neither a request or response).
76
+ if wrong_message = @parser.parsed
77
+ log_system_warn "parsing error for #{MSG_TYPE[wrong_message.class]}: \"#{@parser.error}\""
78
+ else
79
+ log_system_warn "parsing error: \"#{@parser.error}\""
80
+ end
81
+
82
+ @buffer.clear
83
+ @state = :init
84
+ return false
85
+ end
86
+
87
+ unless @parser.finished?
88
+ # The parsing has not finished.
89
+ # If UDP it's invalid as per RFC 3261 a UDP datagram MUST contain an entire
90
+ # SIP request or response. Note we also allow double CRLF in UDP. If just a
91
+ # single CRLF arrives ignore it and clear the buffer.
92
+ # Maybe the parser has gone enought data to determine if the unfinished
93
+ # message is a SIP request or response, log it if so.
94
+ # If not, then @parser.parsed returns nil and nothing is logged.
95
+ unfinished_msg = @parser.parsed
96
+ log_system_warn "ignoring not finished #{MSG_TYPE[unfinished_msg.class]} via UDP" if
97
+ unfinished_msg.is_a? ::OverSIP::SIP::Request or unfinished_msg.is_a? ::OverSIP::SIP::Response
98
+ # Clear the buffer, set :init state and wait for new messages.
99
+ @buffer.clear
100
+ @state = :init
101
+ return false
102
+ end
103
+
104
+ # At this point we've got a SIP::Request, SIP::Response or :outbound_keepalive symbol.
105
+ @msg = @parser.parsed
106
+
107
+ # Clear parsed data from the buffer.
108
+ @buffer.read(@parser_nbytes)
109
+
110
+ # Received data is a Outbound keealive (also allowed in UDP however). Reply single CRLF.
111
+ if @msg == :outbound_keepalive
112
+ log_system_debug "Outbound keepalive received, replying single CRLF" if $oversip_debug
113
+ # Reply a single CRLF over the same connection.
114
+ send_data CRLF
115
+ # If UDP there could be invalid data after double CRLF CRLF, just ignore it
116
+ # and clear the buffer. Set :init state and return false so we leave receive_data()
117
+ # method.
118
+ @buffer.clear
119
+ @state = :init
120
+ return false
121
+ end
122
+
123
+ @parser.post_parsing
124
+
125
+ # Here we have received the entire headers of a SIP request or response. Fill some
126
+ # attributes.
127
+ @msg.connection = self
128
+ @msg.transport = :udp
129
+ @msg.source_ip = source_ip
130
+ @msg.source_port = source_port
131
+ @msg.source_ip_type = self.class.ip_type
132
+
133
+ unless valid_message?
134
+ @buffer.clear
135
+ @state = :init
136
+ return false
137
+ end
138
+
139
+ add_via_received_rport if @msg.request?
140
+
141
+ unless check_via_branch
142
+ @buffer.clear
143
+ @state = :init
144
+ return false
145
+ end
146
+
147
+ # Examine Content-Length header.
148
+ # There is Content-Length header.
149
+ if cl = @msg.content_length and cl > 0
150
+ # Body size is correct. Read it and clear the buffer.
151
+ # Set :finished state and return true so message will be processed.
152
+ if cl == @buffer.size
153
+ @msg.body = @buffer.read.force_encoding(::Encoding::UTF_8)
154
+ @buffer.clear
155
+ @state = :finished
156
+ return true
157
+ # In UDP the remaining data after headers must be the entire body
158
+ # and fill exactly Content-Length bytes. If not it's invalid. Reply
159
+ # 400 and clear the buffer.
160
+ else
161
+ if @msg.request?
162
+ unless @msg.sip_method == :ACK
163
+ log_system_warn "request body size doesn't match Content-Length => 400"
164
+ @msg.reply 400, "Body size doesn't match Content-Length"
165
+ else
166
+ log_system_warn "ACK body size doesn't match Content-Length, ignoring it"
167
+ end
168
+ else
169
+ log_system_warn "response body size doesn't match Content-Length, ignoring it"
170
+ end
171
+ @buffer.clear
172
+ @state = :init
173
+ return false
174
+ end
175
+ # No Content-Length header or 0 value. However it could occur that the datagram
176
+ # contains remaining unuseful data, in this case reply 400. If not
177
+ # set :finished state and return true so message will be processed.
178
+ else
179
+ # Ensure there is no more data in the buffer. If it's ok set :finished
180
+ # state and return true so message will be processed.
181
+ if @buffer.size.zero?
182
+ @state = :finished
183
+ return true
184
+ # Non valid remaining data in the UDP datagram. Reply 400.
185
+ else
186
+ if @msg.request?
187
+ log_system_warn "request contains body but Content-Length is zero or not present => 400"
188
+ @msg.reply 400, "request contains body but Content-Length is zero or not present"
189
+ else
190
+ log_system_warn "response contains body but Content-Length is zero or not present, ignoring it"
191
+ end
192
+ @buffer.clear
193
+ @state = :init
194
+ return false
195
+ end
196
+ end
197
+
198
+ end # parse_headers
199
+
200
+ def send_sip_msg msg, ip, port
201
+ send_datagram msg, ip, port
202
+ true
203
+ end
204
+
205
+
206
+ def unbind cause=nil
207
+ log_system_crit "UDP socket closed!!! cause: #{cause.inspect}"
208
+ end
209
+
210
+ end # class UdpReactor
211
+
212
+ end
213
+
@@ -0,0 +1,28 @@
1
+ # OverSIP files
2
+
3
+ require "oversip/sip/listeners/reactor"
4
+
5
+ require "oversip/sip/listeners/udp_reactor"
6
+ require "oversip/sip/listeners/tcp_reactor"
7
+ require "oversip/sip/listeners/tls_tunnel_reactor"
8
+
9
+ require "oversip/sip/listeners/tcp_server"
10
+ require "oversip/sip/listeners/tls_server"
11
+ require "oversip/sip/listeners/tls_tunnel_server"
12
+
13
+ require "oversip/sip/listeners/ipv4_udp_server"
14
+ require "oversip/sip/listeners/ipv6_udp_server"
15
+ require "oversip/sip/listeners/ipv4_tcp_server"
16
+ require "oversip/sip/listeners/ipv6_tcp_server"
17
+ require "oversip/sip/listeners/ipv4_tls_server"
18
+ require "oversip/sip/listeners/ipv6_tls_server"
19
+ require "oversip/sip/listeners/ipv4_tls_tunnel_server"
20
+ require "oversip/sip/listeners/ipv6_tls_tunnel_server"
21
+
22
+ require "oversip/sip/listeners/tcp_client"
23
+ require "oversip/sip/listeners/tls_client"
24
+
25
+ require "oversip/sip/listeners/ipv4_tcp_client"
26
+ require "oversip/sip/listeners/ipv6_tcp_client"
27
+ require "oversip/sip/listeners/ipv4_tls_client"
28
+ require "oversip/sip/listeners/ipv6_tls_client"
@@ -0,0 +1,14 @@
1
+ module OverSIP::SIP
2
+
3
+ class Logic
4
+
5
+ include ::OverSIP::Logger
6
+
7
+ def initialize request
8
+ @log_id = "Logic " << request.via_branch_id
9
+ @request = request
10
+ end
11
+
12
+ end # class Logic
13
+
14
+ end
@@ -0,0 +1,168 @@
1
+ module OverSIP::SIP
2
+
3
+ class Message
4
+
5
+ include ::OverSIP::Logger
6
+
7
+ DIALOG_FORMING_METHODS = { :INVITE=>true, :SUBSCRIBE=>true, :REFER=>true }
8
+ LOOSE_RECORD_AWARE_METHODS = { :INVITE=>true, :REGISTER=>true, :SUBSCRIBE=>true, :REFER=>true }
9
+ OUTBOUND_AWARE_METHODS = { :INVITE=>true, :REGISTER=>true, :SUBSCRIBE=>true, :REFER=>true }
10
+ EMPTY_ARRAY = [].freeze
11
+
12
+ # SIP related attributes.
13
+ attr_accessor :transport
14
+ attr_accessor :source_ip
15
+ attr_accessor :source_ip_type
16
+ attr_accessor :source_port
17
+ attr_accessor :connection
18
+
19
+ # SIP message attributes.
20
+ attr_reader :sip_method
21
+ attr_reader :sip_version
22
+ attr_reader :headers
23
+
24
+ attr_reader :via_sent_by_host
25
+ attr_reader :via_sent_by_port
26
+ attr_reader :via_branch
27
+ attr_accessor :via_branch_id # It's the branch value without "z9hG4bK".
28
+ attr_reader :via_branch_rfc3261
29
+ attr_reader :via_received
30
+ attr_reader :via_has_rport
31
+ attr_accessor :via_rport # Value not parsed.
32
+ attr_reader :via_has_alias
33
+ attr_reader :via_core_value
34
+ attr_reader :via_params
35
+ attr_reader :num_vias
36
+
37
+ attr_reader :call_id
38
+ attr_reader :cseq
39
+ attr_reader :max_forwards
40
+ attr_reader :content_length
41
+ attr_reader :routes
42
+ attr_reader :require
43
+ attr_reader :supported
44
+ attr_reader :proxy_require
45
+
46
+ attr_accessor :body
47
+
48
+ attr_accessor :from # NameAddr instance.
49
+ attr_reader :from_tag
50
+ attr_accessor :to # NameAddr instance.
51
+ attr_reader :to_tag
52
+ attr_reader :contact # NameAddr instance (when it has a single value).
53
+ attr_reader :contact_params
54
+
55
+ attr_reader :hdr_via # Array
56
+ attr_reader :hdr_from # String
57
+ attr_reader :hdr_to # String
58
+ attr_reader :hdr_route # Array
59
+
60
+ # Other attributes.
61
+ attr_accessor :tvars # Transaction variables (a hash).
62
+
63
+
64
+ def udp? ; @transport == :udp end
65
+ def tcp? ; @transport == :tcp end
66
+ def tls? ; @transport == :tls end
67
+ def ws? ; @transport == :ws end
68
+ def tls? ; @transport == :wss end
69
+
70
+ def websocket? ; @transport == :ws || @transport == :wss end
71
+
72
+ def unknown_method? ; @is_unknown_method end
73
+
74
+ def via_rport? ; @via_has_rport end
75
+
76
+ def via_alias? ; @via_has_alias end
77
+
78
+ def dialog_forming?
79
+ DIALOG_FORMING_METHODS[@sip_method]
80
+ end
81
+
82
+ def loose_record_aware?
83
+ LOOSE_RECORD_AWARE_METHODS[@sip_method]
84
+ end
85
+
86
+ def outbound_aware?
87
+ OUTBOUND_AWARE_METHODS[@sip_method]
88
+ end
89
+
90
+ # Returns true if a header with the given header _name_ exists, false otherwise.
91
+ def has_header? name
92
+ @headers[MessageParser.headerize(name)] && true
93
+ end
94
+
95
+ # Returns the first value of the given header _name_, nil if it doesn't exist.
96
+ def header_top name
97
+ ( hdr = @headers[MessageParser.headerize(name)] ) ? hdr[0] : nil
98
+ end
99
+ alias :header :header_top
100
+
101
+ # Returns an array with all the values of the given header _name_, an empty array
102
+ # if it doesn't exist.
103
+ def header_all name
104
+ ( hdr = @headers[MessageParser.headerize(name)] ) ? hdr : EMPTY_ARRAY
105
+ end
106
+
107
+ # Replaces the header of given _name_ with a the given _value_.
108
+ # _value_ can be a single value or an array.
109
+ def set_header name, value
110
+ @headers[MessageParser.headerize(name)] =
111
+ case value
112
+ when Array
113
+ value
114
+ else
115
+ [ value.to_s ]
116
+ end
117
+ end
118
+
119
+ # Completely deletes the header with given _name_.
120
+ # Returns an array containing all the header values, nil otherwise.
121
+ def delete_header name
122
+ @headers.delete MessageParser.headerize(name)
123
+ end
124
+
125
+ # Removes the first value of a given header _name_.
126
+ # Returns the extracted value, nil otherwise.
127
+ def delete_header_top name
128
+ if hdr = @headers[k=MessageParser.headerize(name)]
129
+ hdr.size > 1 ? hdr.shift : @headers.delete(k)[0]
130
+ end
131
+ end
132
+
133
+ # Inserts the given _value_ in the first position of header _name_.
134
+ # _value_ must be a string.
135
+ def insert_header name, value
136
+ if hdr = @headers[k=MessageParser.headerize(name)]
137
+ hdr.insert 0, value.to_s
138
+ else
139
+ #@headers[k] = [ value.to_s ]
140
+ # NOTE: If the header name doesn't already exist in the mesage, insert
141
+ # the new header in the first position of the Hash.
142
+ @headers = { k => [ value.to_s ] }.merge! @headers
143
+ end
144
+ end
145
+
146
+ # Append the given _value_ in the last position of header _name_.
147
+ # _value_ must be a string.
148
+ def append_header name, value
149
+ if hdr = @headers[k=MessageParser.headerize(name)]
150
+ hdr.push value.to_s
151
+ else
152
+ @headers[k] = [ value.to_s ]
153
+ end
154
+ end
155
+
156
+ # Replaces the top value of the given header _name_ with the
157
+ # string given as argument _value_.
158
+ def replace_header_top name, value
159
+ if hdr = @headers[k=MessageParser.headerize(name)]
160
+ hdr[0] = value.to_s
161
+ else
162
+ @headers[k] = [ value.to_s ]
163
+ end
164
+ end
165
+
166
+ end # class Message
167
+
168
+ end
@@ -0,0 +1,202 @@
1
+ module OverSIP::SIP
2
+
3
+ module MessageProcessor
4
+
5
+ # Constants for efficiency.
6
+ MSG_TYPE = {
7
+ ::OverSIP::SIP::Request => "SIP request",
8
+ ::OverSIP::SIP::Response => "SIP response",
9
+ :outbound_keepalive => "Outbound keepalive"
10
+ }
11
+
12
+
13
+ def valid_message?
14
+ if header = @parser.missing_core_header?
15
+ log_system_notice "ignoring #{MSG_TYPE[@msg.class]} missing #{header} header"
16
+ return false
17
+ elsif header = @parser.duplicated_core_header?
18
+ log_system_notice "ignoring #{MSG_TYPE[@msg.class]} with duplicated #{header} header"
19
+ return false
20
+ end
21
+ return true
22
+ end
23
+ private :valid_message?
24
+
25
+
26
+ # Via ;received and ;rport stuff.
27
+ def add_via_received_rport
28
+ # - If ;rport is present ;received MUST also be set (RFC 3581).
29
+ # - If not add ;received according to RFC 3261 rules.
30
+ if @msg.via_rport?
31
+ via_received = @msg.source_ip
32
+ @msg.via_rport = @msg.source_port
33
+ else
34
+ via_received = (::OverSIP::Utils.compare_ips(@msg.via_sent_by_host, @msg.source_ip) ? nil : @msg.source_ip)
35
+ end
36
+
37
+ if via_received
38
+ via_params = ";branch=" << @msg.via_branch if @msg.via_branch
39
+ via_params << ";received=" << via_received if via_received
40
+ via_params << ";rport=" << @msg.via_rport.to_s if @msg.via_rport
41
+ via_params << ";alias" if @msg.via_alias?
42
+
43
+ if @msg.via_params
44
+ @msg.via_params.each { |k,v| via_params << ( v ? ";#{k}=#{v}" : ";#{k}" ) }
45
+ end
46
+
47
+ @msg.hdr_via[0] = "#{@msg.via_core_value}#{via_params}"
48
+ end
49
+ end
50
+ private :add_via_received_rport
51
+
52
+
53
+ # Reject the message in case it doesn't contain a Via branch compliant with RFC 3261
54
+ def check_via_branch
55
+ if @msg.via_branch_rfc3261
56
+ @msg.via_branch_id = @msg.via_branch[7..-1] # The branch without "z9hG4bK".
57
+ return true
58
+ end
59
+
60
+ if @msg.is_a? Request
61
+ unless @msg.sip_method == :ACK
62
+ log_system_notice "request doesn't contain a RFC 3261 Via branch => 400"
63
+ @msg.reply 400, "Via branch non RFC 3261 compliant"
64
+ else
65
+ log_system_notice "ACK doesn't contain a RFC 3261 Via branch, ignoring it"
66
+ end
67
+ else
68
+ log_system_notice "response doesn't contain a RFC 3261 Via branch, ignoring it"
69
+ end
70
+ false
71
+ end
72
+ private :check_via_branch
73
+
74
+
75
+ def process_request
76
+ # Create a new Logic instance for this request (unless it's a retransmission of the request,
77
+ # a CANCEL or an ACK for a final non-2XX response).
78
+ unless check_transaction
79
+ begin
80
+ # Create the antiloop identifier for this request.
81
+ @msg.antiloop_id = ::OverSIP::SIP::Tags.create_antiloop_id(@msg)
82
+
83
+ # Check loops.
84
+ if @msg.antiloop_id == @msg.via_branch_id[-32..-1]
85
+ @msg.reply 482, "Loop Detected"
86
+ return
87
+ end
88
+
89
+ # Initialize some attributes for the request (for received responses
90
+ # it's set in Proxy#receive_response).
91
+ @msg.tvars = {}
92
+
93
+ # Create the Logic instance and run it!
94
+ OverSIP::SIP::Logic.new(@msg).run
95
+ rescue => e
96
+ log_system_error e
97
+ @msg.reply 503, "Internal Error", ["Content-Type: text/plain"], "#{e.class }: #{e.message}"
98
+ end
99
+ end
100
+ end
101
+ private :process_request
102
+
103
+
104
+ # Process a received response.
105
+ def process_response
106
+ case @msg.sip_method
107
+ when :INVITE
108
+ ### TODO: Esto va a petar cuando tenga una clase que hereda de, p.ej, IPv4TcpServer que se llame xxxClient,
109
+ # ya que en ella no existirá @invite_client_transactions. Tengo que hacer que su @invite_client_transactions
110
+ # se rellene al de la clase padre al hacer el load de las clases.
111
+ if client_transaction = self.class.invite_client_transactions[@msg.via_branch_id]
112
+ client_transaction.receive_response(@msg)
113
+ return
114
+ end
115
+ when :ACK
116
+ when :CANCEL
117
+ if client_transaction = self.class.invite_client_transactions[@msg.via_branch_id]
118
+ client_transaction.receive_response_to_cancel(@msg)
119
+ return
120
+ end
121
+ else
122
+ if client_transaction = self.class.non_invite_client_transactions[@msg.via_branch_id]
123
+ client_transaction.receive_response(@msg)
124
+ return
125
+ end
126
+ end
127
+ log_system_debug "ignoring a response non matching a client transaction (#{@msg.sip_method} #{@msg.status_code})" if $oversip_debug
128
+ end
129
+ private :process_response
130
+
131
+
132
+ # Check transaction.
133
+ def check_transaction
134
+ case @msg.sip_method
135
+
136
+ when :INVITE
137
+ if server_transaction = @msg.connection.class.invite_server_transactions[@msg.via_branch_id]
138
+ # If the retranmission arrives via a different connection (for TCP/TLS) then use
139
+ # the new one.
140
+ if @msg.connection == server_transaction.request.connection
141
+ log_system_debug "INVITE retransmission received" if $oversip_debug
142
+ else
143
+ log_system_debug "INVITE retransmission received via other connection, updating server transaction" if $oversip_debug
144
+ server_transaction.request.connection = @msg.connection
145
+ end
146
+ server_transaction.retransmit_last_response
147
+ return true
148
+ end
149
+
150
+ when :ACK
151
+ # If there is associated INVITE transaction (so it has been rejected)
152
+ # pass ACK to the transaction.
153
+ if server_transaction = @msg.connection.class.invite_server_transactions[@msg.via_branch_id]
154
+ server_transaction.receive_ack
155
+ return true
156
+ # Absorb ACK for statelessly generated final responses by us.
157
+ elsif OverSIP::SIP::Tags.check_totag_for_sl_reply(@msg.to_tag)
158
+ log_system_debug "absorving ACK for a stateless final response" if $oversip_debug
159
+ return true
160
+ else
161
+ log_system_debug "passing ACK to the core" if $oversip_debug
162
+ return false
163
+ end
164
+
165
+ when :CANCEL
166
+ if server_transaction = @msg.connection.class.invite_server_transactions[@msg.via_branch_id]
167
+ case state = server_transaction.state
168
+ when :proceeding
169
+ log_system_debug "CANCEL matches an INVITE server transaction in proceeding state => 200" if $oversip_debug
170
+ @msg.reply 200, "Cancelled"
171
+ server_transaction.receive_cancel(@msg)
172
+ else
173
+ log_system_debug "CANCEL matches an INVITE server transaction in #{state} state => 200" if $oversip_debug
174
+ @msg.reply 200, "Cancelled"
175
+ end
176
+ else
177
+ log_system_debug "CANCEL does not match an INVITE server transaction => 481" if $oversip_debug
178
+ @msg.reply 481
179
+ end
180
+ return true
181
+
182
+ else
183
+ if server_transaction = @msg.connection.class.non_invite_server_transactions[@msg.via_branch_id]
184
+ # If the retranmission arrives via a different connection (for TCP/TLS) then use
185
+ # the new one.
186
+ if @msg.connection == server_transaction.request.connection
187
+ log_system_debug "#{server_transaction.request.sip_method} retransmission received" if $oversip_debug
188
+ else
189
+ log_system_debug "#{server_transaction.request.sip_method} retransmission received via other connection, updating server transaction" if $oversip_debug
190
+ server_transaction.request.connection = @msg.connection
191
+ end
192
+ server_transaction.retransmit_last_response
193
+ return true
194
+ end
195
+
196
+ end
197
+ end # def check_transaction
198
+ private :check_transaction
199
+
200
+ end
201
+
202
+ end