SIP协议栈--osip源码梳理

文章目录

osip

OSIP(Open Source Implementation of SIP)是一个开源的SIP(Session Initiation Protocol)协议栈,主要用于开发VoIP(Voice over Internet Protocol)应用程序。

主要功能

  • SIP消息解析和构建:OSIP提供了丰富的API来解析和构建SIP消息。
  • 事务管理:支持UAC(User Agent Client)、UAS(User Agent Server)等不同角色下的事务处理。
  • 状态机:内置的状态机帮助开发者更好地管理和维护SIP对话的状态。
  • 扩展性:允许用户自定义头字段和其他SIP元素,以便满足特定应用的需求。

osip主体

结构体
c 复制代码
struct osip
{
    void*							application_context;		//User defined Pointer
	// 用户定义的指针,允许开发者存储自定义的应用程序上下文数据
	
    //list of transactions for ict, ist, nict, nist
    osip_list_t						osip_ict_transactions;		//list of ict transactions
    // 客户端事务(Invite Client Transaction, ICT)的列表, 
    // 包含多个osip_transaction_t对象,每个对象表示一个具体的ICT
    osip_list_t						osip_ist_transactions;		//list of ist transactions
    // 服务器事务(Invite Server Transaction, IST)的列表
    //包含多个osip_transaction_t对象,每个对象表示一个具体的IST
    osip_list_t						osip_nict_transactions;		//list of nict transaction
     //处理除INVITE之外的所有其他类型的SIP请求(如REGISTER、SUBSCRIBE等
	
    osip_list_t						osip_nist_transactions;		//list of nist transactions
     // 用于处理接收到的除INVITE之外的所有其他类型的SIP请求。
    osip_list_t						ixt_retransmissions;		//list of ixt elements
	// 管理重新传输的消息元素的列表
    osip_message_cb_t				msg_callbacks[OSIP_MESSAGE_CALLBACK_COUNT]; 
    osip_kill_transaction_cb_t		kill_callbacks[OSIP_KILL_CALLBACK_COUNT];
    osip_transport_error_cb_t		tp_error_callbacks[OSIP_TRANSPORT_ERROR_CALLBACK_COUNT];
	
    int (*cb_send_message)(osip_transaction_t*, osip_message_t*, char*, int, int, int);
	
#if defined(HAVE_DICT_DICT_H)
    dict*							osip_ict_hastable;        //htable of ict transactions
    dict*							osip_ist_hastable;		  //htable of ist transactions
    dict*							osip_nict_hastable;       //htable of nict transactions
    dict*							osip_nist_hastable;       //htable of nist transactions
#endif
}

回调函数:
1 消息回调 (osip_message_cb_t):

功能: 这些回调函数用于处理接收到的各种类型的SIP消息(如INVITE、ACK、BYE等)。每当OSIP库接收到一个新的SIP消息时,它会根据消息类型调用相应的回调函数。

作用: 开发者可以通过实现这些回调函数来定义如何处理不同的SIP消息,从而实现业务逻辑。
2 事务终止回调 (osip_kill_transaction_cb_t):

功能: 这些回调函数用于处理事务的终止。每当OSIP库决定终止一个事务时,它会调用相应的回调函数来清理资源或执行其他必要的操作。

作用: 开发者可以通过实现这些回调函数来确保资源得到正确的释放,并执行任何必要的清理工作。
3 传输层错误回调 (osip_transport_error_cb_t):

功能: 这些回调函数用于处理传输层错误。每当OSIP库检测到传输层错误(如网络连接失败、超时等)时,它会调用相应的回调函数来处理这些错误。

作用: 开发者可以通过实现这些回调函数来应对各种传输层问题,例如重试机制、日志记录等。
4 发送消息回调 (cb_send_message):

功能: 这个回调函数用于发送SIP消息。每当OSIP库需要发送一个SIP消息时,它会调用这个回调函数来完成实际的发送操作。

作用: 开发者可以通过实现这个回调函数来自定义消息的发送方式,例如使用特定的传输协议(TCP、UDP等),或者添加额外的日志记录。

code main函数
c 复制代码
int main() {
    osip_t *osip;
    osip_init(&osip, OSIP_LOG_LEVEL_INFO);

    // 设置消息回调函数
    osip_message_cb_t msg_callbacks[OSIP_MESSAGE_CALLBACK_COUNT];
    for (int i = 0; i < OSIP_MESSAGE_CALLBACK_COUNT; i++) {
        msg_callbacks[i] = NULL;
    }
    msg_callbacks[OSIP_INVITE] = handle_invite;

    osip->msg_callbacks = msg_callbacks;

    // 模拟接收一个INVITE请求
    const char *invite_request_str =
        "INVITE sip:[email protected] SIP/2.0\r\n"
        "Via: SIP/2.0/UDP localhost:5060;branch=z9hG4bK77ef4c2312983.1\r\n"
        "Max-Forwards: 70\r\n"
        "To: \"User\" <sip:[email protected]>\r\n"
        "From: \"Caller\" <sip:caller@localhost>;tag=12345\r\n"
        "Call-ID: unique-id@localhost\r\n"
        "CSeq: 1 INVITE\r\n"
        "Content-Length: 0\r\n\r\n";

    osip_message_t *invite_request;
    osip_message_init(&invite_request);
    osip_message_parse(invite_request, invite_request_str, strlen(invite_request_str));

    // 创建Invite Client Transaction (ICT)
    osip_transaction_t *transaction;
    osip_ict_new(&transaction, invite_request, osip);

    // 初始化事件
    osip_event_t *event;
    osip_event_init(&event, OSIP_ICT_NEW, transaction, invite_request, NULL, NULL);

    // 处理事件
    osip_handle_events(osip);

    // 清理资源
    osip_message_free(invite_request);
    osip_transaction_free(transaction);
    osip_shutdown(osip);

    return 0;
}

