#pragma module SMPP$ESME_SYMBIONT "SMPP$ESME_SYMBIONT-1-X" #define __MODULE__ "SMPP$ESME_SYMBIONT" /* **++ ** FACILITY: SMPP/ESME Symbiont ** ** MODULE DESCRIPTION: ** It's queue processor formed as VMS Symbiont, it implements a SMPP/ESME client ** functionality to sending Short Messages to Short Message Service Center. ** ** AUTHORS: ** ** Ruslan R. Laishev ** ** CREATION DATE: 9-OCT-2002 ** ** BUILD: ** $ CC /NOWARNING/INCLUDE=[] SMPP$ESME_SYMBIONT.C+SYS$LIBRARY:SYS$LIB_C.TLB /LIBRARY ** $ LINK SMPP$ESME_SYMBIONT,SYS$INPUT/OPT ** ESME_API_SHR/SHARE ** SYS$SHARE:SMBSRVSHR/SHARE ** ^Z ** ** INSTALLATION: ** $ COPY SMPP$ESME_SYMBIONT.EXE SYS$COMMON:[SYSEXE] ** $ INITIALIZE /QUEUE /NODEVICE /PROCESSOR=SMPP$ESME_SYMBIONT ** ** $ SET SECURITY /OBJECT=QUEUE /ACL=(...) ** $ SET SECURITY /OBJECT=QUEUE /PROTECTION=(...) ** ** $ DEFINE/SYSTEM/TABLE=LNM$GROUP_000001 SMPP$ESME_ "SMSC.ZZTop.NET:9000/////" ** $ START /QUEUE ** ** DESIGN ISSUES: ** ** It's a VMS symbiont. ** ** ** MODIFICATION HISTORY: ** ** {@tbs@}... **-- */ /* ** ** INCLUDE FILES ** */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define __NEW_STARLET 1 #include #undef __NEW_STARLET /* ** ** SMPP AND ESME API INCLUDE FILES ** */ #include "smppdef.h" #include "esme_msg.h" /* ** ** MACRO DEFINITIONS ** */ #define min(x,y) ((x > y)?y:x) #define max(x,y) ((x < y)?y:x) #define INIT_SDESC(dsc, len, ptr) {(dsc).dsc$b_dtype = DSC$K_DTYPE_T;\ (dsc).dsc$b_class = DSC$K_CLASS_S; (dsc).dsc$w_length = (short) (len);\ (dsc).dsc$a_pointer = (ptr);} /* ** Logical supposed to keep a configuration information for a symbiont: ** ** "IP:TCP-Port/System Id/Password/System Id/Type-of-Number/Number Plan Indicator" ** ** example: ** "SMSC.DeltaTel.RU:9000/symb/VAX/zztop/1/1" ** */ $DESCRIPTOR(log_dsc,"SMPP$ESME_!AS"); $DESCRIPTOR(tbl_dsc,"LNM$GROUP_000001"); /* ** SYMBIONT PRIVILEGES, STRUCTURE LEVEL */ const int privs = PRV$M_NETMBX | PRV$M_TMPMBX, structure_level = SMBMSG$K_STRUCTURE_LEVEL,streams = 32; /* ** SYMBIONT STREAMS CONTEXT SRTUCTURE */ struct stream_ctx { int stream; void *ectx; char ton,npi, stypelen,stype[32]; } sctx[32]; int esmeio_shut ( struct stream_ctx *sctx, struct dsc$descriptor *msg ) { int status,resp,sts,context; /* ** Send a UNBIND request to close session with the SMSC */ if ( !(1 & (status = esme_api_tx(sctx->ectx,SMPP_CMD$K_UNBIND,NULL,NULL,NULL))) ) return status; /* ** Shutdown ESME API */ return esme_api_shut(&sctx->ectx); } int esmeio_init ( struct stream_ctx *sctx, struct dsc$descriptor *msg ) { int status,buflen = 0,resp, sts,seq, item_code = 0,context = 0, attr = LNM$M_CASE_BLIND; char buf[256],name[256],sid[32],stype[32],pwd[32],ton[4],npi[4]; struct dsc$descriptor buf_dsc,name_dsc; ILE3 bind_items_resp [] = { {sizeof(buf), SMPP_PTAG$K_SID,&buf,&buflen}, {0,0,0,0}}; ILE3 log_items [] = { {sizeof(buf), LNM$_STRING, &buf,&buflen}, {0,0,0,0}}; /* ** Get a queue name */ context = 0; INIT_SDESC(buf_dsc,sizeof(buf),buf); while ( (1 & (status = smb$read_message_item (msg,&context,&item_code, &buf_dsc,&buf_dsc.dsc$w_length))) ) if ( item_code == SMBMSG$K_EXECUTOR_QUEUE ) break; if ( !(1 & status) ) return status; else if ( !buf_dsc.dsc$w_length ) return SS$_INSFARG; /* ** Form a logical name by concatenating SMPP$ESME_ and */ INIT_SDESC(name_dsc,sizeof(name),name); if ( !(1 & (status = sys$fao(&log_dsc,&name_dsc.dsc$w_length,&name_dsc,&buf_dsc))) ) return status; /* ** Obtain a value of the logical name */ INIT_SDESC(buf_dsc,sizeof(buf),buf); if ( !(1 & (status = sys$trnlnm(&attr,&tbl_dsc,&name_dsc,0,&log_items))) ) return status; /* ** Got a connection string, we expect to see: ** "SMSC.DeltaTel.RU:9000/symb/VAX/zztop/1/1" */ buf[buflen] = '\0'; if ( 6 != sscanf(buf,"%[^/]/%[^/]/%[^/]/%[^/]/%[^/]/%[^\n]",&name,&sid,&pwd,&stype,&ton,&npi) ) return SS$_INSFARG; /* ** Initalize ESME API */ INIT_SDESC(name_dsc,strnlen(name,sizeof(name)),name); if ( !(1 & (status = esme_api_init(&sctx->ectx,&name_dsc))) ) return status; /* ** Fill out stream context */ strncpy(sctx->stype,stype,sizeof(sctx->stype)); sctx->stypelen = (char) strnlen(stype,sizeof(sctx->stype)); sctx->ton = (char)atoi(ton); sctx->npi = (char)atoi(npi); /* ** Send a BIND request to open a session with the SMSC */ { /* ** Items list for BIND_TRANSMITTER request */ ILE3 bind_items [] = { {strlen(sid), SMPP_PTAG$K_SID, &sid}, {strlen(pwd), SMPP_PTAG$K_PWD, &pwd}, {sctx->stypelen,SMPP_PTAG$K_STYPE, &sctx->stype}, {1, SMPP_PTAG$K_TON, &sctx->ton}, {1, SMPP_PTAG$K_NPI, &sctx->npi}, {0,0,0}}; if ( !(1 & (status = esme_api_tx(sctx->ectx,SMPP_CMD$K_BIND_TRANSMITTER,bind_items,NULL,NULL))) ) return status; } /* ** Receive a RESPONSE to the sent BIND request */ if ( !(1 & (status = esme_api_rx(sctx->ectx,bind_items_resp,&resp,&sts,NULL,NULL,&seq))) ) return status; /* ** Return a translated to VMS condition code SMPP/ESME error status */ return esme_api_err2cond(sts); } int esmeio_sendsms ( struct stream_ctx *sctx, struct dsc$descriptor *msg ) { int status,buflen = 0,resp,sts,seq,context = 0,item_code = 0; char dc = DC$K_ISOCYR,buf[8192],src[1024],dest[1024],sms[1024]; short srclen,destlen,smslen; struct dsc$descriptor buf_dsc,name_dsc; ILE3 submit_items_resp [] = { {sizeof(buf), SMPP_PTAG$K_MSGID, &buf,&buflen}, {0,0,0,0}}; /* ** We expect to see a job with parameters: ** P1 - an IMSI to send ** P2 - an IMSI of originator of the SMS ** P3 - A SMS Body */ /* ** Get a P1 ( Destination IMSI of the SMS) */ context = 0; INIT_SDESC(buf_dsc,sizeof(src),src); while ( (1 & (status = smb$read_message_item (msg,&context,&item_code, &buf_dsc,&srclen))) ) if ( item_code == SMBMSG$K_PARAMETER_1 ) break; if ( !(1 & status) ) return status; else if ( !srclen ) return SS$_INSFARG; /* ** Get a P2 ( Originating IMSI of the SMS) */ context = 0; INIT_SDESC(buf_dsc,sizeof(dest),dest); while ( (1 & (status = smb$read_message_item (msg,&context,&item_code, &buf_dsc,&destlen))) ) if ( item_code == SMBMSG$K_PARAMETER_2 ) break; if ( !(1 & status) ) return status; else if ( !destlen ) return SS$_INSFARG; /* ** Get a P3 ( SMS body ) */ context = 0; INIT_SDESC(buf_dsc,sizeof(sms),sms); while ( (1 & (status = smb$read_message_item (msg,&context,&item_code, &buf_dsc,&smslen))) ) if ( item_code == SMBMSG$K_PARAMETER_3 ) break; if ( !(1 & status) ) return status; else if ( !smslen ) return SS$_INSFARG; { ILE3 submit_items [] = { {sctx->stypelen, SMPP_PTAG$K_STYPE, &sctx->stype}, {1, SMPP_PTAG$K_SRCTON, &sctx->ton}, {1, SMPP_PTAG$K_SRCNPI, &sctx->npi}, {srclen, SMPP_PTAG$K_SRC, src}, {1, SMPP_PTAG$K_DESTTON, &sctx->ton}, {1, SMPP_PTAG$K_DESTNPI, &sctx->npi}, {destlen, SMPP_PTAG$K_DEST, dest}, {1, SMPP_PTAG$K_DC, &dc}, // {1, SMPP_PTAG$K_PRIO, &prio}, {1, SMPP_PTAG$K_SMSLEN, &smslen}, {smslen, SMPP_PTAG$K_SMSBODY, &sms}, {0,0,0}}; /* ** Send a SMS by SUBMIT_SM request */ if ( !(1 & (status = esme_api_tx(sctx->ectx,SMPP_CMD$K_SUBMIT_SM,submit_items,NULL,NULL))) ) return status; } /* ** Receive a RESPONSE to the sent SUBMIT_SM request */ if ( !(1 & (status = esme_api_rx(sctx->ectx,submit_items_resp,&resp,&sts,NULL,NULL,&seq))) ) return status; /* ** Return a translated to VMS condition code SMPP/ESME error status */ return esme_api_err2cond(sts); } void wake_up (void) { sys$wake(0,0); } int main (void) { int status,context = 0,item_code = 0,request = 0,stream = 0,count = 0; char buf[8192]; struct dsc$descriptor buf_dsc; /* ** Set privileges */ if ( !(1 & (status = sys$setprv(1,&privs,0,0))) ) return status; /* ** Initalize SMB's facility internal context, ** claiming support up to 32 streams, symbiont will use async event notification ** from the Job Controller */ if ( !(1 & (status = smb$initialize(&structure_level,wake_up,&streams))) ) return status; /* ** Main loop of processing Job Controller messages */ do { /* ** Is there a message from Job Controller ? */ while ( !(1 & (status = smb$check_for_message())) ) sys$hiber(); /* ** Get a next control message from Job Controller */ INIT_SDESC(buf_dsc,sizeof(buf),buf); if ( !(1 & (status = smb$read_message(&stream,&buf_dsc,&request))) ) lib$stop(status); /* ** Dispatch a processiong of a particular request */ switch (request) { case SMBMSG$K_STOP_STREAM: case SMBMSG$K_RESET_STREAM: /* ** Cleanup a context for the specified stream */ status = esmeio_shut(&sctx[stream],&buf_dsc); count -= 1&status; break; case SMBMSG$K_START_TASK: status = esmeio_sendsms(&sctx[stream],&buf_dsc); request = SMBMSG$K_TASK_COMPLETE; break; case SMBMSG$K_START_STREAM: /* ** Initalize a ESME API context for the specified stream */ status = esmeio_init(&sctx[stream],&buf_dsc); count += 1&status; break; default: break; } { int error [2] = {1,status}; if ( !(1 & (status = smb$send_to_jobctl(&stream,&request,0,0,0,&error))) ) lib$stop(status); } } while ( count ); return SS$_NORMAL; }