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 (udp *Udp) listen(conn *net.UDPConn) { log.Info("Begin listening for UDP on address %s", conn.LocalAddr()) buffer := make([]byte, c_BUFSIZE) for { num, _, err := conn.ReadFromUDP(buffer) if err != nil { if udp.stop { log.Info("Stopped listening for UDP on %s", conn.LocalAddr) break } else { log.Severe("Failed to read from UDP buffer: " + err.Error()) continue } } pkt := append([]byte(nil), buffer[:num]...) go func() { msg, err := parser.ParseMessage(pkt) if err != nil { log.Warn("Failed to parse SIP message: %s", err.Error()) } else { udp.output <- msg } }() } }
// 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 (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()) }
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 } } }
// Create a new connection table. func (t *connTable) Init() { log.Info("Init conntable %p", t) t.conns = make(map[string]*connWatcher) t.connRequests = make(chan *connRequest) t.updates = make(chan *connUpdate) t.expiries = make(chan string) t.stop = make(chan bool) go t.manage() }
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 (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) } }