状态机转化

结构体
c 复制代码
struct _transition_t
{
	state_t					state;
	type_t					type;
	void (*method) (void *, void *);
	struct _transition_t*	next;
	struct _transition_t*	parent;
};

struct _transition_t结构体用于描述有限状态机中的一个状态转换。每个转换由以下几个部分组成:

  • 当前状态 (state_t state): 标识转换前的状态。
  • 事件类型 (type_t type): 标识触发转换的事件。
  • 处理方法 (void (*method) (void *, void *)): 指向处理转换的方法,包含具体的业务逻辑。
  • 下一个转换 (struct _transition_t* next): 指向下一个转换,形成链表或树状结构。
  • 父转换 (struct _transition_t* parent): 指向父转换,用于跟踪层次关系。
code状态转换
c 复制代码
#include <stdio.h>
#include <stdlib.h>

// 定义状态类型
typedef enum {
    STATE_IDLE,
    STATE_RUNNING,
    STATE_PAUSED,
    STATE_STOPPED
} state_t;

// 定义事件类型
typedef enum {
    EVENT_START,
    EVENT_PAUSE,
    EVENT_RESUME,
    EVENT_STOP
} type_t;

// 定义过渡结构体
struct _transition_t {
    state_t state;
    type_t type;
    void (*method)(void *, void *);
    struct _transition_t *next;
    struct _transition_t *parent;
};

// 状态转换方法的原型
void transition_method_start(void *fsm_instance, void *event_data);
void transition_method_pause(void *fsm_instance, void *event_data);
void transition_method_resume(void *fsm_instance, void *event_data);
void transition_method_stop(void *fsm_instance, void *event_data);

// 模拟的状态机实例
typedef struct {
    state_t current_state;
} fsm_instance_t;

// 状态转换方法的具体实现
void transition_method_start(void *fsm_instance, void *event_data) {
    ((fsm_instance_t *)fsm_instance)->current_state = STATE_RUNNING;
    printf("Transition from IDLE to RUNNING\n");
}

void transition_method_pause(void *fsm_instance, void *event_data) {
    ((fsm_instance_t *)fsm_instance)->current_state = STATE_PAUSED;
    printf("Transition from RUNNING to PAUSED\n");
}

void transition_method_resume(void *fsm_instance, void *event_data) {
    ((fsm_instance_t *)fsm_instance)->current_state = STATE_RUNNING;
    printf("Transition from PAUSED to RUNNING\n");
}

void transition_method_stop(void *fsm_instance, void *event_data) {
    ((fsm_instance_t *)fsm_instance)->current_state = STATE_STOPPED;
    printf("Transition from %d to STOPPED\n", ((fsm_instance_t *)fsm_instance)->current_state);
}

// 查找并执行状态转换
void process_event(fsm_instance_t *fsm_instance, type_t event_type, struct _transition_t *transitions) {
    struct _transition_t *current = transitions;
    while (current != NULL) {
        if (current->state == fsm_instance->current_state && current->type == event_type) {
            current->method(fsm_instance, NULL);
            return;
        }
        current = current->next;
    }
    printf("No valid transition found for state %d and event %d\n", fsm_instance->current_state, event_type);
}

int main() {
    // 初始化状态机实例
    fsm_instance_t fsm_instance;
    fsm_instance.current_state = STATE_IDLE;

    // 创建状态转换链表
    struct _transition_t *transitions = NULL;

    // 添加状态转换
    struct _transition_t *start_transition = malloc(sizeof(struct _transition_t));
    start_transition->state = STATE_IDLE;
    start_transition->type = EVENT_START;
    start_transition->method = transition_method_start;
    start_transition->next = NULL;
    start_transition->parent = NULL;
    transitions = start_transition;

    struct _transition_t *pause_transition = malloc(sizeof(struct _transition_t));
    pause_transition->state = STATE_RUNNING;
    pause_transition->type = EVENT_PAUSE;
    pause_transition->method = transition_method_pause;
    pause_transition->next = NULL;
    pause_transition->parent = start_transition;
    start_transition->next = pause_transition;

    struct _transition_t *resume_transition = malloc(sizeof(struct _transition_t));
    resume_transition->state = STATE_PAUSED;
    resume_transition->type = EVENT_RESUME;
    resume_transition->method = transition_method_resume;
    resume_transition->next = NULL;
    resume_transition->parent = pause_transition;
    pause_transition->next = resume_transition;

    struct _transition_t *stop_transition = malloc(sizeof(struct _transition_t));
    stop_transition->state = STATE_RUNNING;
    stop_transition->type = EVENT_STOP;
    stop_transition->method = transition_method_stop;
    stop_transition->next = NULL;
    stop_transition->parent = resume_transition;
    resume_transition->next = stop_transition;

    // 处理事件
    process_event(&fsm_instance, EVENT_START, transitions);  // 从IDLE到RUNNING
    process_event(&fsm_instance, EVENT_PAUSE, transitions); // 从RUNNING到PAUSED
    process_event(&fsm_instance, EVENT_RESUME, transitions);// 从PAUSED到RUNNING
    process_event(&fsm_instance, EVENT_STOP, transitions);  // 从RUNNING到STOPPED

    // 清理资源
    free(start_transition);
    free(pause_transition);
    free(resume_transition);
    free(stop_transition);

    return 0;
}

