SIP注册问题

时间:2012-02-13 08:36:00

标签: sockets tcp udp sip

我目前正在研究SIP示例应用程序。

我正在尝试在Unix上使用基于C的Socket编程进行注册。我已经成功地能够注册PJSIP,但是当我使用正常的套接字编程发送相同的参数时,我无法从服务器接收任何响应。

以下是源代码:

char *server = (char *)serverAddress; // First arg: server address/name
char *echoString = "Request msg REGISTER/cseq=46476 (tdta0x8857200)\r\nREGISTER sip:DOMAIN_NAME SIP/2.0\r\nVia: SIP/2.0/UDP 192.168.1.120:51648;rport;branch=z9hG4bKPjwEt4VvIVdjIJKRmEJbkidYDAu-zQbIqv\r\nMax-Forwards: 70\r\nFrom: <sip:USER_NAME@DOMAIN_NAME>;tag=epCBN7JXsQE1nnI5d5SOZe9a5ujRyI67\r\nTo: <sip:USER_NAME@DOMAIN_NAME>\r\nCall-ID: .5yYCqh2jEYdy5T4kxhzxwDYEkCO1XlD\r\nCSeq: 46476 REGISTER\r\nContact: <sip:USER_NAME@192.168.1.120:51648;ob>\r\nExpires: 300\r\nAllow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS\r\nAuthorization: Digest username=\"USER_NAME\", realm=\"asterisk\", nonce=\"3b63254c\", uri=\"sip:DOMAIN_NAME\", response=\"9e8fc78829d143a58fba5a79f6ad44fd\", algorithm=MD5\r\nContent-Length:  0"; 


size_t echoStringLen = strlen(echoString);


// Third arg (optional): server port/service
char *servPort = (char *)service;

// Tell the system what kind(s) of address info we want
struct addrinfo addrCriteria;                      // Criteria for address match
memset(&addrCriteria, 0, sizeof(addrCriteria));    // Zero out structure
addrCriteria.ai_family = AF_UNSPEC;                // For the following fields, a zero value means 
                                                   // Any address family "don't care"


addrCriteria.ai_socktype = SOCK_DGRAM; // Only datagram sockets
addrCriteria.ai_protocol = IPPROTO_UDP;         // Only UDP protocol
// Get address(es)
struct addrinfo *servAddr; // List of server addresses
int rtnVal = getaddrinfo(server, servPort, &addrCriteria, &servAddr);
if (rtnVal != 0)
    DieWithUserMessage("getaddrinfo() failed", gai_strerror(rtnVal));
// Create a datagram/UDP socket
int sock = socket(servAddr->ai_family, servAddr->ai_socktype,
                  servAddr->ai_protocol); // Socket descriptor for client
if (sock < 0)
    DieWithSystemMessage("socket() failed");
// Send the string to the server
ssize_t numBytes = sendto(sock, echoString, echoStringLen, 0,
                          servAddr->ai_addr, servAddr->ai_addrlen);
if (numBytes < 0)
    DieWithSystemMessage("sendto() failed");
else if (numBytes != echoStringLen)
    DieWithUserMessage("sendto() error", "sent unexpected number of bytes");
// Receive a response
struct sockaddr_storage fromAddr; // Source address of server
// Set length of from address structure (in-out parameter)
socklen_t fromAddrLen = sizeof(fromAddr);
char buffer[100 + 1]; // I/O buffer
numBytes = recvfrom(sock, buffer, 100, 0,
                    (struct sockaddr *) &fromAddr, &fromAddrLen);
if (numBytes < 0)
    DieWithSystemMessage("recvfrom() failed");
else if (numBytes != 100)
    DieWithUserMessage("recvfrom() error", "received unexpected number of bytes");
// Verify reception from expected source

int value = SockAddrsEqual(servAddr->ai_addr, (struct sockaddr *) &fromAddr);
if (value == 0)
    DieWithUserMessage("recvfrom()", "received a packet from unknown source");
freeaddrinfo(servAddr);
buffer[echoStringLen] = '\0';     // Null-terminate received data
printf("Received: %s\n", buffer); // Print the echoed string

close(sock);
exit(0);

当我尝试调试代码时,断点从recvfrom方法调用中消失,如下所示。

numBytes = recvfrom(sock, buffer, 100, 0, (struct sockaddr *) &fromAddr, &fromAddrLen);

提前感谢您的合作。

3 个答案:

答案 0 :(得分:0)

如果您没有收到Registrar服务器的回复,则很可能是因为它无法理解您发送的REGISTER请求或将其作为重复拒绝。您可能需要更加复杂地了解如何构建REGISTER请求,而不是简单地发送硬编码字符串。

除了你可以尝试的一个显而易见的事情是将所需的\ r \ n \ r \ n添加到echoString的末尾。所有SIP请求都需要以双行换行结束标题部分,并且字符串中缺少该请求。

答案 1 :(得分:0)

recvfrom()阻止,直到收到响应,除非您将套接字设置为非阻塞。更好的方法是使用select()超时(如一秒或两秒)。然后更好的是将整个事物放入循环中,重复一些次数(例如三次或四次)。

请记住,UDP不保证您的数据报将被传递:完全取决于您何时等待足够长的时间并且需要再次尝试。

另外,请检查servAddr getaddrinfo()中设置的值是否合理。如果地址或端口号错误,您的数据包可能会无声地消失。

答案 2 :(得分:0)

如果您确认这是套接字问题,那么很容易跟踪。

但如果你不确定那么这个问题使用网络分析应用程序(wireshark)&amp;看到你发送的数据包&amp;接收。然后看看套接字问题。