コード例 #1
0
ファイル: endpoint.go プロジェクト: cema-sp/gossip-demo
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)
}
コード例 #2
0
ファイル: manager.go プロジェクト: hinike/gossip
// 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
}
コード例 #3
0
ファイル: parser.go プロジェクト: hinike/gossip
// 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
}