sip事务

结构体
c 复制代码
struct osip_transaction
{	
    void*				your_instance;      // User Defined Pointer
    int					transactionid;		// Internal Transaction Identifier
    osip_fifo_t*		transactionff;		// events must be added in this fifo
	
    osip_via_t*			topvia;				// CALL-LEG definition (Top Via)
    osip_from_t*		from;				// CALL-LEG definition (From)   
    osip_to_t*			to;					// CALL-LEG definition (To)     
    osip_call_id_t*		callid;				// CALL-LEG definition (Call-ID)
    osip_cseq_t*		cseq;				// CALL-LEG definition (CSeq)   
	
    osip_message_t*		orig_request;		// Initial request           
    osip_message_t*		last_response;		// Last response             
    osip_message_t*		ack;				// ack request sent          
	
    state_t				state;              // Current state of the transaction
	
    time_t				birth_time;         // birth date of transaction       
    time_t				completed_time;     // end   date of transaction    
	unsigned long		birth_time_ms;   
	
    int					in_socket;          // Optional socket for incoming message
    int					out_socket;         // Optional place for outgoing message
	
    void*				config;             // internal transaction is managed by osip_t 
	
    osip_fsm_type_t		ctx_type;			// Type of the transaction
    osip_ict_t*			ict_context;		// internal
    osip_ist_t*			ist_context;		// internal
    osip_nict_t*		nict_context;		// internal
    osip_nist_t*		nist_context;		// internal
	
	osip_srv_record_t	record;				// internal

#ifdef FSM_TIMER_OUT_LIST
	unsigned short		usTimerCtrl;		// the timer start or stop control
	unsigned short		usTimerFlag;		// the timer has or not deleted
#endif
#ifdef FSM_OPTIMIZM_ARRAY
	int					nArrayIndex;
#endif
};

封装了与一个特定SIP事务相关的所有信息和状态,包括请求、响应、状态转换等。通过这个结构体,OSIP库可以有效地处理不同类型的SIP事务

  • 事务标识和上下文:
    your_instance: 用户定义的指针,用于存储自定义的应用程序上下文数据。
    transactionid: 内部事务标识符,唯一标识一个事务。
    config: 指向管理事务的osip_t实例。
  • 事务状态和时间:
    state: 当前事务的状态。
    birth_time: 事务的创建时间。
    completed_time: 事务的完成时间。
    birth_time_ms: 事务的创建时间(毫秒级精度)。
  • SIP消息相关:
    topvia, from, to, callid, cseq: 指向SIP消息中的关键头字段。
    orig_request: 初始请求消息。
    last_response: 最后一个接收到的响应消息。
    ack: 发送出去的ACK请求消息。
  • 事务类型和上下文:
    ctx_type: 事务的类型(ICT、IST、NICT、NIST)。
    ict_context, ist_context, nict_context, nist_context: 指向不同类型事务的上下文。
  • 网络和定时器管理:
    in_socket, out_socket: 可选的套接字,用于接收和发送消息。
    usTimerCtrl, usTimerFlag: 控制和指示定时器的状态。
    record: 内部使用的记录结构,用于存储与事务相关的服务记录。
code

创建并发送100 Trying响应

  • 初始化OSIP库:
    使用osip_init初始化OSIP库。
    设置日志级别为OSIP_LOG_LEVEL_INFO。
  • 设置消息回调函数:
    定义一个回调函数handle_invite来处理INVITE请求。
    将回调函数注册到msg_callbacks数组中,并将其赋值给osip->msg_callbacks。
  • 模拟接收INVITE请求:
    定义一个字符串表示一个INVITE请求。
    初始化一个osip_message_t对象并解析该字符串。
  • 创建Invite Client Transaction (ICT):
    使用osip_ict_new创建一个新的Invite Client Transaction (ICT),并将解析好的INVITE请求传递给它。
  • 初始化事件:
    创建一个osip_event_t对象,并将其类型设置为OSIP_ICT_NEW,同时关联事务和请求。
  • 处理事件:
    调用osip_handle_events处理事件,触发回调函数handle_invite。
  • 处理INVITE请求:
    在handle_invite回调函数中,解析接收到的INVITE请求。
    打印关键头字段(如Via、From、To、Call-ID、CSeq)。
    创建并发送100 Trying响应。
  • 清理资源:
c 复制代码
#include <osipparser2/osip_parser.h>
#include <osipparser2/osip_message.h>
#include <osipparser2/osip_header.h>
#include <osip2/osip.h>
#include <stdio.h>

