// 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 }
// 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() }
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) }
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) }
// 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 } } }
// 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 }
// 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 } } }
// 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 } } } }
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 } } }
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) }
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()) }
// 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} }
// 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 }
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() }
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) } }
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() } }
// 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() }
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) } }
// 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 }
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 (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 } } }
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 (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 }
// 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) }
// 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 }