用exosip2和osip2协议栈写一个C程序,实现本地向服务器注册,收到服务器返回的401后,本地添加鉴权后重新发送注册
时间: 2024-02-05 19:10:32 浏览: 152
exosip2/osip2源代码,sip开源协议栈
4星 · 用户满意度95%
以下是一个使用exosip2和osip2协议栈写的C程序,实现本地向服务器注册,收到服务器返回的401后,本地添加鉴权后重新发送注册的功能:
```
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <exosip2/exosip.h>
#include <osip2/osip.h>
#define LOCAL_IP "192.168.0.100"
#define SERVER_IP "192.168.0.200"
#define SERVER_PORT 5060
#define USERNAME "username"
#define PASSWORD "password"
static int osip_authenticate(osip_message_t *message)
{
osip_authorization_t *auth;
char *response;
int length;
osip_call_id_t *call_id = NULL;
osip_from_t *from = NULL;
osip_to_t *to = NULL;
osip_cseq_t *cseq = NULL;
osip_via_t *via = NULL;
osip_contact_t *contact = NULL;
osip_route_t *route = NULL;
if (osip_message_get_header(message, "Call-ID", 0, &call_id) != OSIP_SUCCESS) {
return -1;
}
if (osip_message_get_header(message, "From", 0, &from) != OSIP_SUCCESS) {
return -1;
}
if (osip_message_get_header(message, "To", 0, &to) != OSIP_SUCCESS) {
return -1;
}
if (osip_message_get_header(message, "CSeq", 0, &cseq) != OSIP_SUCCESS) {
return -1;
}
if (osip_message_get_header(message, "Via", 0, &via) != OSIP_SUCCESS) {
return -1;
}
if (osip_message_get_header(message, "Contact", 0, &contact) != OSIP_SUCCESS) {
return -1;
}
if (osip_message_get_header(message, "Route", 0, &route) != OSIP_SUCCESS) {
return -1;
}
osip_message_remove_header(message, "Authorization");
auth = osip_authorization_new();
osip_authorization_set_scheme(auth, osip_strdup("Digest"));
osip_authorization_set_username(auth, osip_strdup(USERNAME));
osip_authorization_set_realm(auth, osip_strdup("example.com"));
osip_authorization_set_nonce(auth, osip_strdup("1234567890"));
osip_authorization_set_uri(auth, osip_strdup(osip_message_get_uri(message)));
osip_authorization_set_response(auth, osip_strdup("abcdef0123456789"));
osip_authorization_set_algorithm(auth, osip_strdup("MD5"));
response = osip_authorization_to_str(auth, &length);
osip_message_add_header(message, osip_strdup("Authorization"), response);
osip_free(response);
osip_authorization_free(auth);
osip_message_set_call_id(message, call_id);
osip_message_set_from(message, from);
osip_message_set_to(message, to);
osip_message_set_cseq(message, cseq);
osip_message_set_via(message, via);
osip_message_set_contact(message, contact);
while (route != NULL) {
osip_message_add_route(message, route);
route = route->next;
}
return 0;
}
int main(int argc, char **argv)
{
int sock;
osip_message_t *request, *response;
exosip_t *context;
exosip_event_t *event;
osip_uri_t *from_uri, *to_uri, *contact_uri;
osip_authenticate_h authenticate;
/* 初始化协议栈 */
if (exosip_init() != 0) {
fprintf(stderr, "Error initializing eXosip.\n");
return -1;
}
/* 创建 UDP socket */
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock == -1) {
fprintf(stderr, "Error creating UDP socket.\n");
exosip_quit();
return -1;
}
/* 绑定本地 IP 和端口 */
struct sockaddr_in local_addr;
memset(&local_addr, 0, sizeof(local_addr));
local_addr.sin_family = AF_INET;
local_addr.sin_addr.s_addr = inet_addr(LOCAL_IP);
local_addr.sin_port = htons(0);
if (bind(sock, (struct sockaddr *)&local_addr, sizeof(local_addr)) == -1) {
fprintf(stderr, "Error binding UDP socket.\n");
close(sock);
exosip_quit();
return -1;
}
/* 创建 eXosip 上下文 */
context = exosip_malloc();
if (exosip_init_context(context, NULL, NULL, sock, EXOSIP_NON_BLOCKING) < 0) {
fprintf(stderr, "Error initializing eXosip context.\n");
close(sock);
exosip_quit();
return -1;
}
/* 创建 SIP URI */
from_uri = osip_uri_parse("sip:" LOCAL_IP);
to_uri = osip_uri_parse("sip:" SERVER_IP);
contact_uri = osip_uri_parse("sip:" LOCAL_IP);
/* 创建 REGISTER 请求 */
request = exosip_message_build_request(context, "REGISTER", osip_uri_to_str(to_uri), from_uri, to_uri, NULL);
osip_message_set_contact(request, osip_contact_parse(osip_uri_to_str(contact_uri)));
/* 添加认证头 */
authenticate = (osip_authenticate_h)osip_authenticate;
exosip_register_authentication_hook(context, "Digest", authenticate);
osip_authenticate(request);
/* 发送 REGISTER 请求 */
exosip_lock(context);
if (exosip_send_request(context, request) < 0) {
fprintf(stderr, "Error sending REGISTER request.\n");
exosip_unlock(context);
osip_message_free(request);
osip_uri_free(from_uri);
osip_uri_free(to_uri);
osip_uri_free(contact_uri);
close(sock);
exosip_quit();
return -1;
}
exosip_unlock(context);
/* 等待事件 */
while ((event = exosip_wait_event(context, 0)) != NULL) {
if (event->type == EXOSIP_REGISTRATION_FAILURE) {
/* 收到 401 Unauthorized 响应 */
response = event->response;
if (osip_authenticate(response) == 0) {
/* 添加认证头后重新发送 REGISTER 请求 */
exosip_lock(context);
if (exosip_send_request(context, request) < 0) {
fprintf(stderr, "Error sending REGISTER request.\n");
exosip_unlock(context);
osip_message_free(request);
osip_uri_free(from_uri);
osip_uri_free(to_uri);
osip_uri_free(contact_uri);
close(sock);
exosip_quit();
return -1;
}
exosip_unlock(context);
} else {
fprintf(stderr, "Error authenticating REGISTER request.\n");
osip_message_free(request);
osip_uri_free(from_uri);
osip_uri_free(to_uri);
osip_uri_free(contact_uri);
close(sock);
exosip_quit();
return -1;
}
} else {
/* 其他事件 */
exosip_default_action(context, event);
}
exosip_event_free(event);
}
/* 释放资源 */
osip_message_free(request);
osip_uri_free(from_uri);
osip_uri_free(to_uri);
osip_uri_free(contact_uri);
close(sock);
exosip_quit();
return 0;
}
```
在上面的程序中,我们首先使用 `exosip_init()` 函数初始化 eXosip 协议栈,并创建一个 UDP socket 进行通信。然后,我们使用 `exosip_init_context()` 函数创建 eXosip 上下文,并将其与 UDP socket 绑定。接着,我们使用 `osip_uri_parse()` 函数创建 SIP URI,并使用 `exosip_message_build_request()` 函数创建一个 REGISTER 请求。在创建 REGISTER 请求时,我们还使用 `osip_contact_parse()` 函数创建一个 Contact 头。然后,我们使用 `exosip_register_authentication_hook()` 函数注册一个认证钩子函数,以便在收到 401 Unauthorized 响应时添加认证头。接着,我们使用 `exosip_send_request()` 函数发送 REGISTER 请求,并使用 `exosip_wait_event()` 函数等待事件。当收到 401 Unauthorized 响应时,我们使用 `osip_authenticate()` 函数添加认证头,并再次使用 `exosip_send_request()` 函数重新发送 REGISTER 请求。最后,我们释放资源并退出程序。
注意,在实际使用中,需要将程序中的 IP 地址、用户名和密码等信息替换为实际的值。此外,还需要根据实际情况修改程序中的参数,如本地 IP、服务器 IP、服务器端口等。
阅读全文