void handle_invite(osip_event_t *event) {
    osip_transaction_t *transaction = event->transaction;
    osip_message_t *request = transaction->orig_request;

    printf("Received INVITE request:\n%s\n", request->buffer);

    // 打印关键头字段
    printf("Via: %s\n", request->topvia->host);
    printf("From: %s <%s>\n", request->from->displayname, request->from->url->uri);
    printf("To: %s <%s>\n", request->to->displayname, request->to->url->uri);
    printf("Call-ID: %s\n", request->callid->number);
    printf("CSeq: %d %s\n", request->cseq->seq_number, request->cseq->method);

    // 创建并发送100 Trying响应
    osip_message_t *response;
    osip_message_init(&response);
    osip_message_set_version(response, "SIP/2.0");
    osip_message_set_status_code(response, 100);
    osip_message_set_reason_phrase(response, "Trying");

    osip_via_t *via;
    osip_via_init(&via);
    via->version = osip_strdup("2.0");
    via->protocol = osip_strdup("UDP");
    via->host = osip_strdup("localhost");
    via->port = osip_strdup("5060");
    osip_list_add(&response->vias, via, -1);

    osip_message_set_call_id(response, request->callid->number);
    osip_message_set_cseq(response, request->cseq->number, request->cseq->method);
    osip_message_set_from(response, request->from->displayname, request->from->url->username, request->from->url->host);
    osip_message_set_to(response, request->to->displayname, request->to->url->username, request->to->url->host);

    char *response_buffer;
    size_t response_length;
    osip_message_to_str(response, &response_buffer, &response_length);
    printf("Sending 100 Trying response:\n%.*s\n", (int)response_length, response_buffer);

    osip_transaction_send(transaction, response);

    osip_free(response_buffer);
    osip_message_free(response);
}

osip_dialog

结构体

struct osip_dialog结构体在OSIP库中用于管理SIP对话(Dialog)。SIP对话是一系列相关的SIP消息交换,通常涉及一个初始请求(如INVITE)及其响应序列。

c 复制代码
struct osip_dialog
    {
        char *call_id;                       /**< Call-ID string*/
		osip_call_id_t*   call_id_clone;     /**< Call-ID header */ 

        char *local_tag;                     /**< local tag */
        char *remote_tag;                    /**< remote tag */
        osip_list_t route_set;              /**< route set */
        int local_cseq;                      /**< last local cseq */
        int remote_cseq;                     /**< last remote cseq*/
        osip_to_t *remote_uri;               /**< remote_uri */
        osip_from_t *local_uri;              /**< local_uri */
        osip_contact_t *remote_contact_uri;  /**< remote contact_uri */
        int secure;                          /**< use secure transport layer */

        osip_dialog_type_t type;             /**< type of dialog (CALLEE or CALLER) */
        state_t state;                       /**< DIALOG_EARLY || DIALOG_CONFIRMED || DIALOG_CLOSED */
        void *your_instance;                 /**< for application data reference */
    };
code 创建并发送200 OK响应
  • 初始化OSIP库:
    使用osip_init初始化OSIP库。
    设置日志级别为OSIP_LOG_LEVEL_INFO。
  • 设置用户定义的上下文:
    将application_context设置为NULL,可以根据需要设置自定义的上下文数据。
  • 设置消息回调函数:
    定义一个回调函数handle_invite来处理INVITE请求。
    将回调函数注册到msg_callbacks数组中,并将其赋值给osip->msg_callbacks。
  • 设置事务终止回调函数:
    定义一个回调函数kill_transaction_cb来处理事务终止。
    将回调函数注册到kill_callbacks数组中,并将其赋值给osip->kill_callbacks。
  • 设置传输层错误回调函数:
    定义一个回调函数transport_error_cb来处理传输层错误。
    将回调函数注册到tp_error_callbacks数组中,并将其赋值给osip->tp_error_callbacks。
  • 设置发送消息的回调函数:
    定义一个回调函数send_message_cb来发送SIP消息。
    将回调函数赋值给osip->cb_send_message。
  • 模拟接收INVITE请求:
    定义一个字符串表示一个INVITE请求。
    初始化一个osip_message_t对象并解析该字符串。
  • 创建Invite Server Transaction (IST):
    使用osip_ist_new创建一个新的Invite Server Transaction (IST),并将解析好的INVITE请求传递给它。
    初始化事件:
    创建一个osip_event_t对象,并将其类型设置为OSIP_IST_NEW,同时关联事务和请求。
  • 处理事件:
    调用osip_handle_events处理事件,触发回调函数handle_invite。
  • 处理INVITE请求:
    在handle_invite回调函数中,解析接收到的INVITE请求。
    打印关键头字段(如Via、From、To、Call-ID、CSeq)。
    创建并发送100 Trying响应。
    创建并发送200 OK响应。
    创建对话osip_dialog_t并初始化为UAS(User Agent Server)模式。
    将对话添加到OSIP实例中的IST事务列表中。
  • 清理资源:
    释放分配的内存和资源,包括消息、事务和OSIP实例。
c 复制代码
#include <osipparser2/osip_parser.h>
#include <osipparser2/osip_message.h>
#include <osipparser2/osip_header.h>
#include <osip2/osip.h>
#include <stdio.h>
#include <stdlib.h>

