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 (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 } } }
// Send an automatic ACK. func (tx *ClientTransaction) Ack() { ack := base.NewRequest(base.ACK, tx.origin.Recipient, tx.origin.SipVersion, []base.SipHeader{}, "") // Copy headers from original request. // TODO: Safety base.CopyHeaders("From", tx.origin, ack) base.CopyHeaders("Call-Id", tx.origin, ack) base.CopyHeaders("Route", tx.origin, ack) cseq := tx.origin.Headers("CSeq")[0].Copy() cseq.(*base.CSeq).MethodName = base.ACK ack.AddHeader(cseq) via := tx.origin.Headers("Via")[0].Copy() ack.AddHeader(via) // Copy headers from response. base.CopyHeaders("To", tx.lastResp, ack) // Send the ACK. tx.transport.Send(tx.dest, ack) }
// 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 }
func TestMassUDP(t *testing.T) { NUM_MSGS := 10000 from, _ := NewManager("udp") to, _ := NewManager("udp") to.Listen(fmt.Sprintf("%s:%d", alice.host, alice.port)) receiver := to.GetChannel() receivedIDs := make([]int, 0) result := make(chan bool) go func() { recvloop: for { select { case msg, ok := <-receiver: if !ok { break recvloop } id, _ := strconv.ParseInt(msg.GetBody(), 10, 32) receivedIDs = append(receivedIDs, int(id)) if len(receivedIDs) >= NUM_MSGS { break recvloop } case <-time.After(time.Second / 10): break recvloop } } if !(len(receivedIDs) == NUM_MSGS) { t.Errorf("Error - received an unexpected number of messages: %d", len(receivedIDs)) } else { seenSet := make(map[int]bool) for _, val := range receivedIDs { if _, match := seenSet[val]; match { t.Errorf("Duplicate message received: %d", val) } seenSet[val] = true } if len(seenSet) != NUM_MSGS { t.Errorf("Unexpected number of messages received: %d", len(seenSet)) } } result <- true }() go func() { uri := base.SipUri{User: base.String{"alice"}, Host: "127.0.0.1", Port: nil, UriParams: base.NewParams(), Headers: base.NewParams()} for ii := 1; ii <= NUM_MSGS; ii++ { from.Send(fmt.Sprintf("%s:%d", alice.host, alice.port), base.NewRequest(base.ACK, &uri, "SIP/2.0", []base.SipHeader{base.ContentLength(len(fmt.Sprintf("%d", ii)))}, fmt.Sprintf("%d", ii))) if ii%100 == 0 { <-time.After(time.Millisecond) } } }() _ = <-result return }