SIP協議棧--osip源碼梳理

文章目錄

      • osip
      • osip主體
        • 結構體
        • code main函數
      • 狀態機轉化
        • 結構體
        • code狀態轉換
      • sip事務
        • 結構體
        • code
      • osip_dialog
        • 結構體
        • code 創建并發送200 OK響應
      • osip_message
        • 結構體
        • code
      • osip_event
        • code 打印接收到的SIP消息

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主體

結構體
struct osip
{void*							application_context;		//User defined Pointer// 用戶定義的指針,允許開發者存儲自定義的應用程序上下文數據//list of transactions for ict, ist, nict, nistosip_list_t						osip_ict_transactions;		//list of ict transactions// 客戶端事務(Invite Client Transaction, ICT)的列表, // 包含多個osip_transaction_t對象,每個對象表示一個具體的ICTosip_list_t						osip_ist_transactions;		//list of ist transactions// 服務器事務(Invite Server Transaction, IST)的列表//包含多個osip_transaction_t對象,每個對象表示一個具體的ISTosip_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 transactionsdict*							osip_ist_hastable;		  //htable of ist transactionsdict*							osip_nict_hastable;       //htable of nict transactionsdict*							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函數
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:user@example.com 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:user@example.com>\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;
}

狀態機轉化

結構體
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狀態轉換
#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到RUNNINGprocess_event(&fsm_instance, EVENT_PAUSE, transitions); // 從RUNNING到PAUSEDprocess_event(&fsm_instance, EVENT_RESUME, transitions);// 從PAUSED到RUNNINGprocess_event(&fsm_instance, EVENT_STOP, transitions);  // 從RUNNING到STOPPED// 清理資源free(start_transition);free(pause_transition);free(resume_transition);free(stop_transition);return 0;
}

sip事務