// 回调函数:处理INVITE请求
void handle_invite(osip_event_t *event) {
    osip_transaction_t *transaction = event->transaction;
    osip_message_t *request = transaction->orig_request;

    printf("Received INVITE request:\n%s\n", request->buffer);

    // 打印关键头字段
    printf("Via: %s\n", request->topvia->host);
    printf("From: %s <%s>\n", request->from->displayname, request->from->url->uri);
    printf("To: %s <%s>\n", request->to->displayname, request->to->url->uri);
    printf("Call-ID: %s\n", request->callid->number);
    printf("CSeq: %d %s\n", request->cseq->seq_number, request->cseq->method);

    // 创建并发送100 Trying响应
    osip_message_t *response;
    osip_message_init(&response);
    osip_message_set_version(response, "SIP/2.0");
    osip_message_set_status_code(response, 100);
    osip_message_set_reason_phrase(response, "Trying");

    osip_via_t *via;
    osip_via_init(&via);
    via->version = osip_strdup("2.0");
    via->protocol = osip_strdup("UDP");
    via->host = osip_strdup("localhost");
    via->port = osip_strdup("5060");
    osip_list_add(&response->vias, via, -1);

    osip_message_set_call_id(response, request->callid->number);
    osip_message_set_cseq(response, request->cseq->number, request->cseq->method);
    osip_message_set_from(response, request->from->displayname, request->from->url->username, request->from->url->host);
    osip_message_set_to(response, request->to->displayname, request->to->url->username, request->to->url->host);

    char *response_buffer;
    size_t response_length;
    osip_message_to_str(response, &response_buffer, &response_length);
    printf("Sending 100 Trying response:\n%.*s\n", (int)response_length, response_buffer);

    osip_transaction_send(transaction, response);

    osip_free(response_buffer);
    osip_message_free(response);

    // 创建并发送200 OK响应
    osip_message_t *final_response;
    osip_message_init(&final_response);
    osip_message_set_version(final_response, "SIP/2.0");
    osip_message_set_status_code(final_response, 200);
    osip_message_set_reason_phrase(final_response, "OK");

    osip_via_t *final_via;
    osip_via_init(&final_via);
    final_via->version = osip_strdup("2.0");
    final_via->protocol = osip_strdup("UDP");
    final_via->host = osip_strdup("localhost");
    final_via->port = osip_strdup("5060");
    osip_list_add(&final_response->vias, final_via, -1);

    osip_message_set_call_id(final_response, request->callid->number);
    osip_message_set_cseq(final_response, request->cseq->number, request->cseq->method);
    osip_message_set_from(final_response, request->from->displayname, request->from->url->username, request->from->url->host);
    osip_message_set_to(final_response, request->to->displayname, request->to->url->username, request->to->url->host);

    osip_contact_t *contact;
    osip_contact_init(&contact);
    contact->url = osip_uri_clone(request->to->url);
    osip_list_add(&final_response->contacts, contact, -1);

    osip_message_to_str(final_response, &response_buffer, &response_length);
    printf("Sending 200 OK response:\n%.*s\n", (int)response_length, response_buffer);

    osip_transaction_send(transaction, final_response);

    osip_free(response_buffer);
    osip_message_free(final_response);

    // 创建对话
    osip_dialog_t *dialog;
    osip_dialog_init(&dialog);
    osip_dialog_init_as_uas(dialog, request, final_response);

    // 将对话添加到OSIP实例中
    osip_list_add(&transaction->config->osip_ist_transactions, dialog, -1);

    // 打印对话信息
    printf("Dialog created with Call-ID: %s\n", dialog->callid);
}

// 回调函数:处理事务终止
void kill_transaction_cb(osip_event_t *event) {
    osip_transaction_t *transaction = event->transaction;
    printf("Transaction terminated: ID=%d\n", transaction->transactionid);

    // 清理对话
    if (transaction->ctx_type == OSIP_IST) {
        osip_ist_t *ist = (osip_ist_t *)transaction->ict_context;
        if (ist->dialog != NULL) {
            osip_dialog_free(ist->dialog);
            ist->dialog = NULL;
        }
    }
}

// 回调函数:处理传输层错误
void transport_error_cb(int error_code, char *error_description) {
    printf("Transport error: Code=%d, Description=%s\n", error_code, error_description);
}

// 发送消息的回调函数
int send_message_cb(osip_transaction_t* transaction, osip_message_t* message, char* host, int port, int flags, int other_flags) {
    char *message_buffer;
    size_t message_length;
    osip_message_to_str(message, &message_buffer, &message_length);
    printf("Sending message to %s:%d:\n%.*s\n", host, port, (int)message_length, message_buffer);
    osip_free(message_buffer);
    return 0; // 成功
}

