func (e *endpoint) ServeNonInvite() { log.Info("Listening for incoming requests...") tx := <-e.tm.Requests() r := tx.Origin() log.Info("Received request: %v", r.Short()) log.Debug("Full form:\n%v\n", r.String()) // Send a 200 OK resp := base.NewResponse( "SIP/2.0", 200, "OK", []base.SipHeader{}, "", ) base.CopyHeaders("Via", tx.Origin(), resp) base.CopyHeaders("From", tx.Origin(), resp) base.CopyHeaders("To", tx.Origin(), resp) base.CopyHeaders("Call-Id", tx.Origin(), resp) base.CopyHeaders("CSeq", tx.Origin(), resp) resp.AddHeader( &base.ContactHeader{ DisplayName: &e.displayName, Address: &base.SipUri{ User: &e.username, Host: e.host, }, }, ) log.Info("Sending 200 OK") <-time.After(1 * time.Second) tx.Respond(resp) }
// Handle a request. func (mng *Manager) request(r *base.Request) { t, ok := mng.getTx(r) if ok { t.Receive(r) return } // If we failed to correlate an ACK, just drop it. if r.Method == base.ACK { log.Warn("Couldn't correlate ACK to an open transaction. Dropping it.") return } // Create a new transaction tx := &ServerTransaction{} tx.tm = mng tx.origin = r tx.transport = mng.transport // Use the remote address in the top Via header. This is not correct behaviour. viaHeaders := tx.Origin().Headers("Via") if len(viaHeaders) == 0 { log.Warn("No Via header on new transaction. Transaction will be dropped.") return } via, ok := viaHeaders[0].(*base.ViaHeader) if !ok { panic(errors.New("Headers('Via') returned non-Via header!")) } if len(*via) == 0 { log.Warn("Via header contained no hops! Transaction will be dropped.") return } hop := (*via)[0] port := uint16(5060) if hop.Port != nil { port = *hop.Port } tx.dest = fmt.Sprintf("%s:%d", hop.Host, port) tx.transport = mng.transport tx.initFSM() tx.tu = make(chan *base.Response, 3) tx.tu_err = make(chan error, 1) tx.ack = make(chan *base.Request, 1) // Send a 100 Trying immediately. // Technically we shouldn't do this if we trustthe user to do it within 200ms, // but I'm not sure how to handle that situation right now. // Pretend the user sent us a 100 to send. trying := base.NewResponse( "SIP/2.0", 100, "Trying", []base.SipHeader{}, "", ) base.CopyHeaders("Via", tx.origin, trying) base.CopyHeaders("From", tx.origin, trying) base.CopyHeaders("To", tx.origin, trying) base.CopyHeaders("Call-Id", tx.origin, trying) base.CopyHeaders("CSeq", tx.origin, trying) tx.lastResp = trying tx.fsm.Spin(server_input_user_1xx) mng.requests <- tx }
// 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 }