func NewConn(baseConn net.Conn, output chan base.SipMessage) *connection { var isStreamed bool switch baseConn.(type) { case *net.UDPConn: isStreamed = false case *net.TCPConn: isStreamed = true case *tls.Conn: isStreamed = true default: log.Severe("Conn object %v is not a known connection type. Assume it's a streamed protocol, but this may cause messages to be rejected") } connection := connection{baseConn: baseConn, isStreamed: isStreamed} connection.parsedMessages = make(chan base.SipMessage) connection.parserErrors = make(chan error) connection.output = output connection.parser = parser.NewParser(connection.parsedMessages, connection.parserErrors, connection.isStreamed) go connection.read() go connection.pipeOutput() return &connection }
// Render params to a string. // Note that this does not escape special characters, this should already have been done before calling this method. func (p params) ToString(sep uint8) string { var buffer bytes.Buffer first := true for _, k := range p.Keys() { v, ok := p.Get(k) if !ok { log.Severe("Internal consistency error. Key %v present in param.Keys() but failed to Get()!", k) continue } if !first { buffer.WriteString(fmt.Sprintf("%c", sep)) } first = false buffer.WriteString(fmt.Sprintf("%s", k)) switch v := v.(type) { case String: if strings.ContainsAny(v.String(), c_ABNF_WS) { buffer.WriteString(fmt.Sprintf("=\"%s\"", v.String())) } else { buffer.WriteString(fmt.Sprintf("=%s", v.String())) } } } return buffer.String() }
func (udp *Udp) listen(conn *net.UDPConn) { log.Info("Begin listening for UDP on address %s", conn.LocalAddr()) buffer := make([]byte, c_BUFSIZE) for { num, _, err := conn.ReadFromUDP(buffer) if err != nil { if udp.stop { log.Info("Stopped listening for UDP on %s", conn.LocalAddr) break } else { log.Severe("Failed to read from UDP buffer: " + err.Error()) continue } } pkt := append([]byte(nil), buffer[:num]...) go func() { msg, err := parser.ParseMessage(pkt) if err != nil { log.Warn("Failed to parse SIP message: %s", err.Error()) } else { udp.output <- msg } }() } }
// Copy a list of params. func (p params) Copy() Params { dup := NewParams() for _, k := range p.Keys() { if v, ok := p.Get(k); ok { dup.Add(k, v) } else { log.Severe("Internal consistency error. Key %v present in param.Keys() but failed to Get()!", k) } } return dup }
func (tcp *Tcp) serve(listeningPoint *net.TCPListener) { log.Info("Begin serving TCP on address " + listeningPoint.Addr().String()) for { baseConn, err := listeningPoint.Accept() if err != nil { log.Severe("Failed to accept TCP conn on address " + listeningPoint.Addr().String() + "; " + err.Error()) continue } conn := NewConn(baseConn, tcp.output) log.Debug("Accepted new TCP conn %p from %s on address %s", &conn, conn.baseConn.RemoteAddr(), conn.baseConn.LocalAddr()) tcp.connTable.Notify(baseConn.RemoteAddr().String(), conn) } }
func (tx *ServerTransaction) initNonInviteFSM() { // Define States // Trying server_state_def_trying := fsm.State{ Index: server_state_trying, Outcomes: map[fsm.Input]fsm.Outcome{ server_input_request: {server_state_trying, fsm.NO_ACTION}, server_input_user_1xx: {server_state_proceeding, tx.act_respond}, server_input_user_2xx: {server_state_completed, tx.act_respond}, server_input_user_300_plus: {server_state_completed, tx.act_respond}, }, } // Proceeding server_state_def_proceeding := fsm.State{ Index: server_state_proceeding, Outcomes: map[fsm.Input]fsm.Outcome{ server_input_request: {server_state_proceeding, tx.act_respond}, server_input_user_1xx: {server_state_proceeding, tx.act_respond}, server_input_user_2xx: {server_state_completed, tx.act_final}, server_input_user_300_plus: {server_state_completed, tx.act_final}, server_input_transport_err: {server_state_terminated, tx.act_trans_err}, }, } // Completed server_state_def_completed := fsm.State{ Index: server_state_completed, Outcomes: map[fsm.Input]fsm.Outcome{ server_input_request: {server_state_completed, tx.act_respond}, server_input_user_1xx: {server_state_completed, fsm.NO_ACTION}, server_input_user_2xx: {server_state_completed, fsm.NO_ACTION}, server_input_user_300_plus: {server_state_completed, fsm.NO_ACTION}, server_input_timer_h: {server_state_terminated, tx.act_timeout}, server_input_transport_err: {server_state_terminated, tx.act_trans_err}, }, } // Terminated server_state_def_terminated := fsm.State{ Index: server_state_terminated, Outcomes: map[fsm.Input]fsm.Outcome{ server_input_request: {server_state_terminated, fsm.NO_ACTION}, server_input_user_1xx: {server_state_terminated, fsm.NO_ACTION}, server_input_user_2xx: {server_state_terminated, fsm.NO_ACTION}, server_input_user_300_plus: {server_state_terminated, fsm.NO_ACTION}, server_input_timer_h: {server_state_terminated, fsm.NO_ACTION}, server_input_delete: {server_state_terminated, tx.act_delete}, }, } // Define FSM fsm, err := fsm.Define( server_state_def_trying, server_state_def_proceeding, server_state_def_completed, server_state_def_terminated, ) if err != nil { log.Severe("Failed to define transaction FSM. Transaction will be dropped.") return } tx.fsm = fsm }
// Consume input lines one at a time, producing base.SipMessage objects and sending them down p.output. func (p *parser) parse(requireContentLength bool) { var message base.SipMessage for { // Parse the StartLine. startLine, err := p.input.NextLine() if err != nil { log.Debug("Parser %p stopped", p) break } if isRequest(startLine) { method, recipient, sipVersion, err := parseRequestLine(startLine) message = base.NewRequest(method, recipient, sipVersion, []base.SipHeader{}, "") p.terminalErr = err } else if isResponse(startLine) { sipVersion, statusCode, reason, err := parseStatusLine(startLine) message = base.NewResponse(sipVersion, statusCode, reason, []base.SipHeader{}, "") p.terminalErr = err } else { p.terminalErr = fmt.Errorf("transmission beginning '%s' is not a SIP message", startLine) } if p.terminalErr != nil { p.terminalErr = fmt.Errorf("failed to parse first line of message: %s", p.terminalErr.Error()) p.errs <- p.terminalErr break } // Parse the header section. // Headers can be split across lines (marked by whitespace at the start of subsequent lines), // so store lines into a buffer, and then flush and parse it when we hit the end of the header. var buffer bytes.Buffer headers := make([]base.SipHeader, 0) flushBuffer := func() { if buffer.Len() > 0 { newHeaders, err := p.parseHeader(buffer.String()) if err == nil { headers = append(headers, newHeaders...) } else { log.Debug("Skipping header '%s' due to error: %s", buffer.String(), err.Error()) } buffer.Reset() } } for { line, err := p.input.NextLine() if err != nil { log.Debug("Parser %p stopped", p) break } if len(line) == 0 { // We've hit the end of the header section. // Parse anything remaining in the buffer, then break out. flushBuffer() break } if !strings.Contains(c_ABNF_WS, string(line[0])) { // This line starts a new header. // Parse anything currently in the buffer, then store the new header line in the buffer. flushBuffer() buffer.WriteString(line) } else if buffer.Len() > 0 { // This is a continuation line, so just add it to the buffer. buffer.WriteString(" ") buffer.WriteString(line) } else { // This is a continuation line, but also the first line of the whole header section. // Discard it and log. log.Debug("Discarded unexpected continuation line '%s' at start of header block in message '%s'", line, message.Short()) } } // Store the headers in the message object. for _, header := range headers { message.AddHeader(header) } var contentLength int // Determine the length of the body, so we know when to stop parsing this message. if p.streamed { // Use the content-length header to identify the end of the message. contentLengthHeaders := message.Headers("Content-Length") if len(contentLengthHeaders) == 0 { p.terminalErr = fmt.Errorf("Missing required content-length header on message %s", message.Short()) p.errs <- p.terminalErr break } else if len(contentLengthHeaders) > 1 { var errbuf bytes.Buffer errbuf.WriteString("Multiple content-length headers on message ") errbuf.WriteString(message.Short()) errbuf.WriteString(":\n") for _, header := range contentLengthHeaders { errbuf.WriteString("\t") errbuf.WriteString(header.String()) } p.terminalErr = fmt.Errorf(errbuf.String()) p.errs <- p.terminalErr break } contentLength = int(*(contentLengthHeaders[0].(*base.ContentLength))) } else { // We're not in streaming mode, so the Write method should have calculated the length of the body for us. contentLength = (<-p.bodyLengths.Out).(int) } // Extract the message body. body, err := p.input.NextChunk(contentLength) if err != nil { log.Debug("Parsed %p stopped", p) break } switch message.(type) { case *base.Request: message.(*base.Request).Body = body case *base.Response: message.(*base.Response).Body = body default: log.Severe("Internal error - message %s is neither a request type nor a response type", message.Short()) } p.output <- message } if !p.streamed { // We're in unstreamed mode, so we created a bodyLengths ElasticChan which // needs to be disposed. close(p.bodyLengths.In) } return }
func (tx *ClientTransaction) initInviteFSM() { // Define Actions // Resend the request. act_resend := func() fsm.Input { tx.timer_a_time *= 2 tx.timer_a.Reset(tx.timer_a_time) tx.resend() return fsm.NO_INPUT } // Just pass up the latest response. act_passup := func() fsm.Input { tx.passUp() return fsm.NO_INPUT } // Handle 300+ responses. // Pass up response and send ACK, start timer D. act_300 := func() fsm.Input { tx.passUp() tx.Ack() if tx.timer_d != nil { tx.timer_d.Stop() } tx.timer_d = time.AfterFunc(tx.timer_d_time, func() { tx.fsm.Spin(client_input_timer_d) }) return fsm.NO_INPUT } // Send an ACK. act_ack := func() fsm.Input { tx.Ack() return fsm.NO_INPUT } // Send up transport failure error. act_trans_err := func() fsm.Input { tx.transportError() return client_input_delete } // Send up timeout error. act_timeout := func() fsm.Input { tx.timeoutError() return client_input_delete } // Pass up the response and delete the transaction. act_passup_delete := func() fsm.Input { tx.passUp() tx.Delete() return fsm.NO_INPUT } // Just delete the transaction. act_delete := func() fsm.Input { tx.Delete() return fsm.NO_INPUT } // Define States // Calling client_state_def_calling := fsm.State{ Index: client_state_calling, Outcomes: map[fsm.Input]fsm.Outcome{ client_input_1xx: {client_state_proceeding, act_passup}, client_input_2xx: {client_state_terminated, act_passup_delete}, client_input_300_plus: {client_state_completed, act_300}, client_input_timer_a: {client_state_calling, act_resend}, client_input_timer_b: {client_state_terminated, act_timeout}, client_input_transport_err: {client_state_terminated, act_trans_err}, }, } // Proceeding client_state_def_proceeding := fsm.State{ Index: client_state_proceeding, Outcomes: map[fsm.Input]fsm.Outcome{ client_input_1xx: {client_state_proceeding, act_passup}, client_input_2xx: {client_state_terminated, act_passup_delete}, client_input_300_plus: {client_state_completed, act_300}, client_input_timer_a: {client_state_proceeding, fsm.NO_ACTION}, client_input_timer_b: {client_state_proceeding, fsm.NO_ACTION}, }, } // Completed client_state_def_completed := fsm.State{ Index: client_state_completed, Outcomes: map[fsm.Input]fsm.Outcome{ client_input_1xx: {client_state_completed, fsm.NO_ACTION}, client_input_2xx: {client_state_completed, fsm.NO_ACTION}, client_input_300_plus: {client_state_completed, act_ack}, client_input_timer_d: {client_state_terminated, act_delete}, client_input_transport_err: {client_state_terminated, act_trans_err}, client_input_timer_a: {client_state_completed, fsm.NO_ACTION}, client_input_timer_b: {client_state_completed, fsm.NO_ACTION}, }, } // Terminated client_state_def_terminated := fsm.State{ Index: client_state_terminated, Outcomes: map[fsm.Input]fsm.Outcome{ client_input_1xx: {client_state_terminated, fsm.NO_ACTION}, client_input_2xx: {client_state_terminated, fsm.NO_ACTION}, client_input_300_plus: {client_state_terminated, fsm.NO_ACTION}, client_input_timer_a: {client_state_terminated, fsm.NO_ACTION}, client_input_timer_b: {client_state_terminated, fsm.NO_ACTION}, client_input_delete: {client_state_terminated, act_delete}, }, } fsm, err := fsm.Define( client_state_def_calling, client_state_def_proceeding, client_state_def_completed, client_state_def_terminated, ) if err != nil { log.Severe("Failure to define INVITE client transaction fsm: %s", err.Error()) } tx.fsm = fsm }