int main() {
    osip_t *osip;
    osip_init(&osip, OSIP_LOG_LEVEL_INFO);

    // 设置用户定义的上下文
    osip->application_context = NULL;

    // 设置消息回调函数
    osip_message_cb_t msg_callbacks[OSIP_MESSAGE_CALLBACK_COUNT];
    for (int i = 0; i < OSIP_MESSAGE_CALLBACK_COUNT; i++) {
        msg_callbacks[i] = NULL;
    }
    msg_callbacks[OSIP_INVITE] = handle_invite;
    osip->msg_callbacks = msg_callbacks;

    // 设置事务终止回调函数
    osip_kill_transaction_cb_t kill_callbacks[OSIP_KILL_CALLBACK_COUNT];
    for (int i = 0; i < OSIP_KILL_CALLBACK_COUNT; i++) {
        kill_callbacks[i] = NULL;
    }
    kill_callbacks[OSIP_ICT] = kill_transaction_cb;
    osip->kill_callbacks = kill_callbacks;

    // 设置传输层错误回调函数
    osip_transport_error_cb_t tp_error_callbacks[OSIP_TRANSPORT_ERROR_CALLBACK_COUNT];
    for (int i = 0; i < OSIP_TRANSPORT_ERROR_CALLBACK_COUNT; i++) {
        tp_error_callbacks[i] = NULL;
    }
    tp_error_callbacks[OSIP_TP_ERROR] = transport_error_cb;
    osip->tp_error_callbacks = tp_error_callbacks;

    // 设置发送消息的回调函数
    osip->cb_send_message = send_message_cb;

    // 模拟接收一个INVITE请求
    const char *invite_request_str =
        "INVITE sip:[email protected] SIP/2.0\r\n"
        "Via: SIP/2.0/UDP localhost:5060;branch=z9hG4bK77ef4c2312983.1\r\n"
        "Max-Forwards: 70\r\n"
        "To: \"User\" <sip:[email protected]>\r\n"
        "From: \"Caller\" <sip:caller@localhost>;tag=12345\r\n"
        "Call-ID: unique-id@localhost\r\n"
        "CSeq: 1 INVITE\r\n"
        "Contact: <sip:user@localhost:5060>\r\n"
        "Content-Length: 0\r\n\r\n";

    osip_message_t *invite_request;
    osip_message_init(&invite_request);
    osip_message_parse(invite_request, invite_request_str, strlen(invite_request_str));

    // 创建Invite Server Transaction (IST)
    osip_transaction_t *transaction;
    osip_ist_new(&transaction, invite_request, osip);

    // 初始化事件
    osip_event_t *event;
    osip_event_init(&event, OSIP_IST_NEW, transaction, invite_request, NULL, NULL);

    // 处理事件
    osip_handle_events(osip);

    // 清理资源
    osip_message_free(invite_request);
    osip_transaction_free(transaction);
    osip_shutdown(osip);

    return 0;
}

osip_message

结构体

osip_message_t结构体用于表示一个完整的SIP消息,包括请求和响应消息。它包含了所有必要的头部字段、消息体以及其他相关信息

主要字段:

  • 版本信息 osip_version_t *version;
  • 请求行(仅限请求消息) osip_request_line_t *reqline;
  • 状态行(仅限响应消息) osip_status_line_t *statusline;
  • 头部字段 osip_list_t headers;
  • 消息体 char *body;
  • 缓冲区(存储整个SIP消息的原始字符串表示, 通过解析buffer可以填充其他字段。) char *buffer;
  • 长度 size_t length;
c 复制代码
struct osip_message
 {
		int						nm_nCh;						//对应nAppCh
		int						nm_BId;						//对应板卡的ID
		int                                     sip_length;//this sip message length
        char*     sip_version;                /**< SIP version (SIP request only) */
        osip_uri_t*    req_uri;     /**< Request-Uri (SIP request only) */
        char*     sip_method;                 /**< METHOD (SIP request only) */

        int      status_code;                /**< Status Code (SIP answer only) */
        char*     reason_phrase;              /**< Reason Phrase (SIP answer only) */

        osip_list_t    accepts;     /**< Accept headers */
        osip_list_t    accept_encodings;   /**< Accept-Encoding headers */
        osip_list_t    accept_languages;   /**< Accept-Language headers */
        osip_list_t    alert_infos;    /**< Alert-Info headers */
        osip_list_t    allows;      /**< Allows headers */
        osip_list_t    authentication_infos;  /**< authentication_info headers */
        osip_list_t    authorizations;    /**< Authorizations headers */
        osip_call_id_t*   call_id;     /**< Call-ID header */
        osip_list_t    call_infos;     /**< Call-Infos header */
        osip_list_t    contacts;     /**< Contacts headers */
        osip_list_t    content_encodings;   /**< Content-Encodings headers */
        osip_content_length_t* content_length;    /**< Content-Length header */
        osip_content_type_t* content_type;    /**< Content-Type header */
        osip_cseq_t*   cseq;      /**< CSeq header */
        osip_list_t    error_infos;    /**< Error-Info headers */
        osip_from_t*   from;      /**< From header */
        osip_mime_version_t* mime_version;    /**< Mime-Version header */
        osip_list_t    proxy_authenticates;  /**< Proxy-Authenticate headers */
        osip_list_t    proxy_authentication_infos; /**< P-Authentication-Info headers */
        osip_list_t    proxy_authorizations;  /**< Proxy-authorization headers */
        osip_list_t    record_routes;    /**< Record-Route headers */
        osip_list_t    routes;      /**< Route headers */
        osip_to_t*    to;       /**< To header */
        osip_list_t    vias;      /**< Vias headers */
        osip_list_t    www_authenticates;   /**< WWW-Authenticate headers */

        osip_list_t    headers;     /**< Other headers */
        osip_list_t    bodies;      /**< List of attachements */

        /*
         *1: structure and buffer "message" are identical.
         *2: buffer "message" is not up to date with the structure info
        *  (call osip_message_to_str to update it).
         */
        int      message_property;           /**@internal */
        char*     message;                    /**@internal */
        size_t     message_length;    /**@internal */
        void*     application_data;           /**can be used by upper layer*/
        
		/* +++ start +++ add by ykf problem:DS-45612 2016,04,29*/
        char 				remote_addr_from_iplayer[128];		//IP层获取的远端地址和端口,其实就是来源地址
		int	 				remote_port_from_iplayer; 			
		/*+++ end +++ problem:DS-45612 2016,04,29*/

		unsigned long		ulLocalSipUsedEthPort;		//要发送该SIP消息的本地SIP信令端口 用于多SIP端口时发送IVT时确定socket
		int					nNetNo; 

        char 				recv_register_hostaddr[128];		//register消息的来源地址
		int	 				recv_register_hostport; 			//register消息的来源地址的端口
		int                 ulids_addr; //ids 侵入检测源地址
	    char				bnoresource; //added by lqf for 资源不足需回复503
		char				bNotSupportPayload; //added by lqf for 编码格式不支持回复415
		char 				recv_addr[128];		//sip消息的来源地址
		int	 				recv_port; 			//sip消息的来源地址的端口

	    //+++start+++ added by ykf for	DS-50678  限制同一被叫号码外呼次数 2016.12.21
		int 	nCallFiledSipValue; //呼叫失败自定义SIP发送值
		//+++end+++ added by ykf for  DS-50678 
		int nSipSessionExpiresEnable;
};
code

