/****************************************************************/ /* SIP UA Implementation Program */ /* Version 9.0.1 */ /* Designed By Francis */ /* Last Update: 2008-5-21 */ /****************************************************************/ #include "./include/sip_ua_pub.h" #include "./include/sip_ua_def.h" #include "./include/sip_ua_dialog.h" #include "./include/sip_ua_const.h" #include "./include/sip.h" #include "./include/sip_ext.h" #include "./include/sip_debug.h" #include "./include/sip_ua_msg.h" extern void sip_ua_fsm(WORD port); int sip_ua_get_local_ip(void) { struct hostent *host; if (gethostname(sipUaHostName, 50) == -1) { printf("SIP gethostname fail!\n"); return -1; } if ((host = gethostbyname(sipUaHostName)) == NULL) { printf("SIP gethostbyname fail!\n"); return -1; } else { sprintf(sipUaDottedHostIp, "%d.%d.%d.%d", (BYTE)host->h_addr_list[0][0], (BYTE)host->h_addr_list[0][1], (BYTE)host->h_addr_list[0][2], (BYTE)host->h_addr_list[0][3]); sipUaHostIp = inet_addr(sipUaDottedHostIp); // Network byte order sipHostIp, like 0xE60012AC printf("sipHostName: %s, sipHostIp: %s (0x%lX)\n", sipUaHostName, sipUaDottedHostIp, sipUaHostIp); } return 0; } int sip_ua_get_port() { int i; int port = sipUaPortSelect; if (port >= SIP_UA_MAX_NUM_OF_PORT) { sprintf((char *)sipAsciTempBuf, "sip_ua_get_port:port select have been changed\r\n"); sip_log_err(sipAsciTempBuf); port = 0; } for (i = 0; i < SIP_UA_MAX_NUM_OF_PORT; i++) { if (sipUaPort[port].flag == 1) { if (++port >= SIP_UA_MAX_NUM_OF_PORT) port = 0; continue; } sip_ua_init_port(port); sipUaPort[port].flag = 1; sipUaPortSelect = (port + 1)%SIP_UA_MAX_NUM_OF_PORT; return port; } return -1; } WORD sip_ua_match_dialog_with_req(SIP_API_STRUCT *request) { WORD i; BYTE method; SIP_HDR_CALL_ID *callId; char *toTag; char *fromTag; SIP_DIALOG *sipDlgPtr; char *branchRecv; if (request == NULL) { return SIP_UA_MAX_NUM_OF_DIALOG; } method = request->sipApiMsg.sipMsg.sipStartLine.sipMethod; branchRecv = request->sipApiMsg.sipMsg.sipHdrVias.vias[1].params.para[0].para.paraStr; callId = &request->sipApiMsg.sipMsg.sipHdrCallId; toTag = request->sipApiMsg.sipMsg.sipHdrTo.params.para[0].para.paraStr; fromTag = request->sipApiMsg.sipMsg.sipHdrFrom.params.para[0].para.paraStr; /* if (method == SIP_METHOD_INVITE) return SIP_UA_MAX_NUM_OF_DIALOG;*/ for (i = 0; i < SIP_UA_MAX_NUM_OF_DIALOG; i++) { sipDlgPtr = &sipUaDialog[i]; if ((sipDlgPtr->flag == 0) || (sipDlgPtr->state == SIP_UA_DIALOG_DESTROY) || (strcmp(sipDlgPtr->callId.value, callId->value) != 0) || (strcmp(sipDlgPtr->remoteTag, fromTag) != 0)) continue; if (method == SIP_METHOD_INVITE) return i; if (method == SIP_METHOD_CANCEL) { if ((sipDlgPtr->state < SIP_UA_DIALOG_WAIT_ACK_FOR_200) && (strcmp(sipDlgPtr->invBranch, branchRecv) == 0)) return i; else continue; } else { if (strcmp(sipDlgPtr->localTag, toTag) != 0) continue; return i; } } return SIP_UA_MAX_NUM_OF_DIALOG; } WORD sip_ua_match_dialog_with_rsp(SIP_API_STRUCT *response) { WORD i; SIP_HDR_CALL_ID *callId; char *toTag; char *fromTag; if (response == NULL) { return SIP_UA_MAX_NUM_OF_DIALOG; } callId = &response->sipApiMsg.sipMsg.sipHdrCallId; toTag = response->sipApiMsg.sipMsg.sipHdrTo.params.para[0].para.paraStr; fromTag = response->sipApiMsg.sipMsg.sipHdrFrom.params.para[0].para.paraStr; for (i = 0; i < SIP_UA_MAX_NUM_OF_DIALOG; i++) { if ((sipUaDialog[i].flag == 0) || (strcmp(sipUaDialog[i].callId.value, callId->value) != 0) || (strcmp(sipUaDialog[i].localTag, fromTag) != 0)) continue; if (sipUaDialog[i].state < SIP_UA_DIALOG_WAIT_ACK_FOR_200) { return i; } else { if (strcmp(sipUaDialog[i].remoteTag, toTag) != 0) continue; return i; } } return SIP_UA_MAX_NUM_OF_DIALOG; } int sip_ua_select_user_by_domain(SIP_API_STRUCT *sipApiMsg) { int i; SIP_URI *sipUri; if (sipApiMsg == NULL) return -1; sipUri = &sipApiMsg->sipApiMsg.sipMsg.sipStartLine.requestUri; for (i = 0; i < SIP_UA_MAX_NUM_OF_SAP; i++) { if ((sipUaSaps[i].flag == 1) && (strcmp(sipUaSaps[i].sipUaSap.domain, sipUri->host.addr.domain) == 0)) return i; } return -1; } int sip_ua_check_retransmit_invit(SIP_API_STRUCT *sipApiMsg) { SIP_HDR_CALL_ID *callId; char *fromTag; int i; callId = &sipApiMsg->sipApiMsg.sipMsg.sipHdrCallId; fromTag = sipApiMsg->sipApiMsg.sipMsg.sipHdrFrom.params.para[0].para.paraStr; for (i = 0; i < SIP_UA_MAX_NUM_OF_PORT; i++) { if (sipUaPort[i].flag != 1) continue; if ((strcmp(sipUaPort[i].callStruct.callId.value, callId->value) == 0) && (strcmp(sipUaPort[i].callStruct.callId.host, callId->host) == 0) && (strcmp(sipUaPort[i].callStruct.fromTag, fromTag) == 0)) return i; } return -1; } int sip_ua_allocate_port_for_req(BYTE method, SIP_API_STRUCT *sipApiMsg) { int port; if (((sipApiMsg->sipApiMsg.sipMsg.sipGenHdrFlag[0] & SIP_HDR_EXPIRES_MASK) == SIP_HDR_EXPIRES_MASK) && (sipApiMsg->sipApiMsg.sipMsg.sipHdrExpires.value == 0)) { sprintf((char *)sipAsciTempBuf, "sip_ua_allocate_port_for_req:expier value is 0\r\n"); sip_log_err(sipAsciTempBuf); return -2; } if ((port = sip_ua_get_port()) < 0) { sprintf((char *)sipAsciTempBuf, "sip_ua_allocate_port_for_req:no enough resource\r\n"); sip_log_err(sipAsciTempBuf); return -1; } sipUaPort[port].sipuafState = SIP_UA_FSM_STATE_INDICATE; sipUaPort[port].mainState = SIP_UA_MAIN_STATE_IDLE; if ((sipApiMsg->sipApiMsg.sipMsg.sipGenHdrFlag[0] & SIP_HDR_EXPIRES_MASK) == SIP_HDR_EXPIRES_MASK) { sipUaPort[port].sipuafTimer = (sipApiMsg->sipApiMsg.sipMsg.sipHdrExpires.value * 100); } else { sipUaPort[port].sipuafTimer = SIP_UA_FSM_TIMER; } sipUaPort[port].rcvCmd = method; return port; } int sip_ua_sip_recv_proc(WORD sipPort, WORD upPort, BYTE transFlag, SIP_API_STRUCT *sipApiMsg) { int ret; // int sapIndex; WORD dialogId; BYTE method; int statusCode; SIP_API_STRUCT sdSipMsg; int port; DWORD usrPort; pal_cg_struct *cg; char *localDomain; char *destDomain; SIP_EVENTHANDLE_STRUCT *event_handle = NULL; if (sipApiMsg == NULL) return -1; localDomain = sipApiMsg->sipApiMsg.sipMsg.sipStartLine.requestUri.host.addr.domain; destDomain = sipApiMsg->sipApiMsg.sipMsg.sipHdrVias.vias[sipApiMsg->sipApiMsg.sipMsg.sipHdrVias.head].url.domain; memset(&sipUaRecvMsg, 0, sizeof(SIP_API_STRUCT)); switch(transFlag) { case SIP_TRANSPORT_LAYER: if (sipApiMsg->sipApiType == SIP_API_REQ_MSG) { /* if ((sapIndex = sip_ua_select_user_by_domain(sipApiMsg)) < 0) { sprintf(sipAsciTempBuf, "sip ua recv msg can not find user\r\n"); sip_log_err(sipAsciTempBuf); return -1; }*/ if ((cg = (pal_cg_struct *)pal_sip_find_cg(localDomain, destDomain)) == NULL) { sprintf((char *)sipAsciTempBuf, "sip_ua_sip_recv: can not find cg!\r\n"); sip_log_err(sipAsciTempBuf); return -1; } if ((dialogId = sip_ua_match_dialog_with_req(sipApiMsg)) >= SIP_UA_MAX_NUM_OF_DIALOG) dialogId = SIP_UA_NULL_DIALOG; method = sipApiMsg->sipApiMsg.sipMsg.sipStartLine.sipMethod; if ((method == SIP_METHOD_INVITE) && (dialogId <= SIP_UA_MAX_NUM_OF_DIALOG)) { sprintf((char *)sipAsciTempBuf, "sip ua recv retransmitted invite\r\n"); sip_log_err(sipAsciTempBuf); return 0; } if (((method == SIP_METHOD_RE_INVITE) || (method == SIP_METHOD_CANCEL) || (method == SIP_METHOD_ACK) || (method == SIP_METHOD_BYE) || (method == SIP_METHOD_INFO)) && (dialogId == SIP_UA_NULL_DIALOG)) { if (method != SIP_METHOD_ACK) { memcpy(&sdSipMsg, sipApiMsg, sizeof(SIP_API_STRUCT)); sdSipMsg.sipApiType = SIP_API_RES_MSG; sdSipMsg.sipApiMsg.sipMsg.sipStartLine.statusCode = 481; strcpy(sdSipMsg.sipApiMsg.sipMsg.sipStartLine.reasonPhrase, "Call/Transaction Does Not Exist"); sdSipMsg.sipApiMsg.sipMsg.sipEntity.sipHdrContentLength = 0; sdSipMsg.sipApiMsg.sipMsg.sipGenHdrFlag[0] = SIP_HDR_CALL_ID_MASK | SIP_HDR_CSEQ_MASK | SIP_HDR_FROM_MASK | SIP_HDR_TO_MASK | SIP_HDR_VIA_MASK; sdSipMsg.sipApiMsg.sipMsg.sipReStruct.sipReHdrFlag[0] = 0; sip_send_msg(SIP_NULL_TRANS_ID, SIP_NULL_UP_PORT, SIP_TRANSPORT_LAYER, &sdSipMsg); } sprintf((char *)sipAsciTempBuf, "sip ua recv a inside msg without relational dialog\r\n"); sip_log_err(sipAsciTempBuf); return -7; } if (dialogId < SIP_UA_NULL_DIALOG) { if ((method != SIP_METHOD_ACK) && (method != SIP_METHOD_CANCEL)) { if ((ret =sip_ua_update_dialog_with_req(dialogId, sipApiMsg)) < 0) { if (ret == -2) { //need forward develop memset(&sdSipMsg, 0, sizeof(SIP_API_STRUCT)); memcpy(&sdSipMsg, sipApiMsg, sizeof(SIP_API_STRUCT)); sdSipMsg.sipApiType = SIP_API_RES_MSG; sdSipMsg.sipApiMsg.sipMsg.sipStartLine.statusCode = 500; strcpy( sdSipMsg.sipApiMsg.sipMsg.sipStartLine.reasonPhrase, "Server Internal Error"); sdSipMsg.sipApiMsg.sipMsg.sipEntity.sipHdrContentLength = 0; sdSipMsg.sipApiMsg.sipMsg.sipGenHdrFlag[0] = SIP_HDR_CALL_ID_MASK | SIP_HDR_CSEQ_MASK | SIP_HDR_FROM_MASK | SIP_HDR_TO_MASK | SIP_HDR_VIA_MASK; sdSipMsg.sipApiMsg.sipMsg.sipReStruct.sipReHdrFlag[0] = 0; sip_send_msg(SIP_NULL_TRANS_ID, SIP_NULL_UP_PORT, SIP_TRANSPORT_LAYER, &sdSipMsg); } sprintf((char *)sipAsciTempBuf, "sip_ua_sip_recv:update dialog with req failed, ret=%d\r\n", ret); sip_log_err(sipAsciTempBuf); return -1; } } else { if (sipApiMsg->sipApiMsg.sipMsg.sipHdrCseq.value != sipUaDialog[dialogId].remoteInvCseq) { sprintf((char *)sipAsciTempBuf, "sip_ua_sip_recv:ack or cancel cseq is not equal to invite\r\n"); sip_log_err(sipAsciTempBuf); return -6; } } } if (method != SIP_METHOD_ACK) { if (method == SIP_METHOD_INVITE) { if (sip_ua_check_retransmit_invit(sipApiMsg) >= 0) { sprintf((char *)sipAsciTempBuf, "sip_ua_sip_recv:retransmit invit already in progress\r\n"); sip_log_err(sipAsciTempBuf); return 0; } } if ((port = sip_ua_allocate_port_for_req(method, sipApiMsg)) < 0) { if (port == -2) { memset(&sdSipMsg, 0, sizeof(SIP_API_STRUCT)); memcpy(&sdSipMsg, sipApiMsg, sizeof(SIP_API_STRUCT)); sdSipMsg.sipApiType = SIP_API_RES_MSG; sdSipMsg.sipApiMsg.sipMsg.sipStartLine.statusCode = 487; strcpy(sdSipMsg.sipApiMsg.sipMsg.sipStartLine.reasonPhrase, "Request Terminated"); sdSipMsg.sipApiMsg.sipMsg.sipEntity.sipHdrContentLength = 0; sdSipMsg.sipApiMsg.sipMsg.sipGenHdrFlag[0] = SIP_HDR_CALL_ID_MASK | SIP_HDR_CSEQ_MASK | SIP_HDR_FROM_MASK | SIP_HDR_TO_MASK | SIP_HDR_VIA_MASK; sdSipMsg.sipApiMsg.sipMsg.sipReStruct.sipReHdrFlag[0] = 0; sip_send_msg(SIP_NULL_TRANS_ID, SIP_NULL_UP_PORT, SIP_TRANSPORT_LAYER, &sdSipMsg); } else { sprintf((char *)sipAsciTempBuf, "sip_ua_sip_recv:no enough resource\r\n"); sip_log_err(sipAsciTempBuf); } return -1; } if (method == SIP_METHOD_INVITE) { memcpy(&sipUaPort[port].callStruct.callId, &sipApiMsg->sipApiMsg.sipMsg.sipHdrCallId, sizeof(SIP_HDR_CALL_ID)); strcpy(sipUaPort[port].callStruct.fromTag, sipApiMsg->sipApiMsg.sipMsg.sipHdrFrom.params.para[0].para.paraStr); /* cg = pal_sip_find_cg(sipApiMsg->sipApiMsg.sipMsg.sipHdrVias.vias[sipApiMsg->sipApiMsg.sipMsg.sipHdrVias.head].url.host.addr.domain); if (cg == NULL) { sprintf(sipAsciTempBuf, "sip_ua_sip_recv: Invite req can not find cg!\r\n"); sip_log_err(sipAsciTempBuf); sip_ua_init_port(port); return -1; }*/ sip_ua_set_inv_temp_rsp(port, sipApiMsg); usrPort = SIP_UA_NULL_UP_PORT; } else { if (dialogId < SIP_UA_MAX_NUM_OF_DIALOG) { usrPort = sipUaDialog[dialogId].usrPort; sipUaDialog[dialogId].sipUaPort = port; } else { usrPort = SIP_UA_NULL_UP_PORT; } // cg = NULL; } event_handle = (SIP_EVENTHANDLE_STRUCT *)pal_get_handler(cg->id); event_handle->recv_req(port, usrPort, dialogId, method, sipApiMsg, cg); // sipUaSaps[sapIndex].sipUaSap.recv_req(port, usrPort, dialogId, method, sipApiMsg, cg); } else { if (sipUaDialog[dialogId].uaPort >= SIP_UA_MAX_NUM_OF_PORT) { sprintf((char *)sipAsciTempBuf, "sip_ua_sip_recv:recv ack, but no port in dialog to proc inv rsp\r\n"); sip_log_err(sipAsciTempBuf); return -3; } sipUaPort[sipUaDialog[dialogId].uaPort].rcvCmd = SIP_METHOD_ACK; memcpy(&sipUaRecvMsg, sipApiMsg, sizeof(SIP_API_STRUCT)); sip_ua_fsm(sipUaDialog[dialogId].uaPort); } } else { if ((sipApiMsg->sipApiMsg.sipMsg.sipHdrCseq.method == SIP_METHOD_INVITE) && (sipApiMsg->sipApiMsg.sipMsg.sipStartLine.statusCode == 200) && ((dialogId = sip_ua_match_dialog_with_rsp(sipApiMsg)) < SIP_UA_MAX_NUM_OF_DIALOG)) { if (sipUaDialog[dialogId].uaAckPort >= SIP_UA_MAX_NUM_OF_PORT) { sprintf((char *)sipAsciTempBuf, "sip_ua_sip_recv:recv retransmitted 200, no ack proc port in dialog\r\n"); sip_log_err(sipAsciTempBuf); return -5; } sipUaPort[sipUaDialog[dialogId].uaAckPort].rcvCmd = 200; memcpy(&sipUaRecvMsg, sipApiMsg, sizeof(SIP_API_STRUCT)); sip_ua_fsm(sipUaDialog[dialogId].uaAckPort); } else { sprintf((char *)sipAsciTempBuf, "sip_ua_sip_recv:recv rsp from transport layer\r\n"); sip_log_err(sipAsciTempBuf); return -4; } } break; case SIP_TRANSACTION_LAYER: if ((upPort >= SIP_UA_MAX_NUM_OF_PORT) || (sipUaPort[upPort].flag != 1)) { return -1; } if (sipApiMsg->sipApiType == SIP_API_REQ_MSG) { sprintf((char *)sipAsciTempBuf, "sip_ua_sip_recv:recv req from transaction layer\r\n"); sip_log_err(sipAsciTempBuf); return -1; } else { if ((dialogId = sip_ua_match_dialog_with_rsp(sipApiMsg)) >= SIP_UA_MAX_NUM_OF_DIALOG) dialogId = SIP_UA_NULL_DIALOG; if (sipUaPort[upPort].dialogId != dialogId) { sprintf((char *)sipAsciTempBuf, "sip_ua_sip_recv:find dialog wrong\r\n"); sip_log_err(sipAsciTempBuf); dialogId = sipUaPort[upPort].dialogId; // return -1; } if ((dialogId < SIP_UA_MAX_NUM_OF_DIALOG) && (sipUaPort[upPort].cgId != sipUaDialog[dialogId].cgId))//sipUaPort[upPort].sapIndex != sipUaDialog[dialogId].userIndex { sprintf((char *)sipAsciTempBuf, "sip_ua_sip_recv: cg id wrong\r\n"); sip_log_err(sipAsciTempBuf); return -1; } statusCode = sipApiMsg->sipApiMsg.sipMsg.sipStartLine.statusCode; sipUaPort[upPort].rcvCmd= statusCode; memcpy(&sipUaRecvMsg, sipApiMsg, sizeof(SIP_API_STRUCT)); sip_ua_fsm(upPort); } break; default: return -1; } return 0; } int sip_ua_init_dialog(WORD dialogId) { if (dialogId >= SIP_UA_MAX_NUM_OF_DIALOG) { return -1; } memset(&sipUaDialog[dialogId], 0, sizeof(SIP_DIALOG)); sipUaDialog[dialogId].uaPort = 0xFFFF; sipUaDialog[dialogId].uaAckPort = 0xFFFF; return 0; } int sip_ua_init_port(WORD port) { if (port >= SIP_UA_MAX_NUM_OF_PORT) { return -1; } memset(&sipUaPort[port], 0, sizeof(SIP_UA_PORT)); sipUaPort[port].dialogId = SIP_UA_NULL_DIALOG; sipUaPort[port].llPort = 0xFFFF; sipUaPort[port].usrPort = 0xFFFF; return 0; } void sip_ua_timer() { WORD port; for (port = 0; port < SIP_UA_MAX_NUM_OF_PORT; port++) { if (sipUaPort[port].flag == 0) continue; sip_ua_fsm(port); } sip_t10ms(); } int sip_ua_regist_in_sip() { sipUaSipUser.proxyType= SIP_PROXY_TYPE_NONE; strcpy(sipUaSipUser.userName, "SIP_UA"); strcpy(sipUaSipUser.domain, sipUaDottedHostIp); sipUaSipUser.recv_proc = sip_ua_sip_recv_proc; if ((sipUaSipIndex = sip_register_user(&sipUaSipUser)) < 0) { printf("SIP UA Module register in SIP Module Failed\r\n"); return -1; } return 0; } int sip_ua_init() { WORD i; printf("SIP UA Module Init Start!\n"); if (sip_ua_get_local_ip() < 0) exit(1); if (sip_ua_regist_in_sip() < 0) { printf("SIP UA Module regist in sip fail\r\n"); } sipUaPortSelect = 0; sipUaDialogSelect = 0; for (i = 0; i < SIP_UA_MAX_NUM_OF_DIALOG; i++) { sip_ua_init_dialog(i); } for (i = 0; i < SIP_UA_MAX_NUM_OF_PORT; i++) { sip_ua_init_port(i); } memset((BYTE *)&sipUaSaps[0], 0, sizeof(SIP_UA_SAPS) * SIP_UA_MAX_NUM_OF_SAP); memset((BYTE *)&sipUaRecvMsg, 0, sizeof(SIP_API_STRUCT)); printf("SIP UA Module Init Complete!\n"); return 0; } /*int sip_ua_bind(SIP_UA_SAP *sap) { BYTE sapIndex; if ((sap == NULL) || (sap->recv_req == NULL) || (sap->recv_resp == NULL) || (sap->proxyType != SIP_PROXY_TYPE_NONE)) { sprintf(sipAsciTempBuf, "sip_ua_bind:sap malformed\r\n"); sip_log_err(sipAsciTempBuf); return -1; } for (sapIndex = 0; sapIndex < SIP_UA_MAX_NUM_OF_SAP; sapIndex++) { if ((sipUaSaps[sapIndex].flag == 1) && (strcmp(sipUaSaps[sapIndex].sipUaSap.userName, sap->userName) == 0)) { memcpy(&sipUaSaps[sapIndex].sipUaSap, sap, sizeof(SIP_UA_SAP)); if (sip_store_sip_ua_user(sapIndex, sap->domain) < 0) { sprintf(sipAsciTempBuf, "sip_ua_bind:sip store sip ua user failed!\r\n"); sip_log_err(sipAsciTempBuf); } return sapIndex; } } for (sapIndex = 0; sapIndex < SIP_UA_MAX_NUM_OF_SAP; sapIndex++) { if (sipUaSaps[sapIndex].flag != 0) continue; sipUaSaps[sapIndex].flag = 1; memcpy((BYTE *)&sipUaSaps[sapIndex].sipUaSap, sap, sizeof(SIP_UA_SAP)); if (sip_store_sip_ua_user(sapIndex, sap->domain) < 0) { sprintf(sipAsciTempBuf, "sip_ua_bind:sip store sip ua user failed\r\n"); sip_log_err(sipAsciTempBuf); } return sapIndex; } sprintf(sipAsciTempBuf, "sip ua user bind fail\r\n"); sip_log_err(sipAsciTempBuf); return -1; }*/