예제 #1
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
		}
	}
}
예제 #2
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)
}
예제 #3
0
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
			}
		}()
	}
}
예제 #4
0
파일: conntable.go 프로젝트: hinike/gossip
// 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
		}
	}
}
예제 #5
0
파일: conntable.go 프로젝트: hinike/gossip
// 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
			}
		}
	}
}
예제 #6
0
파일: connection.go 프로젝트: hinike/gossip
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())
}
예제 #7
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
		}
	}
}
예제 #8
0
파일: conntable.go 프로젝트: hinike/gossip
// 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()
}
예제 #9
0
파일: manager.go 프로젝트: hinike/gossip
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
	}
}
예제 #10
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)
	}
}