主要函数:

  • 初始化和销毁

    osip_message_init(osip_message_t **): 初始化一个osip_message_t对象。

    osip_message_free(osip_message_t *): 释放一个osip_message_t对象及其占用的资源。

  • 解析和构建

    osip_message_parse(osip_message_t *, const char *, size_t): 解析一个SIP消息字符串buffer并填充osip_message_t对象。

    osip_message_to_str(osip_message_t *, char **, size_t *): 将osip_message_t对象转换为SIP消息字符串buffer

  • 获取和设置头部字段

    osip_message_get_header(const osip_message_t *, const char *, int): 获取指定名称的头部字段。

    osip_message_set_header(osip_message_t *, const char *, const char *): 设置指定名称的头部字段。

    osip_message_add_header(osip_message_t *, const char *, const char *): 添加一个新的头部字段

  • 处理请求和响应

    对于请求消息,可以通过osip_message_t->reqline访问请求行

    对于响应消息,可以通过osip_message_t->statusline访问状态行

c 复制代码
#include <osipparser2/osip_parser.h>
#include <osipparser2/osip_message.h>
#include <osipparser2/osip_header.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    osip_message_t *sip_message;

    // 初始化SIP消息
    osip_message_init(&sip_message);

    // 定义一个SIP请求字符串
    const char *request_str =
        "INVITE sip:[email protected] SIP/2.0\r\n"
        "Via: SIP/2.0/UDP localhost:5060;branch=z9hG4bK77ef4c2312983.1\r\n"
        "Max-Forwards: 70\r\n"
        "To: \"User\" <sip:[email protected]>\r\n"
        "From: \"Caller\" <sip:caller@localhost>;tag=12345\r\n"
        "Call-ID: unique-id@localhost\r\n"
        "CSeq: 1 INVITE\r\n"
        "Contact: <sip:user@localhost:5060>\r\n"
        "Content-Length: 0\r\n\r\n";

    // 解析SIP请求字符串
    osip_message_parse(sip_message, request_str, strlen(request_str));

    // 打印解析后的SIP消息
    printf("Parsed SIP Request:\n%s\n", sip_message->buffer);

    // 访问请求行
    printf("Request Line: %s %s %s\n",
           sip_message->reqline->method,
           sip_message->reqline->uri,
           sip_message->reqline->version);

    // 访问头部字段
    printf("Via: %s\n", sip_message->topvia->host);
    printf("From: %s <%s>\n", sip_message->from->displayname, sip_message->from->url->uri);
    printf("To: %s <%s>\n", sip_message->to->displayname, sip_message->to->url->uri);
    printf("Call-ID: %s\n", sip_message->callid->number);
    printf("CSeq: %d %s\n", sip_message->cseq->seq_number, sip_message->cseq->method);
    printf("Contact: %s\n", sip_message->contact->url->uri);

    // 构建一个新的SIP响应消息
    osip_message_t *response;
    osip_message_init(&response);

    // 设置版本
    osip_version_t *version;
    osip_version_init(&version);
    version->major = 2;
    version->minor = 0;
    response->version = version;

    // 设置状态行
    osip_status_line_t *statusline;
    osip_status_line_init(&statusline);
    statusline->code = 200;
    statusline->reason_phrase = osip_strdup("OK");
    response->statusline = statusline;

    // 复制一些头部字段
    osip_via_t *via;
    osip_via_clone(sip_message->topvia, &via);
    osip_list_add(&response->vias, via, -1);

    osip_from_t *from;
    osip_from_clone(sip_message->from, &from);
    response->from = from;

    osip_to_t *to;
    osip_to_clone(sip_message->to, &to);
    response->to = to;

    osip_call_id_t *callid;
    osip_call_id_clone(sip_message->callid, &callid);
    response->callid = callid;

    osip_cseq_t *cseq;
    osip_cseq_clone(sip_message->cseq, &cseq);
    response->cseq = cseq;

    // 添加Contact头字段
    osip_contact_t *contact;
    osip_contact_init(&contact);
    contact->url = osip_uri_clone(sip_message->to->url);
    osip_list_add(&response->contacts, contact, -1);

    // 设置内容长度
    response->contentlength = osip_content_length_init();
    response->contentlength->value = osip_strdup("0");

    // 转换为字符串
    char *response_buffer;
    size_t response_length;
    osip_message_to_str(response, &response_buffer, &response_length);

    // 打印构建后的SIP响应
    printf("Constructed SIP Response:\n%.*s\n", (int)response_length, response_buffer);

    // 清理资源
    osip_message_free(sip_message);
    osip_message_free(response);
    osip_free(response_buffer);

    return 0;
}

