Class: OverSIP::SIP::UdpConnection
- Inherits:
-
Connection
- Object
- EM::Connection
- Connection
- OverSIP::SIP::UdpConnection
- Defined in:
- lib/oversip/sip/listeners/udp_connection.rb
Direct Known Subclasses
Constant Summary
Constants included from MessageProcessor
Instance Attribute Summary
Attributes inherited from Connection
Instance Method Summary collapse
- #parse_message ⇒ Object
- #receive_data(data) ⇒ Object
-
#send_sip_msg(msg, ip, port) ⇒ Object
parse_headers.
- #unbind(cause = nil) ⇒ Object
Methods inherited from Connection
#initialize, #open?, outbound_listener?, #receive_senderror, reliable_transport_listener?, #transport
Methods included from Logger
fg_system_msg2str, load_methods, #log_id
Constructor Details
This class inherits a constructor from OverSIP::SIP::Connection
Instance Method Details
#parse_message ⇒ Object
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/oversip/sip/listeners/udp_connection.rb', line 29 def return false if @buffer.empty? buffer_str = @buffer.to_str # Quikly ignore single CRLF (widely used by SIP UDP clients as keep-alive). if buffer_str == CRLF @buffer.clear @state = :init return false end begin source_port, source_ip = ::Socket.unpack_sockaddr_in(get_peername) rescue => e log_system_crit "error obtaining remote IP/port (#{e.class}: #{e.})" @buffer.clear @state = :init return false end case stun_res = ::OverSIP::Stun.parse_request(buffer_str, source_ip, source_port) # Not a STUN request so continue with SIP parsing. when nil # An invalid STUN request, log it and drop it. when false log_system_debug "invalid STUN message received (not a valid STUN Binding Request)" if $oversip_debug @buffer.clear @state = :init return false # A valid STUN Binding Request so we get a response to be sent. when ::String log_system_debug "STUN Binding Request received, replying to it" if $oversip_debug send_data stun_res @buffer.clear @state = :init return false end # Parse the currently buffered data. If parsing fails @parser_nbytes gets nil value. unless @parser_nbytes = @parser.execute(buffer_str, @parser_nbytes) # The parsed data is invalid, however some data could be parsed so @parsed.parsed # can be: # - SIP::Request # - SIP::Response # - nil (the message is so wrong that cannot be neither a request or response). if = @parser.parsed log_system_warn "parsing error for #{MSG_TYPE[.class]}: \"#{@parser.error}\"" else log_system_warn "parsing error: \"#{@parser.error}\"" end @buffer.clear @state = :init return false end unless @parser.finished? # The parsing has not finished. # If UDP it's invalid as per RFC 3261 a UDP datagram MUST contain an entire # SIP request or response. Note we also allow double CRLF in UDP. If just a # single CRLF arrives ignore it and clear the buffer. # Maybe the parser has gone enought data to determine if the unfinished # message is a SIP request or response, log it if so. # If not, then @parser.parsed returns nil and nothing is logged. unfinished_msg = @parser.parsed log_system_warn "ignoring not finished #{MSG_TYPE[unfinished_msg.class]} via UDP" if unfinished_msg.is_a? ::OverSIP::SIP::Request or unfinished_msg.is_a? ::OverSIP::SIP::Response # Clear the buffer, set :init state and wait for new messages. @buffer.clear @state = :init return false end # At this point we've got a SIP::Request, SIP::Response or :outbound_keepalive symbol. @msg = @parser.parsed # Clear parsed data from the buffer. @buffer.read(@parser_nbytes) # Received data is a Outbound keealive (also allowed in UDP however). Reply single CRLF. if @msg == :outbound_keepalive log_system_debug "Outbound keepalive received, replying single CRLF" if $oversip_debug # Reply a single CRLF over the same connection. send_data CRLF # If UDP there could be invalid data after double CRLF CRLF, just ignore it # and clear the buffer. Set :init state and return false so we leave receive_data() # method. @buffer.clear @state = :init return false end @parser.post_parsing # Here we have received the entire headers of a SIP request or response. Fill some # attributes. @msg.connection = self @msg.transport = :udp @msg.source_ip = source_ip @msg.source_port = source_port @msg.source_ip_type = self.class.ip_type unless @parser @buffer.clear @state = :init return false end add_via_received_rport if @msg.request? unless check_via_branch @buffer.clear @state = :init return false end # Examine Content-Length header. # There is Content-Length header. if cl = @msg.content_length and cl > 0 # Body size is correct. Read it and clear the buffer. # Set :finished state and return true so message will be processed. if cl == @buffer.size @msg.body = @buffer.read.force_encoding(::Encoding::UTF_8) @buffer.clear @state = :finished return true # In UDP the remaining data after headers must be the entire body # and fill exactly Content-Length bytes. If not it's invalid. Reply # 400 and clear the buffer. else if @msg.request? unless @msg.sip_method == :ACK log_system_warn "request body size doesn't match Content-Length => 400" @msg.reply 400, "Body size doesn't match Content-Length" else log_system_warn "ACK body size doesn't match Content-Length, ignoring it" end else log_system_warn "response body size doesn't match Content-Length, ignoring it" end @buffer.clear @state = :init return false end # No Content-Length header or 0 value. However it could occur that the datagram # contains remaining unuseful data, in this case reply 400. If not # set :finished state and return true so message will be processed. else # Ensure there is no more data in the buffer. If it's ok set :finished # state and return true so message will be processed. if @buffer.size.zero? @state = :finished return true # Non valid remaining data in the UDP datagram. Reply 400. else if @msg.request? log_system_warn "request contains body but Content-Length is zero or not present => 400" @msg.reply 400, "request contains body but Content-Length is zero or not present" else log_system_warn "response contains body but Content-Length is zero or not present, ignoring it" end @buffer.clear @state = :init return false end end end |
#receive_data(data) ⇒ Object
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
# File 'lib/oversip/sip/listeners/udp_connection.rb', line 5 def receive_data data @buffer << data while (case @state when :init @parser.reset @parser_nbytes = 0 @state = :message when :message when :finished if @msg.request? process_request else process_response end @state = :init false end) end # while end |
#send_sip_msg(msg, ip, port) ⇒ Object
parse_headers
199 200 201 202 |
# File 'lib/oversip/sip/listeners/udp_connection.rb', line 199 def send_sip_msg msg, ip, port send_datagram msg, ip, port true end |
#unbind(cause = nil) ⇒ Object
205 206 207 208 209 |
# File 'lib/oversip/sip/listeners/udp_connection.rb', line 205 def unbind cause=nil unless $! log_system_crit "UDP socket closed!!! cause: #{cause.inspect}" end end |