func (mng *Manager) handle(msg base.SipMessage) { log.Info("Received message: %s", msg.Short()) switch m := msg.(type) { case *base.Request: mng.request(m) case *base.Response: mng.correlate(m) default: // TODO: Error } }
func sendAndCheckReceipt(from *Manager, to string, receiver chan base.SipMessage, msg base.SipMessage, timeout time.Duration) bool { from.Send(to, msg) select { case msgIn, ok := <-receiver: if !ok { return false } return msgIn.String() == msg.String() case <-time.After(timeout): return false } }
func (udp *Udp) Send(addr string, msg base.SipMessage) error { log.Debug("Sending message %s to %s", msg.Short(), addr) raddr, err := net.ResolveUDPAddr("udp", addr) if err != nil { return err } var conn *net.UDPConn conn, err = net.DialUDP("udp", nil, raddr) if err != nil { return err } defer conn.Close() _, err = conn.Write([]byte(msg.String())) return err }
func (connection *connection) Send(msg base.SipMessage) (err error) { log.Debug("Sending message over connection %p: %s", connection, msg.Short()) msgData := msg.String() n, err := connection.baseConn.Write([]byte(msgData)) if err != nil { return } if n != len(msgData) { return fmt.Errorf("not all data was sent when dispatching '%s' to %s", msg.Short(), connection.baseConn.RemoteAddr()) } return }
func (mng *Manager) makeKey(s base.SipMessage) (key, bool) { viaHeaders := s.Headers("Via") via, ok := viaHeaders[0].(*base.ViaHeader) if !ok { panic(errors.New("Headers('Via') returned non-Via header!")) } b, ok := (*via)[0].Params.Get("branch") if !ok { return key{}, false } branch, ok := b.(base.String) if !ok { return key{}, false } var method string switch s := s.(type) { case *base.Request: // Correlate an ACK request to the related INVITE. if s.Method == base.ACK { method = string(base.INVITE) } else { method = string(s.Method) } case *base.Response: cseqs := s.Headers("CSeq") if len(cseqs) == 0 { // TODO - Handle non-existent CSeq panic("No CSeq on response!") } cseq, _ := s.Headers("CSeq")[0].(*base.CSeq) method = string(cseq.MethodName) } return key{branch.String(), method}, true }
// 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 }