osip_event

osip_event 结构体在OSIP(Open Source Implementation of SIP)库中用于表示SIP事件。这些事件可以是各种类型的网络事件、定时器事件或其他与SIP处理相关的事件
主要字段:

  • type_t type 表示事件的类型。
  • int transactionid 标识与该事件相关的SIP事务ID
  • int sip_length 记录本SIP消息的长度。
  • unsigned int uinttick 标记这个事件产生的系统时间戳。
  • int socket 记录这个事件关联的套接字
  • osip_message_t sip* 存储与事件相关的SIP消息
c 复制代码
struct osip_event
	{
		type_t				type;           //Event Type
		int					transactionid;  //identifier of the related osip transaction
		int               	sip_length;//本SIP消息的长度
		unsigned int		uinttick;		//标记这个event产生的时间,用于上层计算系统的繁忙程度
		int					socket;			//记录这个事件关联的socket。用于tcp和tls协议。
		osip_message_t*		sip;			//SIP message (optional)
	};
code 打印接收到的SIP消息
c 复制代码
#include <osip2/osip.h>
#include <stdio.h>

void handle_sip_event(osip_event_t *event) {
    switch (event->type) {
        case OSIP_MESSAGE_RECEIVED:
            printf("Received SIP Message:\n");
            osip_message_to_str(event->sip, NULL);
            printf("%s\n", event->sip->message);
            break;
        case OSIP_TIMEOUT_NORESPONSE:
            printf("Timeout for transaction ID %d\n", event->transactionid);
            break;
        default:
            printf("Unhandled event type: %d\n", event->type);
            break;
    }
}

int main() {
    osip_event_t *event;

    // 初始化OSIP库
    if (osip_init(NULL) != 0) {
        fprintf(stderr, "Failed to initialize OSIP\n");
        return -1;
    }

    // 创建一个新的SIP事件
    event = osip_new_outgoing_sipmessage(OSIP_INVITE);
    if (event == NULL) {
        fprintf(stderr, "Failed to create a new SIP event\n");
        osip_free();
        return -1;
    }

    // 设置事件类型为接收消息
    event->type = OSIP_MESSAGE_RECEIVED;

    // 假设我们有一个SIP消息
    osip_message_t *sip_msg;
    if (osip_message_init(&sip_msg) != 0) {
        fprintf(stderr, "Failed to create a new SIP message\n");
        osip_free();
        return -1;
    }

    // 设置SIP方法为INVITE
    sip_msg->sip_method = osip_strdup("INVITE");

    // 设置请求URI
    if (osip_uri_parse(sip_msg->msg_osip, "sip:[email protected]", &sip_msg->req_uri) != 0) {
        fprintf(stderr, "Failed to parse request URI\n");
        osip_message_free(sip_msg);
        osip_free();
        return -1;
    }

    // 将SIP消息附加到事件
    event->sip = sip_msg;

    // 处理事件
    handle_sip_event(event);

    // 清理资源
    osip_message_free(sip_msg);
    osip_free();

    return 0;
}
相关推荐
uyeonashi39 分钟前
【Boost搜索引擎】构建Boost站内搜索引擎实践
开发语言·c++·搜索引擎
R_.L40 分钟前
Linux : 线程【同步与互斥】
linux
再睡一夏就好42 分钟前
从硬件角度理解“Linux下一切皆文件“,详解用户级缓冲区
linux·服务器·c语言·开发语言·学习笔记
zm3 小时前
TCP 粘包
服务器·网络·php
bjbxkj3 小时前
量子隧穿:PROFINET到Ethernet ip的无损耗协议转换方案转
网络·网络协议·tcp/ip
Smile丶凉轩4 小时前
Qt 界面优化(绘图)
开发语言·数据库·c++·qt
small_wh1te_coder5 小时前
从经典力扣题发掘DFS与记忆化搜索的本质 -从矩阵最长递增路径入手 一步步探究dfs思维优化与编程深度思考
c语言·数据结构·c++·stm32·算法·leetcode·深度优先
honey ball6 小时前
R & S的EMI接收机面板
linux·运维·网络
hjjdebug7 小时前
constexpr 关键字的意义(入门)
c++·constexpr
GBXLUO8 小时前
如何使用远程桌面控制电脑
服务器