Files
svc.ems/plat/smpp/src/smpp_func.c
2024-10-18 16:54:41 +08:00

1168 lines
30 KiB
C

/*
** CDMA 2000 project, SMPP module
**
** File name: smpp_func.c
** Written by Li Long at 2004-11-25
** CVS $Id: smpp_func.c,v0.1 2004/11/25 17:03:14 lilong Exp $
**
*/
#include "./include/smpp.h"
#include "./include/smpp_def.h"
extern int register_ssn(BYTE ssn, BYTE usertype);
/* by simon at 23/9/26 */
SocketsMsg SockMsg;
int smpp_init_new(u8 sys_id)
{
smpp_system_no = sys_id & 0x01;
#ifdef SMPP_DEBUG
smpp_debugInit();
#endif //end ifdef SMPP_DEBUG
smpp_mibInit();
smpp_loadParam();
smpp_writeParam();
heartbeat_init(0xffff);
smpp_initTCPClient();
smpp_initTCPServer();
smpp_stateInit();
smpp_msgInit();
// if (FALSE == register_ssn(SMPP_PPS_SSN, SMPP_PPS_USERTYPE))
if (FALSE == register_ssn(SMPP_PPS_SSN, SMPP_SMSC_USERTYPE))
printf("SMPP register PPS SSN %d fail!\n", SMPP_PPS_SSN);
if (FALSE == register_ssn(SMPP_SMSC_SSN, SMPP_SMSC_USERTYPE))
printf("SMPP register SMSC SSN %d fail!\n", SMPP_SMSC_SSN);
printf("SMPP init........ Complete.\n");
return TRUE;
}
void smpp_reset()
{
int i;
for (i=0; i<MAX_SMPP_LINK; i++) {
if (smpp_param[i].link_type == SMPP_TCP)
smpp_closeTCPConnection(i);
}
close(Mysock.DaemonSock);
smpp_init_new(smpp_system_no);
for (i=0; i<MAX_SMPP_LINK; i++) {
if (callBackFunc[i].link_proc != NULL)
callBackFunc[i].link_proc(i, FALSE);
}
}
/*
return: bit7: 0-not fill, 1-fill
bit6-0: link number (<=128)
server_type: 0-SMPP_CLIENT; 1-SMPP_SERVER
session_type: 0-BIND_TX; 1-BIND_RX; 2-BIND_TRX
service_number_ptr: poiter to remote service number.
message_mode: 0-STORE_AND_FORWARD; 1-DATAGRAM; 2-TRANSACTION
*/
BYTE smpp_registerLink(BYTE server_type, BYTE session_type, char* service_number_ptr, BYTE message_mode)
{
char debugBuf[1024];
int i, len_get, len_in_para;
for (i=0; i<MAX_SMPP_LINK; i++) {
if ((smpp_param[i].link_enable & 0x01) == 0) continue;
if (smpp_param[i].session_type != session_type) continue;
if (smpp_param[i].server_type != server_type) continue;
if(smpp_param[i].local_ip>0x00 && smpp_param[i].local_ip != GetLocalIP()) continue;
len_get = strlen(service_number_ptr);
if (len_get > 8) {
service_number_ptr[8] = 0;
len_get = 8;
}
len_in_para = strlen(smpp_param[i].service_number);
if (len_in_para < len_get) {
if (strncmp(service_number_ptr, smpp_param[i].service_number, len_in_para) == 0) {
smpp_param[i].message_mode = message_mode;
return (BYTE)((i&0x7F)|0x80);
}
}
else {
if (strcmp(service_number_ptr, smpp_param[i].service_number) == 0) {
smpp_param[i].message_mode = message_mode;
return (BYTE)((i&0x7F)|0x80);
}
}
}
sprintf(debugBuf,"smpp_registerLink(server_type:%d,session_type:%d,service_number:%s,message_mode:%d) fail\r\n\r\n",server_type,session_type,service_number_ptr,message_mode);
smpp_send_error(debugBuf);
return 0;
}
void smpp_attach_link(BYTE linkNo, smpp_callBack_dataProc onDataRecv,
smpp_callBack_linkProc onLinkStateChange)
{
BYTE temp_status;
if(linkNo>=MAX_SMPP_LINK) return;
// removed by simon, 2023/11/04
// added by simon at 2024/06/12
smeg_debug_log("[smpp]link %d attached.\n", linkNo);
if(smpp_state[linkNo] == ESTABLISHED ||
smpp_state[linkNo] == SUSPEND)
{
if(callBackFunc[linkNo].link_proc!= NULL)
callBackFunc[linkNo].link_proc(linkNo,TRUE);
return;
}
else if(smpp_state[linkNo] == WAITING)
{
if(callBackFunc[linkNo].link_proc!= NULL)
callBackFunc[linkNo].link_proc(linkNo,FALSE);
return;
}
linkAttachFlag[linkNo] = TRUE;
smpp_state[linkNo] = IDLE;
temp_status = IDLE;
temp_status = temp_status<<((linkNo%4)*2);
smpp_hearbeat_status[linkNo/4] |= temp_status;
callBackFunc[linkNo].data_proc = onDataRecv;
callBackFunc[linkNo].link_proc = onLinkStateChange;
exterEvent[linkNo][exter_head[linkNo]] = Setup;
exter_head[linkNo] = (exter_head[linkNo]+1)&0x7;
if(SMPP_TCP == smpp_param[linkNo].link_type)
{
switch (smpp_param[linkNo].session_type) {
case BIND_TX:
case BIND_TRX:
if (smpp_param[linkNo].server_type == SMPP_CLIENT)
smpp_TCPClientFlag[linkNo] = 1;
break;
case BIND_RX:
if (smpp_param[linkNo].server_type == SMPP_SERVER)
smpp_TCPClientFlag[linkNo] = 1;
break;
}
}
}
WORD smpp_send(BYTE linkNo, SMPP_MSG* pMsg, WORD dataLen)
{
PDU_SUBMIT_SM *pSubmitSM;
PDU_SUBMIT_MULTI *pSubmitMulti;
PDU_DELIVER_SM *pDeliverSM;
PDU_DATA_SM *pDataSM;
PDU_QUERY_SM *pQuerySM;
PDU_CANCEL_SM *pCancelSM;
PDU_REPLACE_SM *pReplaceSM;
DWORD seqNum;
smeg_debug_log("\33[32mlink %d call smpp_send, message_type=%d\33[0m\n", linkNo, pMsg->message_type);
switch (pMsg->message_type)
{
case 0x0B: /* SUBMIT SM */
pSubmitSM = &pMsg->pdu.submit_sm;
pSubmitSM->head.command_id = htonl(SUBMIT_SM);
pSubmitSM->head.command_status = 0x0;
//seqNum = smpp_getSequenceNumber(linkNo);
//pSubmitSM->head.sequence_number = htonl(seqNum);
pSubmitSM->head.sequence_number = htonl(pSubmitSM->head.sequence_number);
smpp_encode_msg(linkNo, pMsg, SubmitSM);
break;
case 0x0C: /* SUBMIT SM RESP */
pMsg->pdu.submit_sm_resp.head.command_id = htonl(SUBMIT_SM_RESP);
seqNum = ntohl(pMsg->pdu.submit_sm_resp.head.sequence_number);
smpp_encode_msg(linkNo, pMsg, SubmitSMResp);
break;
case 0x0D: /* SUBMIT MULTI */
pSubmitMulti = &pMsg->pdu.submit_multi;
pMsg->pdu.submit_multi.head.command_id = htonl(SUBMIT_MULTI);
pMsg->pdu.submit_multi.head.command_status = 0x0;
//seqNum = smpp_getSequenceNumber(linkNo);
//pMsg->pdu.submit_multi.head.sequence_number = htonl(seqNum);
pSubmitMulti->head.sequence_number = htonl(pSubmitMulti->head.sequence_number);
smpp_encode_msg(linkNo, pMsg, SubmitMulti);
break;
case 0x0E: /* SUBMIT MULTI RESP */
pMsg->pdu.submit_multi_resp.head.command_id = htonl(SUBMIT_MULTI_RESP);
seqNum = ntohl(pMsg->pdu.submit_multi_resp.head.sequence_number);
smpp_encode_msg(linkNo, pMsg, SubmitMultiResp);
break;
case 0x0F: /* DELIVER SM */
pDeliverSM = &pMsg->pdu.deliver_sm;
pDeliverSM->head.command_id = htonl(DELIVER_SM);
pDeliverSM->head.command_status = 0x0;
//seqNum = smpp_getSequenceNumber(linkNo);
//pDeliverSM->head.sequence_number = htonl(seqNum);
pDeliverSM->head.sequence_number = htonl(pDeliverSM->head.sequence_number);
pDeliverSM->schedule_delivery_time = 0;
pDeliverSM->validity_period = 0;
pDeliverSM->replace_if_present_flag = 0;
pDeliverSM->sm_default_msg_id = 0;
smpp_encode_msg(linkNo, pMsg, DeliverSM);
break;
case 0x10: /* DELIVER SM RESP */
pMsg->pdu.deliver_sm.head.command_id = htonl(DELIVER_SM_RESP);
seqNum = ntohl(pMsg->pdu.deliver_sm.head.sequence_number);
smpp_encode_msg(linkNo, pMsg, DeliverSMResp);
break;
case 0x11: /* DATA SM */
pDataSM = &pMsg->pdu.data_sm;
pDataSM->head.command_id = htonl(DATA_SM);
pDataSM->head.command_status = 0x0;
//seqNum = smpp_getSequenceNumber(linkNo);
//pDataSM->head.sequence_number = htonl(seqNum);
pDataSM->head.sequence_number = htonl(pDataSM->head.sequence_number);
smpp_encode_msg(linkNo, pMsg, DataSM);
break;
case 0x12: /* DATA SM RESP */
pMsg->pdu.data_sm_resp.head.command_id = htonl(DATA_SM_RESP);
seqNum = ntohl(pMsg->pdu.data_sm_resp.head.sequence_number);
smpp_encode_msg(linkNo, pMsg, DataSMResp);
break;
case 0x13: /* QUERY SM */
pQuerySM = &pMsg->pdu.query_sm;
pMsg->pdu.query_sm.head.command_id = htonl(QUERY_SM);
pMsg->pdu.query_sm.head.command_status = 0x0;
//seqNum = smpp_getSequenceNumber(linkNo);
//pMsg->pdu.query_sm.head.sequence_number = htonl(seqNum);
pQuerySM->head.sequence_number = htonl(pQuerySM->head.sequence_number);
smpp_encode_msg(linkNo, pMsg, QuerySM);
break;
case 0x14: /* QUERY SM RESP */
pMsg->pdu.query_sm_resp.head.command_id = htonl(QUERY_SM_RESP);
seqNum = ntohl(pMsg->pdu.query_sm_resp.head.sequence_number);
smpp_encode_msg(linkNo, pMsg, QuerySMResp);
break;
case 0x15: /* CANCEL SM */
pCancelSM = &pMsg->pdu.cancel_sm;
pMsg->pdu.cancel_sm.head.command_id = htonl(CANCEL_SM);
pMsg->pdu.cancel_sm.head.command_status = 0x0;
//seqNum = smpp_getSequenceNumber(linkNo);
//pMsg->pdu.cancel_sm.head.sequence_number = htonl(seqNum);
pCancelSM->head.sequence_number = htonl(pCancelSM->head.sequence_number);
smpp_encode_msg(linkNo, pMsg, CancelSM);
break;
case 0x16: /* CANCEL SM RESP */
pMsg->pdu.cancel_sm_resp.head.command_id = htonl(CANCEL_SM_RESP);
seqNum = ntohl(pMsg->pdu.cancel_sm_resp.head.sequence_number);
smpp_encode_msg(linkNo, pMsg, CancelSMResp);
break;
case 0x17: /* REPLACE SM */
pReplaceSM = &pMsg->pdu.replace_sm;
pMsg->pdu.replace_sm.head.command_id = htonl(REPLACE_SM);
pMsg->pdu.replace_sm.head.command_status = 0x0;
//seqNum = smpp_getSequenceNumber(linkNo);
//pMsg->pdu.replace_sm.head.sequence_number = htonl(seqNum);
pReplaceSM->head.sequence_number = htonl(pReplaceSM->head.sequence_number);
smpp_encode_msg(linkNo, pMsg, ReplaceSM);
break;
case 0x18: /* REPLACE SM RESP */
pMsg->pdu.replace_sm_resp.head.command_id = htonl(REPLACE_SM_RESP);
seqNum = ntohl(pMsg->pdu.replace_sm_resp.head.sequence_number);
smpp_encode_msg(linkNo, pMsg, ReplaceSMResp);
break;
default:
smeg_debug_log("[ERROR]link %d no such message type!(=%02x)\n", linkNo, pMsg->message_type);
return 0;
}
return seqNum;
}
void smpp_close(BYTE linkNo)
{
exterEvent[linkNo][exter_head[linkNo]] = Close;
exter_head[linkNo] = (exter_head[linkNo]+1)&0x7;
}
void smpp_PrimitiveSend(int linkNo, int event_id)
{
switch (event_id)
{
case BindTransmitter:
smpp_sendBind(linkNo, BindTransmitter);
break;
case BindTransmitterResp:
smpp_sendBindResp(linkNo, BindTransmitterResp, 0);
break;
case BindReceiver:
smpp_sendBind(linkNo, BindReceiver);
break;
case BindReceiverResp:
smpp_sendBindResp(linkNo, BindReceiverResp, 0);
break;
case BindTransceiver:
smpp_sendBind(linkNo, BindTransceiver);
break;
case BindTransceiverResp:
smpp_sendBindResp(linkNo, BindTransceiverResp, 0);
break;
case Unbind:
smpp_sendUnbind(linkNo);
break;
case UnbindResp:
smpp_sendUnbindResp(linkNo);
break;
case EnquireLink:
smpp_sendEnquireLink(linkNo);
break;
case EnquireLinkResp:
smpp_sendEnquireLinkResp(linkNo);
break;
case Outbind:
smpp_sendOutbind(linkNo);
break;
default:
break;
}
}
void smpp_initTCPClintByLink(unsigned int linkNo)
{
int on=1, flag=1;
struct sockaddr_in local_addr;
if(linkNo>=MAX_SMPP_LINK) return;
if (((smpp_param[linkNo].link_enable & 0x01) == 0) || (smpp_param[linkNo].link_type == SMPP_UDP))
{
return;
}
if ((Mysock.client_sock[linkNo] = socket(AF_INET, SOCK_STREAM, 0))<0)
{
return;
}
if (setsockopt(Mysock.client_sock[linkNo], SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)
{
close(Mysock.client_sock[linkNo]);
return;
}
if (setsockopt(Mysock.client_sock[linkNo], SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) == -1)
{
close(Mysock.client_sock[linkNo]);
return;
}
if (fcntl(Mysock.client_sock[linkNo], F_SETFL, O_NONBLOCK) == -1)
{
close(Mysock.client_sock[linkNo]);
return;
}
/* Set this sockets as a Non-blocking sockets. */
if (ioctl(Mysock.client_sock[linkNo], FIONBIO, &flag) == -1)
{
close(Mysock.client_sock[linkNo]);
return;
}
bzero(&local_addr, sizeof(local_addr));
local_addr.sin_family = AF_INET;
local_addr.sin_addr.s_addr = GetLocalIP();//htonl(INADDR_ANY);
local_addr.sin_port = 0;
memset(local_addr.sin_zero, 0, sizeof(local_addr.sin_zero));
if (bind(Mysock.client_sock[linkNo], (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0)
{
perror("init TCP Client By Link: bind error");
exit(1);
}
}
void smpp_initTCPClient()
{
int i;
for (i=0; i<MAX_SMPP_LINK; i++)
{
smpp_initTCPClintByLink(i);
}
}
void smpp_tcp_connect(int link)
{
struct sockaddr_in server;
int on = 1, flag = 1;
server.sin_family = AF_INET;
server.sin_port = htons(SMPP_PORT);
server.sin_addr.s_addr = smpp_param[link].remote_ip;
/* Connect to the server. */
if (connect(Mysock.client_sock[link], (struct sockaddr *)&server, sizeof(server))<0)
{
if( EINPROGRESS !=errno && EALREADY != errno)//ch:Bad file descriptor
{
close(Mysock.client_sock[link]);
Mysock.client_sock[link]=0;
smpp_initTCPClintByLink(link);
/*
if ((Mysock.client_sock[link] = socket(AF_INET, SOCK_STREAM, 0))<0)
return;
if (setsockopt(Mysock.client_sock[link], SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)
{
close(Mysock.client_sock[link]);
return;
}
if (setsockopt(Mysock.client_sock[link], SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) == -1)
{
close(Mysock.client_sock[link]);
return;
}
if (fcntl(Mysock.client_sock[link], F_SETFL, O_NONBLOCK) == -1)
{
close(Mysock.client_sock[link]);
return;
}
if (ioctl(Mysock.client_sock[link], FIONBIO, &flag) == -1)
{
close(Mysock.client_sock[link]);
return;
}
*/
}
//perror("connect");
return;
}
/*
FD_SET(clientSockFd, &Mysock.readfds);
FD_SET(clientSockFd, &Mysock.writefds);
FD_SET(clientSockFd, &Mysock.exceptfds);
*/
Mysock.Sockets[link] = Mysock.client_sock[link];
Mysock.client_sock[link] =-1;
smeg_debug_log("[init TCP client]link %d socket number = %d\n", link, Mysock.Sockets[link]);
}
extern DWORD GetLocalIP();
void smpp_initTCPServer()
{
int serverSockFd;
int on=1;
struct sockaddr_in local_addr;
serverSockFd = socket(AF_INET, SOCK_STREAM, 0);
if (serverSockFd < 0)
{
perror("server socket error!");
exit(1);
}
//if ((serverSockFd = socket(AF_INET, SOCK_STREAM, 0))<0) { return (-1); }
if (setsockopt(serverSockFd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)
{
close(serverSockFd);
return;
}
if (setsockopt(serverSockFd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) == -1)
{
close(serverSockFd);
return;
}
if (fcntl(serverSockFd, F_SETFL, O_NONBLOCK) == -1)
{
close(serverSockFd);
return;
}
bzero(&local_addr, sizeof(local_addr));
local_addr.sin_family = AF_INET;
// local_addr.sin_addr.s_addr = inet_addr(smpp_getLocalIP());
local_addr.sin_addr.s_addr = GetLocalIP();//htonl(INADDR_ANY);
local_addr.sin_port = htons(SMPP_PORT);
memset(local_addr.sin_zero, 0, sizeof(local_addr.sin_zero));
// printf("Init TCP server: ip = %s, port = %d\n",
// inet_ntoa(local_addr.sin_addr),
// ntohs(local_addr.sin_port));
if (bind(serverSockFd, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0)
{
perror("bind error");
exit(1);
}
if (listen(serverSockFd, MAX_SMPP_LINK*2) < 0)
{
perror("listen error");
exit(1);
}
/*set this socket as a non-blocking socket.
if (ioctl(serverSockFd, FIONBIO, &flag) == -1)
{
perror("ioctl error");
close(serverSockFd);
}
*/
Mysock.DaemonSock = serverSockFd;
FD_SET(serverSockFd, &Mysock.readfds);
FD_SET(serverSockFd, &Mysock.exceptfds);
smeg_debug_log("init TCP server complete. socket number = %d.\n",serverSockFd);
}
WORD smpp_getServerPort()
{
static WORD offset = 0;
offset = offset % 1000;
return (offset + offset++);
}
DWORD smpp_getSequenceNumber(int linkNo)
{
DWORD sequence_number;
sequence_number = smpp_link[linkNo].seq_num;
sequence_number++;
smpp_link[linkNo].seq_num = sequence_number;
#ifdef SMPP_PRINT_SCREEN
// printf("link %d sequence number = %d.\n", linkNo, sequence_number);
#endif //end ifdef SMPP_PRINT_SCREEN
return sequence_number;
}
char *smpp_getLocalIP()
{
char hostname[128];
char *host_ip;
struct hostent *host;
if (gethostname(hostname,128) == 0)
{
if ((host = gethostbyname(hostname)) != NULL)
{
((struct in_addr *)(*host->h_addr_list))->s_addr = GetLocalIP();
host_ip = inet_ntoa(*(struct in_addr *)(*host->h_addr_list));
}
else
{
perror("[smpp] gethostbyname");
exit(2);
}
}
return host_ip;
}
int smpp_closeTCPConnection(int linkNo)
{
int retcode;
if ( (linkNo>=MAX_SMPP_LINK) || (linkNo<0) || (Mysock.Sockets[linkNo]<=0) )
return (0);
retcode = close(Mysock.Sockets[linkNo]);
FD_CLR(Mysock.Sockets[linkNo], &Mysock.readfds);
FD_CLR(Mysock.Sockets[linkNo], &Mysock.writefds);
FD_CLR(Mysock.Sockets[linkNo], &Mysock.exceptfds);
Mysock.Sockets[linkNo] = 0;
#ifdef SMPP_PRINT_SCREEN
// printf("link %d close TCP connection.\n", linkNo);
#endif
return (retcode);
}
int QuerySocketsMsg()
{
fd_set rfds,wfds,efds;
int retcode,i;
struct timeval TimeOut;
rfds = Mysock.readfds;
wfds = Mysock.writefds;
efds = Mysock.exceptfds;
TimeOut.tv_sec = 0;
TimeOut.tv_usec = 0;
bzero((char *)&SockMsg, sizeof(SockMsg));
if ((retcode = select(MAX_SMPP_LINK, &rfds, &wfds, &efds, &TimeOut)) == 0)
{
return (0);
}
if (FD_ISSET(Mysock.DaemonSock, &rfds))
{
SockMsg.AcceptNum = 1;
}
for (i=0; i<MAX_SMPP_LINK; i++)
{
if ((Mysock.Sockets[i]>0) && (FD_ISSET(Mysock.Sockets[i],&rfds)))
{
SockMsg.ReadQueue[SockMsg.ReadNum++] = i;
}
}
for (i=0; i<MAX_SMPP_LINK; i++)
{
if ((Mysock.Sockets[i]>0) && (FD_ISSET(Mysock.Sockets[i],&wfds)))
{
SockMsg.WriteQueue[SockMsg.WriteNum++] = i;
}
}
if (FD_ISSET(Mysock.DaemonSock, &efds))
{
SockMsg.AcceptNum = -1;
}
for (i=0; i<MAX_SMPP_LINK; i++)
{
if ((Mysock.Sockets[i]>0) && (FD_ISSET(Mysock.Sockets[i],&efds)))
{
SockMsg.WriteQueue[SockMsg.ExceptNum++] = i;
}
}
return (retcode);
}
int smpp_check_sysid_route(char* sysid_rv, BYTE sysidlen_rv, BYTE server_type, BYTE session_type)
{
int i;
char debugBuf[256];
for (i=0; i<MAX_SMPP_LINK; i++) {
if (linkAttachFlag[i] == FALSE) continue;
if ((smpp_param[i].link_enable & 0x01) == 0) continue;
if (smpp_param[i].server_type == server_type) continue;
if (smpp_param[i].session_type != session_type) continue;
#ifdef SMPP_DEBUG
if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[i] == 1)) {
sprintf(debugBuf,
"link: %d, link type: %d\n \
[RECEIVE] system id: %s, sysidlen: %d\n \
[PARAM] system id: %s\n",
i, smpp_param[i].link_type, sysid_rv, sysidlen_rv, smpp_param[i].sys_id);
smpp_send_ascout(debugBuf);
}
#endif
if (memcmp(sysid_rv, smpp_param[i].sys_id, sysidlen_rv) == 0)
return i;
}
return (-1);
}
void smpp_setSccpAddr(int linkNo, SCCP_ADDR *pSrcAddr, SCCP_ADDR *pDstAddr)
{
/* set SCCP source addr. */
pSrcAddr->RI = 0;
pSrcAddr->GTI = 4;
pSrcAddr->TT = 0;
pSrcAddr->NP = 1; /* MSISDN */
pSrcAddr->NAI = 4;
pDstAddr->SSN = smpp_param[linkNo].localSSN;
pSrcAddr->len = smpp_ascii2GTAI(pSrcAddr->GTAI, smpp_param[linkNo].localGTT);
/* set SCCP destination address. */
pDstAddr->RI = 0;
pDstAddr->GTI = 4;
pDstAddr->TT = 0;
pDstAddr->NP = 1; /* MSISDN */
pDstAddr->NAI = 4;
pDstAddr->SSN = smpp_param[linkNo].remoteSSN;
pDstAddr->len = smpp_ascii2GTAI(pDstAddr->GTAI, smpp_param[linkNo].remoteGTT);
}
BYTE smpp_ascii2GTAI(BYTE *pGTAI, char *pGTT)
{
BYTE len, bcd;
int i;
char debugBuf[1024];
len = strlen(pGTT);
if (len < 1) return 0;
if (len==16) len = 15;//last BYTE is ssn
for (i=0; i<len; i++)
{
bcd = pGTT[i]-'0';
if (i%2 == 0)
pGTAI[i/2] = 0|bcd;
else
pGTAI[i/2] = pGTAI[i/2]|(bcd<<4);
}
if (len%2 == 1)
pGTAI[(len-1)/2] |= 0xf0;
#ifdef SMPP_DEBUG
if (smppDebug.debug_switch == 1) {
sprintf(debugBuf, "GTAI: ");
for (i=0; i<(len+1)/2; i++)
{
sprintf(debugBuf+6+i*2, "%02X", pGTAI[i]);
}
debugBuf[6+i*2] = 0x0a;
debugBuf[7+i*2] = 0;
smpp_send_ascout(debugBuf);
}
#endif
/*
#ifdef SMPP_PRINT_SCREEN
printf("GTAI[]: ");
for (i=0; i<(len+1)/2; i++)
{
printf("0x%02x ", pGTAI[i]);
}
printf("\n");
#endif
*/
return len;
}
void smpp_GTAI2ascii(char *pGTT, BYTE *pGTAI, BYTE len)
{
BYTE i;
for (i=0; i<(len+1)/2; i++)
{
pGTT[i*2] = (pGTAI[i]&0xf) + '0';
if ((pGTAI[i]>>4) == 0xf)
{
pGTT[i*2+1] = '\0';
}
else
{
pGTT[i*2+1] = ((pGTAI[i]>>4)&0xf) + '0';
}
}
pGTT[len] = '\0';
}
void smpp_addTLV(BYTE *smpp_msg, WORD optionTag, BYTE *pMsg, WORD len)
{
WORD ns_optionTag;
WORD ns_len;
ns_optionTag = htons(optionTag);
switch (optionTag)
{
/* value 0 byte */
case ALERT_ON_MESSAGE_DELIVERY:
memcpy(smpp_msg, &ns_optionTag, 2);
len = 0;
memcpy(smpp_msg+2, &len, 2);
break;
/* value 1 byte for integer. */
case DEST_ADDR_SUBUNIT:
case SOURCE_ADDR_SUBUNIT:
case DEST_NETWORK_TYPE:
case SOURCE_NETWORK_TYPE:
case DEST_BEARER_TYPE:
case SOURCE_BEARER_TYPE:
case PRIVACY_INDICATOR:
case PAYLOAD_TYPE:
case LANGUAGE_INDICATOR:
case USER_RESPONSE_CODE:
case MS_MSG_WAIT_FACILITIES:
case SAR_TOTAL_SEGMENTS:
case SAR_SEGMENT_SEQNUM:
case SC_INTERFACE_VERSION:
case DISPLAY_TIME:
case MS_VALIDITY:
case DPF_RESULT:
case SET_DPF:
case MS_AVAILABILITY_STATUS:
case DELIVERY_FAILURE_REASON:
case MORE_MESSAGES_TO_SEND:
case MESSAGE_STATE:
case CALLBACK_NUM_PRES_IND:
case NUMBER_OF_MESSAGES:
case ITS_REPLY_TYPE:
case USSD_SERVICE_OP:
memcpy(smpp_msg, &ns_optionTag, 2);
len = 1;
ns_len = htons(len);
memcpy(smpp_msg+2, &ns_len, 2);
*(smpp_msg+4) = *pMsg;
break;
/* value 2 bytes for integer */
case DEST_TELEMATICS_ID:
case SOURCE_TELEMATICS_ID:
case USER_MESSAGE_REFERENCE:
case SOURCE_PORT:
case DESTINATION_PORT:
case SAR_MSG_REF_NUM:
case SMS_SIGNAL:
case ITS_SESSION_INFO:
memcpy(smpp_msg, &ns_optionTag, 2);
len = 2;
ns_len = htons(len);
memcpy(smpp_msg+2, &ns_len, 2);
memcpy(smpp_msg+4, pMsg, 2);
break;
/* value 3 bytes for octet string */
case NETWORK_ERROR_CODE:
memcpy(smpp_msg, &ns_optionTag, 2);
len = 3;
ns_len = htons(len);
memcpy(smpp_msg+2, &ns_len, 2);
memcpy(smpp_msg+4, pMsg, 3);
break;
/* value 4 bytes for integer */
case QOS_TIME_TO_LIVE:
memcpy(smpp_msg, &ns_optionTag, 2);
len = 4;
ns_len = htons(len);
memcpy(smpp_msg+2, &ns_len, 2);
memcpy(smpp_msg+4, pMsg, 4);
break;
/* variable length */
case ADDITIONAL_STATUS_INFO_TEXT:
case RECEIPTED_MESSAGE_ID:
case SOURCE_SUBADDRESS:
case DEST_SUBADDRESS:
case MESSAGE_PAYLOAD:
case CALLBACK_NUM:
case CALLBACK_NUM_ATAG:
memcpy(smpp_msg, &ns_optionTag, 2);
ns_len = htons(len);
memcpy(smpp_msg+2, &ns_len, 2);
memcpy(smpp_msg+4, pMsg, len+1);
break;
}
}
void smpp_display_hex_msg(BYTE* disp_ptr, int len)
{
int i;
char debugBuf[4096];
for (i=0; i<len; i++)
{
sprintf(debugBuf+i*3, "%02X ", disp_ptr[i]);
}
debugBuf[len*3] = 0x0a; //line feed
debugBuf[len*3+1] = 0;
smpp_send_ascout(debugBuf);
}
void smpp_command_id_to_string(char *comm_str, DWORD command_id)
{
switch (command_id)
{
case BIND_TRANSMITTER:
strcpy(comm_str, "BIND_TRANSMITTER");
break;
case BIND_TRANSMITTER_RESP:
strcpy(comm_str, "BIND_TRANSMITTER_RESP");
break;
case BIND_RECEIVER:
strcpy(comm_str, "BIND_RECEIVER");
break;
case BIND_RECEIVER_RESP:
strcpy(comm_str, "BIND_RECEIVER_RESP");
break;
case BIND_TRANSCEIVER:
strcpy(comm_str, "BIND_TRANSCEIVER");
break;
case BIND_TRANSCEIVER_RESP:
strcpy(comm_str, "BIND_TRANSCEIVER_RESP");
break;
case ENQUIRE_LINK:
strcpy(comm_str, "ENQUIRE_LINK");
break;
case ENQUIRE_LINK_RESP:
strcpy(comm_str, "ENQUIRE_LINK_RESP");
break;
case SUBMIT_SM:
strcpy(comm_str, "SUBMIT_SM");
break;
case SUBMIT_SM_RESP:
strcpy(comm_str, "SUBMIT_SM_RESP");
break;
case SUBMIT_MULTI:
strcpy(comm_str, "SUBMIT_MULTI");
break;
case SUBMIT_MULTI_RESP:
strcpy(comm_str, "SUBMIT_MULTI_RESP");
break;
case DELIVER_SM:
strcpy(comm_str, "DELIVER_SM");
break;
case DELIVER_SM_RESP:
strcpy(comm_str, "DELIVER_SM_RESP");
break;
case DATA_SM:
strcpy(comm_str, "DATA_SM");
break;
case DATA_SM_RESP:
strcpy(comm_str, "DATA_SM_RESP");
break;
case UNBIND:
strcpy(comm_str, "UNBIND");
break;
case UNBIND_RESP:
strcpy(comm_str, "UNBIND_RESP");
break;
case GENERIC_NAK:
strcpy(comm_str, "GENERIC_NAK");
break;
case OUTBIND:
strcpy(comm_str, "OUTBIND");
break;
default:
strcpy(comm_str, "\x1b[31mUnknown Command Id\x1b[0m");
break;
}
}
void smpp_command_status_to_string(char* status_str, DWORD command_status)
{
switch (command_status)
{
case ESME_ROK:
strcpy(status_str, "No Error");
break;
case ESME_RINVMSGLEN:
strcpy(status_str, "Message Length is invalid");
break;
case ESME_RINVCMDLEN:
strcpy(status_str, "Command Length is invalid");
break;
case ESME_RINVCMDID:
strcpy(status_str, "Invalid Command ID");
break;
case ESME_RINVBNDSTS:
strcpy(status_str, "Incorrect BIND status for given command");
break;
case ESME_RALYBND:
strcpy(status_str, "ESME Already in Bound State");
break;
case ESME_RINVPRTFLG:
strcpy(status_str, "Invalid Priority Flag");
break;
case ESME_RINVREGDLVFLG:
strcpy(status_str, "Invalid Registered Delivery Flag");
break;
case ESME_RSYSERR:
strcpy(status_str, "System Error");
break;
case ESME_RINVSRCADR:
strcpy(status_str, "Invalid Source Address");
break;
case ESME_RINVDSTADR:
strcpy(status_str, "Invalid Dest Addr");
break;
case ESME_RINVMSGID:
strcpy(status_str, "Message ID is invalid");
break;
case ESME_RBINDFAIL:
strcpy(status_str, "Bind Failed");
break;
case ESME_RINVPASWD:
strcpy(status_str, "Invalid Password");
break;
case ESME_RINVSYSID:
strcpy(status_str, "Invalid System ID");
break;
case ESME_RCANCELFAIL:
strcpy(status_str, "Cancel SM Failed");
break;
case ESME_RREPLACEFAIL:
strcpy(status_str, "Replace SM Failed");
break;
case ESME_RMSGQFUL:
strcpy(status_str, "Message Queue Full");
break;
case ESME_RINVSERTYP:
strcpy(status_str, "Invalid Service Type");
break;
case ESME_RINVNUMDESTS:
strcpy(status_str, "Invalid Number of Destinations");
break;
case ESME_RINVDLNAME:
strcpy(status_str, "Invalid Distribution List Name");
break;
case ESME_RINVDESTFLAG:
strcpy(status_str, "Destination flag is invalid");
break;
case ESME_RINVSUBREP:
strcpy(status_str, "Invalid 'submit with replace' reques( i.e. submit_sm with replace_if_present_flag set");
break;
case ESME_RINVESMCLASS:
strcpy(status_str, "Invalid esm_class filed data");
break;
case ESME_RCNTSUBDL:
strcpy(status_str, "Cannot Submit to Distribution List");
break;
case ESME_RSUBMITFAIL:
strcpy(status_str, "submit_sm or submit_multi failed");
break;
case ESME_RINVSRCTON:
strcpy(status_str, "Invalid Source address TON");
break;
case ESME_RINVSRCNPI:
strcpy(status_str, "Invalid Source address NPI");
break;
case ESME_RINVDSTTON:
strcpy(status_str, "Invalid Destination address TON");
break;
case ESME_RINVDSTNPI:
strcpy(status_str, "Invalid Destination address NPI");
break;
case ESME_RINVSYSTYP:
strcpy(status_str, "Invalid system_tpye field");
break;
case ESME_RINVREPFLAG:
strcpy(status_str, "Invalid replace_if_present flag");
break;
case ESME_RINVNUMMSGS:
strcpy(status_str, "Invalid number of messages");
break;
case ESME_RTHROTTLED:
strcpy(status_str, "Throttling error(ESME has exceeded allowed message limits)");
break;
case ESME_RINVSCHED:
strcpy(status_str, "Invalid Scheduled Delivery Time");
break;
case ESME_RINVEXPIRY:
strcpy(status_str, "Invalid message validity period(Expiry time)");
break;
case ESME_RINVDFTMSGID:
strcpy(status_str, "Predefined Message Invalid or Not Found");
break;
case ESME_RX_T_APPN:
strcpy(status_str, "ESME Receiver Temporary App Error Code");
break;
case ESME_RX_P_APPN:
strcpy(status_str, "ESME Receiver Permanent App Error Code");
break;
case ESME_RX_R_APPN:
strcpy(status_str, "ESME Receiver Reject Message Error Code");
break;
case ESME_RQUERYFAIL:
strcpy(status_str, "query_sm request failed");
break;
case ESME_RINVOPTPARSTREAM:
strcpy(status_str, "Error in the optional part of the PDU Body");
break;
case ESME_ROPTPARNOTALLWD:
strcpy(status_str, "Optional Parameter Length");
break;
case ESME_RINVPARSLEN:
strcpy(status_str, "Invalid Parameter Length");
break;
case ESME_RMISSINGOPTPARAM:
strcpy(status_str, "Expected Optional Parameter missing");
break;
case ESME_RINVOPTPARAMVAL:
strcpy(status_str, "Invalid Optional Parameter Value");
break;
case ESME_RDELIVERYFAILURE:
strcpy(status_str, "Delivery Failure (used for data_sm_resp)");
break;
case ESME_RUNKNOWNERR:
strcpy(status_str, "Unknown Error");
break;
default:
strcpy(status_str, "Reserved");
break;
}
}
void smpp_ton_to_string(char* ton_str, BYTE ton)
{
switch (ton)
{
case TON_UNKNOWN:
strcpy(ton_str, "Unknown");
break;
case TON_INTERNATIONAL:
strcpy(ton_str, "International");
break;
case TON_NATIONAL:
strcpy(ton_str, "National");
break;
case TON_NETWORK_SPECIFIC:
strcpy(ton_str, "Network Specific");
break;
case TON_SUBSCRIBER_NUMBER:
strcpy(ton_str, "Subscriber Number");
break;
case TON_ALPHANUMERIC:
strcpy(ton_str, "Alphanumeric");
break;
case TON_ABBREVIATE:
strcpy(ton_str, "Abbreviated");
break;
default:
strcpy(ton_str, "Reserved");
break;
}
}
void smpp_npi_to_string(char* npi_str, BYTE npi)
{
switch (npi)
{
case NPI_UNKNOWN:
strcpy(npi_str, "Unknown");
break;
case NPI_ISDN:
strcpy(npi_str, "ISDN(E163/E164)");
break;
case NPI_DATA:
strcpy(npi_str, "Data(X.121)");
break;
case NPI_TELEX:
strcpy(npi_str, "Telex(F.69)");
break;
case NPI_LAND_MOBILE:
strcpy(npi_str, "Land Mobile(E.212)");
break;
case NPI_NATIONAL:
strcpy(npi_str, "National");
break;
case NPI_PRIVATE:
strcpy(npi_str, "Private");
break;
case NPI_ERMES:
strcpy(npi_str, "ERMES");
break;
case NPI_INTERNET:
strcpy(npi_str, "Internet(IP)");
break;
default:
strcpy(npi_str, "Reserved");
break;
}
}
/* msg_ptr start with optional parameters. len=optional parameter total length */
int smpp_decode_optional_parameter(SMPP_OPTIONAL_PARAMETER* opt_ptr, BYTE* msg_ptr, int t_len)
{
int param_counter = 0, pointer = 0;
WORD tag = 0, len = 0;
char debugBuf[1024];
while (pointer < t_len)
{
tag = msg_ptr[pointer++];
tag = (tag<<8) + msg_ptr[pointer++];
opt_ptr[param_counter].tag = tag;
len = msg_ptr[pointer++];
len = (len<<8) + msg_ptr[pointer++];
opt_ptr[param_counter].len = len;
memcpy(&opt_ptr[param_counter].value, msg_ptr+pointer, len);
pointer = pointer + len;
#ifdef SMPP_DEBUG
sprintf(debugBuf, "optional parameter %d: tag = 0x%04X, len = %d, value[0] = 0x%02X",
param_counter, tag, len, *(msg_ptr+pointer));
//smpp_send_ascout(debugBuf);
//printf("%s\n", debugBuf);
#endif
param_counter++;
}
return param_counter;
}