結構體
struct osip_transaction
{	void*				your_instance;      // User Defined Pointerint					transactionid;		// Internal Transaction Identifierosip_fifo_t*		transactionff;		// events must be added in this fifoosip_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 transactiontime_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 messageint					out_socket;         // Optional place for outgoing messagevoid*				config;             // internal transaction is managed by osip_t osip_fsm_type_t		ctx_type;			// Type of the transactionosip_ict_t*			ict_context;		// internalosip_ist_t*			ist_context;		// internalosip_nict_t*		nict_context;		// internalosip_nist_t*		nist_context;		// internalosip_srv_record_t	record;				// internal#ifdef FSM_TIMER_OUT_LISTunsigned short		usTimerCtrl;		// the timer start or stop controlunsigned short		usTimerFlag;		// the timer has or not deleted
#endif
#ifdef FSM_OPTIMIZM_ARRAYint					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響應。
  • 清理資源:
#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)及其響應序列。

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實例。
#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:user@example.com 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:user@example.com>\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;
struct osip_message{int						nm_nCh;						//對應nAppChint						nm_BId;						//對應板卡的IDint                                     sip_length;//this sip message lengthchar*     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時確定socketint					nNetNo; char 				recv_register_hostaddr[128];		//register消息的來源地址int	 				recv_register_hostport; 			//register消息的來源地址的端口int                 ulids_addr; //ids 侵入檢測源地址char				bnoresource; //added by lqf for 資源不足需回復503char				bNotSupportPayload; //added by lqf for 編碼格式不支持回復415char 				recv_addr[128];		//sip消息的來源地址int	 				recv_port; 			//sip消息的來源地址的端口//+++start+++ added by ykf for	DS-50678  限制同一被叫號碼外呼次數 2016.12.21int 	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訪問狀態行

#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:user@example.com 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:user@example.com>\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消息
struct osip_event{type_t				type;           //Event Typeint					transactionid;  //identifier of the related osip transactionint               	sip_length;//本SIP消息的長度unsigned int		uinttick;		//標記這個event產生的時間,用于上層計算系統的繁忙程度int					socket;			//記錄這個事件關聯的socket。用于tcp和tls協議。osip_message_t*		sip;			//SIP message (optional)};
code 打印接收到的SIP消息
#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方法為INVITEsip_msg->sip_method = osip_strdup("INVITE");// 設置請求URIif (osip_uri_parse(sip_msg->msg_osip, "sip:user@example.com", &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;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/80549.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/80549.shtml
英文地址,請注明出處:http://en.pswp.cn/web/80549.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Linux之Yum源與Nginx服務篇

1.Yum源知識理論總結概括 Yum源概述 Yum 源 即軟件倉庫的標識&#xff0c;里面承載著軟件包集合 Yum源組成 包含模塊 【OS】、【everything】、【EPOL】、【debuginfo】、【source】、【update-source】 【os】:簡稱operator system 它內部包含操作系統的核心組件&#x…

從單體架構到微服務:架構演進之路

引言&#xff1a;當“大貨車”遇上“集裝箱運輸” 在軟件開發領域&#xff0c;單體架構曾像一輛載滿貨物的大貨車&#xff0c;將所有功能打包在一個應用中。但隨著業務復雜度飆升&#xff0c;這輛“大貨車”逐漸陷入泥潭&#xff1a;啟動慢如蝸牛、故障波及全局、升級如履薄冰……

AM32電調學習解讀九:ESC上電啟動關閉全流程波形分析

這是第九篇&#xff0c;前面的文章把各個模塊的實現都介紹了一輪&#xff0c;本章是從運行的角度結合波形圖&#xff0c;把整個流程走一遍。 先看下一運行的配置&#xff0c;我把一些配置關閉了&#xff0c;這樣跑起來會好分析一些&#xff0c;不同配置跑起來效果會有差異。使用…

全球寵物經濟新周期下的亞馬遜跨境采購策略革新——寵物用品賽道成本優化三維路徑

在全球"孤獨經濟"與"銀發經濟"雙輪驅動下&#xff0c;寵物用品市場正經歷結構性增長。Euromonitor數據顯示&#xff0c;2023年全球市場規模突破1520億美元&#xff0c;其中中國供應鏈貢獻度達38%&#xff0c;跨境電商出口增速連續三年超25%。在亞馬遜流量紅…

reshape/view/permute的原理

在pytorch中&#xff0c;Tensor的存儲是行主序的&#xff0c;也就是意味著最后一個維度的元素的存儲時連續的&#xff0c;reshape和view并不改變元素存儲的內存&#xff0c;僅僅改變訪問的間隔&#xff0c;下面舉例說明&#xff1b; 比如一個23的Tensor在內存中的存儲是連續的&…

upload-labs靶場通關詳解:第11關

一、分析源代碼 $is_upload false; $msg null; if (isset($_POST[submit])) {if (file_exists(UPLOAD_PATH)) {$deny_ext array("php","php5","php4","php3","php2","html","htm","phtml"…

L1-7 最短字母串【保姆級詳細講解】

請你設計一個程序&#xff0c;該程序接受起始字母和目標字母作為輸入&#xff0c;通過在字母表中向前或向后移動來計算兩個給定字母之間的最短路徑。然后&#xff0c;程序會沿著最短路徑打印出從起始字母到目標字母的所有字母。例如&#xff0c;如果輸入“c”和“k”作為起始字…

項目QT+ffmpeg+rtsp(三)——延遲巨低的項目+雙屏顯示

文章目錄 前言雙屏顯示widget.cppwidget.h前言 對于復現情況,分為兩種情況 第一種,對于我而言,是直接解壓后,就能直接運行了 第二種,對于師兄而言,需要你構建debug后,會產生這個文件夾,執行的時候,地址應該在這,我猜的,這里面沒有dll,exe程序就找不到dll這些庫,你…

ansible進階06

復雜的循環結構 循環基礎 [studentworktest myansible]$ cat users.yml --- - name: create usershosts: serveratasks:- name: create some usersuser:name: "{{item}}"password: "{{123456|password_hash(sha512)}}"state: presentloop:- zhangsan- li…

Go 模塊版本管理

Go 模塊版本管理指南 1、創建帶注釋的 Git 標簽 基本命令 # 創建帶注釋的標簽 git tag -a v1.0.0 -m "Release version 1.0.0 - initial stable release" -a&#xff1a;創建帶注釋的標簽 -m&#xff1a;添加標簽注釋信息 # 推送標簽到遠程倉庫 git push origin v…

Java—— IO流 第一期

什么是IO流 存儲和讀取數據的解決方案 I&#xff1a;input O&#xff1a;output 流&#xff1a;像水流一樣傳輸數據 IO流的作用 用于讀寫數據(本地文件&#xff0c;網絡) IO流的分類 按照流向分類 輸出流&#xff1a;程序 --> 文件 輸入流&#xff1a;文件 --> 程序 按照…

物聯網安全技術的最新進展與挑戰

隨著物聯網&#xff08;IoT&#xff09;技術的飛速發展&#xff0c;越來越多的設備被連接到互聯網&#xff0c;從智能家居設備到工業控制系統&#xff0c;物聯網正在深刻改變我們的生活和生產方式。然而&#xff0c;物聯網的安全問題也日益凸顯&#xff0c;成為制約其發展的關鍵…

【深度學習基礎】損失函數與優化算法詳解:從理論到實踐

【深度學習基礎】損失函數與優化算法詳解&#xff1a;從理論到實踐 一、引言 1. 損失函數與優化算法在深度學習中的核心作用 在深度學習中&#xff0c;模型訓練的本質是通過不斷調整參數&#xff0c;使模型輸出盡可能接近真實值。這一過程的核心驅動力是損失函數&#xff08;…

mvc-review

review&#xff1a; 1.Servlet生命周期中初始化方法&#xff1a;init(),init(config) public void init(ServletConfig config) throws ServletException { this.config config; this.init(); } 因此&#xff0c;如果我們需要…

YouTube視頻字幕轉成文章算重復內容嗎?

很多創作者誤以為「自己說的話不算抄襲」&#xff0c;卻不知道YouTube自動生成的字幕早已被搜索引擎存檔。 去年就有案例&#xff1a;某美食博主將教程視頻字幕轉為圖文&#xff0c;結果原創度檢測僅42%&#xff0c;導致頁面權重暴跌。 本文揭秘5個實操技巧&#xff1a;從刪除…

R語言數據可視化

R note book 文檔–輸出html格式文檔&#xff0c;plotly不能生成PDF文件 --- title: "R語言數據可視化" output: html_notebook ---在R語言中進行數據可視化是數據分析和呈現的重要環節&#xff0c;R提供了多種強大的繪圖系統和工具。以下是常見的數據可視化方法和示…

Axure難點解決分享:垂直菜單展開與收回(4大核心問題與專家級解決方案)

親愛的小伙伴,在您瀏覽之前,煩請關注一下,在此深表感謝!如有幫助請訂閱專欄! Axure產品經理精品視頻課已登錄CSDN可點擊學習https://edu.csdn.net/course/detail/40420 課程主題:垂直菜單展開與收回 主要內容:超長菜單實現、展開與收回bug解釋、Axure9版本限制等問題解…

云原生攻防2(Docker基礎補充)

Docker基礎入門 容器介紹 Docker是什么 Docker是基于Linux內核實現,最早是采用了 LXC技術,后來Docker自己研發了runc技術運行容器。 它基于Google Go語言實現,采用客戶端/服務端架構,使用API來管理和創建容器。 虛擬機 VS Docker Namespace 內核命名空間屬于容器非常核…

Spring Boot 攔截器:解鎖5大實用場景

一、Spring Boot中攔截器是什么 在Spring Boot中&#xff0c;攔截器&#xff08;Interceptor&#xff09;是一種基于AOP&#xff08;面向切面編程&#xff09;思想的組件&#xff0c;用于在請求處理前后插入自定義邏輯&#xff0c;實現權限校驗、日志記錄、性能監控等非業務功能…

Vue百日學習計劃Day24-28天詳細計劃-Gemini版

總目標: 在 Day 24-27 熟練掌握 Vue.js 的各種模板語法&#xff0c;包括文本插值、屬性綁定、條件渲染、列表渲染、事件處理和表單綁定&#xff0c;并能結合使用修飾符。 所需資源: Vue 3 官方文檔 (模板語法): https://cn.vuejs.org/guide/essentials/template-syntax.htmlVu…