Ejemplo n.º 1
0
// Parse a header string, producing one or more SipHeader objects.
// (SIP messages containing multiple headers of the same type can express them as a
// single header containing a comma-separated argument list).
func (p *parser) parseHeader(headerText string) (headers []base.SipHeader, err error) {
	log.Debug("Parser %p parsing header \"%s\"", p, headerText)
	headers = make([]base.SipHeader, 0)

	colonIdx := strings.Index(headerText, ":")
	if colonIdx == -1 {
		err = fmt.Errorf("Field name with no value in header: %s", headerText)
		return
	}

	fieldName := strings.ToLower(strings.TrimSpace(headerText[:colonIdx]))
	fieldText := strings.TrimSpace(headerText[colonIdx+1:])
	if headerParser, ok := p.headerParsers[fieldName]; ok {
		// We have a registered parser for this header type - use it.
		headers, err = headerParser(fieldName, fieldText)
	} else {
		// We have no registered parser for this header type,
		// so we encapsulate the header data in a GenericHeader struct.
		log.Debug("Parser %p has no parser for header type %s", p, fieldName)
		header := base.GenericHeader{fieldName, fieldText}
		headers = []base.SipHeader{&header}
	}

	return
}
Ejemplo n.º 2
0
// Poll for input from one end of the channel and add it to the buffer.
// Also poll sending buffered signals out over the output chan.
func (c *ElasticChan) manage() {
	for {
		if len(c.buffer) > 0 {
			// The buffer has something in it, so try to send as well as
			// receive.
			// (Receive first in order to minimize blocked Send() calls).
			select {
			case in, ok := <-c.In:
				if !ok {
					log.Debug("Chan %p will dispose", c)
					break
				}
				log.Debug("Chan %p gets '%v'", c, in)
				c.buffer = append(c.buffer, in)
			case c.Out <- c.buffer[0]:
				log.Debug("Chan %p sends '%v'", c, c.buffer[0])
				c.buffer = c.buffer[1:]
			}
		} else {
			// The buffer is empty, so there's nothing to send.
			// Just wait to receive.
			in, ok := <-c.In
			if !ok {
				log.Debug("Chan %p will dispose", c)
				break
			}
			log.Debug("Chan %p gets '%v'", c, in)
			c.buffer = append(c.buffer, in)
		}
	}

	c.dispose()
}
Ejemplo n.º 3
0
func (c *ElasticChan) dispose() {
	log.Debug("Chan %p disposing...", c)
	for len(c.buffer) > 0 {
		c.Out <- c.buffer[0]
		c.buffer = c.buffer[1:]
	}
	log.Debug("Chan %p disposed", c)
}
Ejemplo n.º 4
0
func (t *connTable) handleUpdate(update *connUpdate) {
	log.Debug("Update received in connTable %p for address %s", t, update.addr)
	watcher, entry_exists := t.conns[update.addr]
	if !entry_exists {
		log.Debug("No connection watcher registered for %s; spawn one", update.addr)
		watcher = &connWatcher{update.addr, update.conn, timing.NewTimer(c_SOCKET_EXPIRY), timing.Now().Add(c_SOCKET_EXPIRY), t.expiries, make(chan bool)}
		t.conns[update.addr] = watcher
		go watcher.loop()
	}

	watcher.Update(update.conn)
}
Ejemplo n.º 5
0
// Block until the buffer contains at least one CRLF-terminated line.
// Return the line, excluding the terminal CRLF, and delete it from the buffer.
// Returns an error if the parserbuffer has been stopped.
func (pb *parserBuffer) NextLine() (response string, err error) {
	var buffer bytes.Buffer
	var data string
	var b byte

	// There has to be a better way!
	for {
		data, err = pb.reader.ReadString('\r')
		if err != nil {
			return
		}

		buffer.WriteString(data)

		b, err = pb.reader.ReadByte()
		if err != nil {
			return
		}

		buffer.WriteByte(b)
		if b == '\n' {
			response = buffer.String()
			response = response[:len(response)-2]
			log.Debug("Parser buffer returns line '%s'", response)
			return
		}
	}
}
Ejemplo n.º 6
0
// Create Client transaction.
func (mng *Manager) Send(r *base.Request, dest string) *ClientTransaction {
	log.Debug("Sending to %v: %v", dest, r.String())

	tx := &ClientTransaction{}
	tx.origin = r
	tx.dest = dest
	tx.transport = mng.transport
	tx.tm = mng

	tx.initFSM()

	tx.tu = make(chan *base.Response, 3)
	tx.tu_err = make(chan error, 1)

	tx.timer_a_time = T1
	tx.timer_a = time.AfterFunc(tx.timer_a_time, func() {
		tx.fsm.Spin(client_input_timer_a)
	})
	tx.timer_b = time.AfterFunc(64*T1, func() {
		tx.fsm.Spin(client_input_timer_b)
	})

	// Timer D is set to 32 seconds for unreliable transports, and 0 seconds otherwise.
	tx.timer_d_time = 32 * time.Second

	err := mng.transport.Send(dest, r)
	if err != nil {
		log.Warn("Failed to send message: %s", err.Error())
		tx.fsm.Spin(client_input_transport_err)
	}

	mng.putTx(tx)

	return tx
}
Ejemplo n.º 7
0
// Management loop for the connTable.
// Handles notifications of connection updates, expiries of connections, and
// the termination of the routine.
func (t *connTable) manage() {
	for {
		select {
		case request := <-t.connRequests:
			watcher := t.conns[request.addr]
			if watcher != nil {
				request.responseChan <- watcher.conn
			} else {
				request.responseChan <- nil
			}
		case update := <-t.updates:
			t.handleUpdate(update)
		case addr := <-t.expiries:
			if t.conns[addr].expiryTime.Before(time.Now()) {
				log.Debug("Conntable %p notified that the watcher for address %s has expired. Remove it.", t, addr)
				t.conns[addr].stop <- true
				t.conns[addr].conn.Close()
				delete(t.conns, addr)
			} else {
				// Due to a race condition, the socket has been updated since this expiry happened.
				// Ignore the expiry since we already have a new socket for this address.
				log.Warn("Ignored spurious expiry for address %s in conntable %p", t, addr)
			}
		case <-t.stop:
			log.Info("Conntable %p stopped")
			t.stopped = true
			for _, watcher := range t.conns {
				watcher.stop <- true
				watcher.conn.Close()
			}
			break
		}
	}
}
Ejemplo n.º 8
0
// connWatcher main loop. Waits for the connection to expire, and notifies the connTable
// when it does.
func (watcher *connWatcher) loop() {
	// We expect to close off connections explicitly, but let's be safe and clean up
	// if we close unexpectedly.
	defer func(c *connection) {
		if c != nil {
			c.Close()
		}
	}(watcher.conn)

	for {
		select {
		case <-watcher.timer.C():
			// Socket expiry timer has run out. Close the connection.
			log.Debug("Socket %p (%s) inactive for too long; close it", watcher.conn, watcher.addr)
			watcher.expiry <- watcher.addr

		case stop := <-watcher.stop:
			// We've received a termination signal; stop managing this connection.
			if stop {
				log.Info("Connection watcher for address %s got the kill signal. Stopping.", watcher.addr)
				watcher.timer.Stop()
				break
			}
		}
	}
}
Ejemplo n.º 9
0
func (caller *endpoint) Invite(callee *endpoint) error {
	// Starting a dialog.
	callid := "thisisacall" + string(caller.dialogIx)
	tagString := fmt.Sprintf("tag.%s.%s", caller.username, caller.host)
	branch := "z9hG4bK.callbranch.INVITE"
	caller.dialog.callId = callid
	caller.dialog.from_tag = base.String{tagString}
	caller.dialog.currentTx = txInfo{}
	caller.dialog.currentTx.branch = branch

	invite := base.NewRequest(
		base.INVITE,
		&base.SipUri{
			User: &callee.username,
			Host: callee.host,
		},
		"SIP/2.0",
		[]base.SipHeader{
			Via(caller, branch),
			To(callee, caller.dialog.to_tag),
			From(caller, caller.dialog.from_tag),
			Contact(caller),
			CSeq(caller.dialog.cseq, base.INVITE),
			CallId(callid),
			ContentLength(0),
		},
		"",
	)
	caller.dialog.cseq += 1

	log.Info("Sending: %v", invite.Short())
	tx := caller.tm.Send(invite, fmt.Sprintf("%v:%v", callee.host, callee.port))
	caller.dialog.currentTx.tx = transaction.Transaction(tx)
	for {
		select {
		case r := <-tx.Responses():
			log.Info("Received response: %v", r.Short())
			log.Debug("Full form:\n%v\n", r.String())
			// Get To tag if present.
			tag, ok := r.Headers("To")[0].(*base.ToHeader).Params.Get("tag")
			if ok {
				caller.dialog.to_tag = tag.(base.String)
			}

			switch {
			case r.StatusCode >= 300:
				// Call setup failed.
				return fmt.Errorf("callee sent negative response code %v.", r.StatusCode)
			case r.StatusCode >= 200:
				// Ack 200s manually.
				log.Info("Sending Ack")
				tx.Ack()
				return nil
			}
		case e := <-tx.Errors():
			log.Warn(e.Error())
			return e
		}
	}
}
Ejemplo n.º 10
0
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)
}
Ejemplo n.º 11
0
func (connection *connection) pipeOutput() {
	for {
		select {
		case message, ok := <-connection.parsedMessages:
			if ok {
				log.Debug("Connection %p from %s to %s received message over the wire: %s",
					connection,
					connection.baseConn.RemoteAddr(),
					connection.baseConn.LocalAddr(),
					message.Short())
				connection.output <- message
			} else {
				break
			}
		case err, ok := <-connection.parserErrors:
			if ok {
				// The parser has hit a terminal error. We need to restart it.
				log.Warn("Failed to parse SIP message: %s", err.Error())
				connection.parser = parser.NewParser(connection.parsedMessages,
					connection.parserErrors, connection.isStreamed)
			} else {
				break
			}
		}
	}

	log.Info("Parser stopped in ConnWrapper %v (local addr %s; remote addr %s); stopping listening",
		connection, connection.baseConn.LocalAddr(), connection.baseConn.RemoteAddr())
}
Ejemplo n.º 12
0
// Push a connection to the connection table, registered under a specific address.
// If it is a new connection, start the socket expiry timer.
// If it is a known connection, restart the timer.
func (t *connTable) Notify(addr string, conn *connection) {
	if t.stopped {
		log.Debug("Ignoring conn notification for address %s after table stop.", addr)
		return
	}

	t.updates <- &connUpdate{addr, conn}
}
Ejemplo n.º 13
0
// Return an existing open socket for the given address, or nil if no such socket
// exists.
func (t *connTable) GetConn(addr string) *connection {
	responseChan := make(chan *connection)
	t.connRequests <- &connRequest{addr, responseChan}
	conn := <-responseChan

	log.Debug("Query connection for address %s returns %p", conn)
	return conn
}
Ejemplo n.º 14
0
func (n *notifier) register(l listener) {
	log.Debug("Notifier %p has new listener %p", n, l)
	if n.listeners == nil {
		n.listeners = make(map[listener]bool)
	}
	n.listenerLock.Lock()
	n.listeners[l] = true
	n.listenerLock.Unlock()
}
Ejemplo n.º 15
0
func (connection *connection) read() {
	buffer := make([]byte, c_BUFSIZE)
	for {
		log.Debug("Connection %p waiting for new data on sock", connection)
		num, err := connection.baseConn.Read(buffer)
		if err != nil {
			// If connections are broken, just let them drop.
			log.Debug("Lost connection to %s on %s",
				connection.baseConn.RemoteAddr().String(),
				connection.baseConn.LocalAddr().String())
			return
		}

		log.Debug("Connection %p received %d bytes", connection, num)
		pkt := append([]byte(nil), buffer[:num]...)
		connection.parser.Write(pkt)
	}
}
Ejemplo n.º 16
0
func (n *notifier) forward() {
	for msg := range n.inputs {
		deadListeners := make([]chan base.SipMessage, 0)
		n.listenerLock.Lock()
		log.Debug(fmt.Sprintf("Notify %d listeners of message", len(n.listeners)))
		for listener := range n.listeners {
			sent := listener.notify(msg)
			if !sent {
				deadListeners = append(deadListeners, listener)
			}
		}
		for _, deadListener := range deadListeners {
			log.Debug(fmt.Sprintf("Expiring listener %#v", deadListener))
			delete(n.listeners, deadListener)
		}
		n.listenerLock.Unlock()
	}
}
Ejemplo n.º 17
0
// Deletes a transaction from the transaction store.
// Should only be called inside the storage handling goroutine to ensure concurrency safety.
func (mng *Manager) delTx(t Transaction) {
	key, ok := mng.makeKey(t.Origin())
	if !ok {
		log.Debug("Could not build lookup key for transaction. Is it missing a branch parameter?")
	}

	mng.txLock.Lock()
	delete(mng.txs, key)
	mng.txLock.Unlock()
}
Ejemplo n.º 18
0
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)
	}
}
Ejemplo n.º 19
0
// Block until the buffer contains at least n characters.
// Return precisely those n characters, then delete them from the buffer.
func (pb *parserBuffer) NextChunk(n int) (response string, err error) {
	var data []byte = make([]byte, n)

	var read int
	for total := 0; total < n; {
		read, err = pb.reader.Read(data[total:])
		total += read
		if err != nil {
			return
		}
	}

	response = string(data)
	log.Debug("Parser buffer returns chunk '%s'", response)
	return
}
Ejemplo n.º 20
0
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
}
Ejemplo n.º 21
0
func (caller *endpoint) nonInvite(callee *endpoint, method base.Method) error {
	caller.dialog.currentTx.branch = "z9hG4bK.callbranch." + string(method)
	request := base.NewRequest(
		method,
		&base.SipUri{
			User: &callee.username,
			Host: callee.host,
		},
		"SIP/2.0",
		[]base.SipHeader{
			Via(caller, caller.dialog.currentTx.branch),
			To(callee, caller.dialog.to_tag),
			From(caller, caller.dialog.from_tag),
			Contact(caller),
			CSeq(caller.dialog.cseq, method),
			CallId(caller.dialog.callId),
			ContentLength(0),
		},
		"",
	)
	caller.dialog.cseq += 1

	log.Info("Sending: %v", request.Short())
	tx := caller.tm.Send(request, fmt.Sprintf("%v:%v", callee.host, callee.port))
	caller.dialog.currentTx.tx = transaction.Transaction(tx)
	for {
		select {
		case r := <-tx.Responses():
			log.Info("Received response: %v", r.Short())
			log.Debug("Full form:\n%v\n", r.String())
			switch {
			case r.StatusCode >= 300:
				// Failure (or redirect).
				return fmt.Errorf("callee sent negative response code %v.", r.StatusCode)
			case r.StatusCode >= 200:
				// Success.
				log.Info("Successful transaction")
				return nil
			}
		case e := <-tx.Errors():
			log.Warn(e.Error())
			return e
		}
	}
}
Ejemplo n.º 22
0
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
}
Ejemplo n.º 23
0
func (tcp *Tcp) getConnection(addr string) (*connection, error) {
	conn := tcp.connTable.GetConn(addr)

	if conn == nil {
		log.Debug("No stored connection for address %s; generate a new one", addr)
		raddr, err := net.ResolveTCPAddr("tcp", addr)
		if err != nil {
			return nil, err
		}

		baseConn, err := net.DialTCP("tcp", nil, raddr)
		if err != nil {
			return nil, err
		}

		conn = NewConn(baseConn, tcp.output)
	} else {
		conn = tcp.connTable.GetConn(addr)
	}

	tcp.connTable.Notify(addr, conn)
	return conn, nil
}
Ejemplo n.º 24
0
// Stop parser processing, and allow all resources to be garbage collected.
// The parser will not release its resources until Stop() is called,
// even if the parser object itself is garbage collected.
func (p *parser) Stop() {
	log.Debug("Stopping parser %p", p)
	p.stopped = true
	p.input.Stop()
	log.Debug("Parser %p stopped", p)
}
Ejemplo n.º 25
0
// 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
}