#pragma module SLFAX_SRV "SLFAX-SRV-1-A" #define __MODULE__ "SLFAX-SRV" /* **++ ** FACILITY: StarLet Fax server ** ** MODULE DESCRIPTION: ** ** This module is covers a server functionality to perofm next actions: ** receiving faxes from SL-FAX Clients ** submit fax-es to the Gold-Fax subsystem to sending ** retrive a status of the sent fax from the Gold-Fax subsystem ** accounts in the OpenVMS environment. ** ** AUTHORS: ** ** Ruslan R. Laishev ** ** CREATION DATE: 22-JAN-2004 ** ** DESIGN ISSUES: ** ** This server runs as network service, listening on TCP-port, accept a connection request ** from a remote client. After connection establishing perform processing next commands: ** ** LOGIN user pass - Authenticate/authorize a remote user ** LOGOUT - Close session and shutdown TCP-connection ** STATUS [] - Request a status of sent fax ** SEND - Send/submit a fax ** [/FORMAT=PS|HPPCL|G3|TIFF,TEXT] ** [/NOTIFY=(ERRORS,SUCCESS)] ** [/AFTER=EVENING|NIGHT|NOW|MORNING] ** CAPABILITY - Request a current capabilities ** HELP - Display a help information ** ** MODIFICATION HISTORY: ** ** ** {@tbs@}... **-- */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "netlibdef.h" /* MadGoat's NETLIB definitions */ #include "slfaxdef.h" /* StarLet FAX Gateway definitions */ #include "slfax_msg.h" /* StarLet FAX Gateway message codes */ #include "gfaxdef.h" /* DPD GoldFax API definitions */ #define INIT_DDESC(dsc) {(dsc).dsc$b_dtype = DSC$K_DTYPE_T;\ (dsc).dsc$b_class = DSC$K_CLASS_D;(dsc).dsc$w_length = 0;\ (dsc).dsc$a_pointer = 0;} #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);} #define min(x,y) ((x > y)?y:x) #define max(x,y) ((x < y)?y:x) int debug_flag = 1,exit_flag = 0; #define DEBUG if(debug_flag)printf("%-24.24s:%-08.0u ",__MODULE__,__LINE__);if(debug_flag)printf $DESCRIPTOR(slfax_right, "SLFAX_ACCESS"); $DESCRIPTOR(prompt_dsc, "\r\n."); $DESCRIPTOR(slfax_evening, "EVENING"); $DESCRIPTOR(slfax_night, "NIGHT"); $DESCRIPTOR(slfax_now, "NOW"); $DESCRIPTOR(slfax_morning, "MORNING"); /* ** A time coversion related stuff */ int tm_context = 0; $DESCRIPTOR(tm_fmt,"|!Y4!MN0!D0-!H04!M0!S0|"); /* YYYYMMDDHHMMSS */ /* ** ** LIB$TPARSE stuff ** */ extern char ufd_state, ufd_key; struct tp_block { struct tpadef tpb; int *cmd; ile2 *args; }; #ifdef __VAX #define LONGWORD_SZ 4 #else #define LONGWORD_SZ 8 #endif #pragma member_alignment save #pragma member_alignment QUADWORD struct _queue { void *head,*tail; /* Head and Tail pointers of a queue */ int reserved[3]; } FreeCtxPool, BusyCtxPool; #pragma member_alignment restore int RETRY_COUNT = -1; /* A counter for LIB$ calls */ /* ** ** Workers/threads context data structure ** **/ struct thctx { struct thctx *flink,*blink; /* Forward and backward links */ int reserved0[4]; pthread_t tid; /* A thread ID */ unsigned char idx; /* A thread index */ unsigned chan; /* Network I/O NETLIB context */ unsigned short id; /* A thread Index */ unsigned char iplen, /* IP address counted string */ ip[15]; unsigned char usrlen, /* Username counted string */ usr[12]; unsigned int state; /* A current session state */ unsigned int jobid; /* ID of last submited FAX */ }; $DESCRIPTOR(iotmo_dsc,"0 00:30:00"); int iotmo [ 2 ]; void *netchan = NULL; /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Put message to standard output device (SYS$OUTPUT). ** ** FORMAL PARAMETERS: ** ** msgid: ** VMS condition code ** variable agriments list ** ** RETURN VALUE: ** ** VMS condition code ** ** **-- */ char msg_pref[] = {"!%D "}; char msg_pref_ctx[] = {"!%D [!2ZB !AC/!AC] "}; int slfax_log ( struct thctx * ctx, int msgid, ... ) { long status,retvalue = msgid,len = 0; va_list args; char buf[1024],outadr[4]; struct dsc$descriptor opr_dsc,buf_dsc,fao_dsc; int argc,argl[32],idx = 0,flag=15,lvl; char msg_buf[1024]; if ( !ctx ) memcpy(buf,msg_pref,sizeof(msg_pref)-1); else memcpy(buf,msg_pref_ctx,sizeof(msg_pref_ctx)-1); len = (ctx)?sizeof(msg_pref_ctx)-1:sizeof(msg_pref)-1; /* ** Get a message text with given msgid */ INIT_SDESC(fao_dsc,sizeof(buf)-len,&buf[len]); if ( !(1 & (status = sys$getmsg (msgid,&fao_dsc.dsc$w_length,&fao_dsc,flag,&outadr))) ) lib$signal(status); /* ** Reorganize parameters list for $FAOL */ va_start(args,msgid); argl[0] = idx++; if ( ctx ) { argl[idx++] = ctx->idx; argl[idx++] = &ctx->iplen; argl[idx++] = &ctx->usrlen; } for (va_count(argc);idx < argc;idx++,args += LONGWORD_SZ) argl[idx] = *((long *)args); va_end((char *) msgid); /* ** Format a message, put it to SYS$OUTPUT */ fao_dsc.dsc$a_pointer -=len; fao_dsc.dsc$w_length +=len; INIT_SDESC(buf_dsc, sizeof(msg_buf),msg_buf); if ( !(1 & (status = sys$faol(&fao_dsc,&buf_dsc.dsc$w_length,&buf_dsc,argl))) ) lib$signal(status); lib$put_output(&buf_dsc); if ( ctx ) status = netlib_writeline(&ctx->chan,&buf_dsc,0,0,0); return retvalue; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** An action routine called from LIB$TPARSE routine to store a command code. ** ** FORMAL PARAMETERS: ** ** tblock: A pointer to the TPARSE block ** ** RETURN VALUE: ** ** VMS condition code ** **-- */ int store_cmd ( struct tp_block *tblock ) { /* ** Store a command code to the TP Block */ *tblock->cmd = tblock->tpb.tpa$l_param; /* ** Always return a success status */ return SS$_NORMAL; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** An action routine called from LIB$TPARSE routine, if a field token is matched ** store a length and a pointer to the found field. ** ** FORMAL PARAMETERS: ** ** tblock: A pointer to the TPARSE block ** ** RETURN VALUE: ** ** VMS condition code ** ** SIDE EFFECTS: ** ** Modify a string pointer and length in the TPARSE block. ** ** **-- */ int store_arg ( struct tp_block *tblock ) { ile2 *ileptr; /* ** Run over itemlist array to match a found token with requested */ for (ileptr = tblock->args;ileptr->ile2$w_code;ileptr++) { if ( ileptr->ile2$w_code == tblock->tpb.tpa$l_param ) { /* ** Store length and pointer */ ileptr->ile2$w_length = tblock->tpb.tpa$l_tokencnt; ileptr->ile2$ps_bufaddr = tblock->tpb.tpa$l_tokenptr; break; } } /* ** Always return a success status */ return SS$_NORMAL; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** A routine to performs a parsing and extraction of the selected fields ** from an answer to REVIEW command. ** ** FORMAL PARAMETERS: ** ** ptr: a pointer to string to be parsed ** len: a length of the string ** itmlst: an array of ile2 elements to store a pointers and lengths of the found fields ** ** RETURN VALUE: ** ** VMS condition code ** **-- */ int slfax_parsecmd ( char *ptr, int len, int *cmd, ile2 *itmlst ) { struct tp_block tblock = {{TPA$K_COUNT0},cmd,itmlst}; /* ** Prepare a TPARSE block */ tblock.tpb.tpa$l_stringcnt = len; tblock.tpb.tpa$l_stringptr = ptr; /* ** Call parser, and return status */ return lib$table_parse( &tblock,&ufd_state,&ufd_key); } //char sts [] = "LOGIN field fieldpassword "; //char sts [] = "LOGOUT"; //char sts [] = "SEND 88121163222/FORMAT=TEXT/AFTER=EVENING/NOTIFY=(ERRORS,SUCCESS)"; int slfax__chkid ( struct dsc$descriptor_s *dsc$right, int uic ) { int status,id,uai_id,context = 0; struct { union uicdef uai_uic; int mbz; } holder = {uic,0}; /* ** Convert VMS Right id from ASCII to Binary from */ if ( !(1 & (status = sys$asctoid(dsc$right,&id,0))) ) return status; /* ** Find for presence of right_id for UIC */ while ( 1 & (status = sys$find_held(&holder,&uai_id,0,&context)) ) if ( id == uai_id ) break; sys$finish_rdb (&context); return status; } int slfax_login ( struct thctx *ctx, ile2 *args ) { int status,uai_flags, uai_pwd[2], putative_pw[2], uai_expire_date[2],lgi_time[2],delta_time[2], uai_netw_p,uai_netw_s; union uicdef uai_uic; int uai_salt = 0, uai_encrypt = 0; char uai_defdev[32],uai_defdir[64],buf[1024]; short authlen,buflen; struct dsc$descriptor buf_dsc,usr_dsc,pwd_dsc,node_dsc; ile3 get_itmlst[] = { {4, UAI$_FLAGS, &uai_flags, 0}, {1, UAI$_ENCRYPT, &uai_encrypt, 0}, {2, UAI$_SALT, &uai_salt, 0}, {8, UAI$_PWD, uai_pwd, 0}, {3, UAI$_NETWORK_ACCESS_P, &uai_netw_p, 0}, {3, UAI$_NETWORK_ACCESS_S, &uai_netw_s, 0}, {8, UAI$_EXPIRATION, &uai_expire_date,0}, {32, UAI$_DEFDEV, &uai_defdev, 0}, {64, UAI$_DEFDIR, &uai_defdir, 0}, {4, UAI$_UIC, &uai_uic, 0}, {0, 0, 0, 0}}; ile3 set_itmlst[] = { {8, UAI$_LASTLOGIN_N, &lgi_time, 0}, {0, 0, 0, 0}}; INIT_SDESC(usr_dsc,args[SLF_ARG$K_USER-1].ile2$w_length,args[SLF_ARG$K_USER-1].ile2$ps_bufaddr); INIT_SDESC(pwd_dsc,args[SLF_ARG$K_PASS-1].ile2$w_length,args[SLF_ARG$K_PASS-1].ile2$ps_bufaddr); INIT_SDESC(node_dsc,ctx->iplen,ctx->ip); /* ** Get login time for future checking */ if ( !(1 & (status = sys$gettim(&lgi_time))) ) lib$signal(status); /* ** Find & get user's record from SYSUAF.DAT & check: ** ** - Disabled Account & Restricted flags, ** - Expiration date of account ** */ status = sys$getuai(0, 0, &usr_dsc, &get_itmlst, 0, 0, 0); if ( status == RMS$_RNF ) { sys$scan_intrusion (SS$_NOSUCHUSER,&usr_dsc,JPI$K_NETWORK,0, &node_dsc,&usr_dsc,0,0,0,0, CIA$M_IGNORE_RETURN|CIA$M_REAL_USERNAME); return slfax_log(ctx,SLFAX_ERRLOGIN,SS$_NOSUCHUSER); } else if ( !(1 & status) ) return slfax_log(ctx,SLFAX_ERRLOGIN,status); /* ** We don't allow logins with expired passwords */ if ( UAI$M_PWD_EXPIRED & uai_flags ) { sys$scan_intrusion (LGI$_PWDEXPIR,&usr_dsc,JPI$K_NETWORK,0, &node_dsc,&usr_dsc,0,0,0,0, CIA$M_IGNORE_RETURN|CIA$M_REAL_USERNAME); return slfax_log(ctx,SLFAX_ERRLOGIN,LGI$_PWDEXPIR); } if ( (!uai_expire_date[0]) && (!uai_expire_date[1]) ) uai_expire_date[0] = uai_expire_date[1] = -1; /* ** Check DisUser flag and account expiration flag */ if ( UAI$M_DISACNT & uai_flags ) status = LGI$_DISUSER; else { status = lib$sub_times (uai_expire_date,lgi_time,delta_time); status = (status == LIB$_NEGTIM)?LGI$_ACNTEXPIR:SS$_NORMAL; } if ( !(1 & status )) { sys$scan_intrusion (status,&usr_dsc,JPI$K_NETWORK,0, &node_dsc,&usr_dsc,0,&pwd_dsc,0,0, CIA$M_IGNORE_RETURN|CIA$M_REAL_USERNAME); return slfax_log(ctx,SLFAX_ERRLOGIN,status); } /* ** Now hash the putative password to see if it matches the one on file. */ if ( !(1 & (status = sys$hash_password(&pwd_dsc, uai_encrypt, uai_salt, &usr_dsc,putative_pw))) ) lib$signal(status); if ( (putative_pw[0] != uai_pwd[0]) || (putative_pw[1] != uai_pwd[1]) ) { sys$scan_intrusion (LGI$_INVPWD,&usr_dsc,JPI$K_NETWORK,0, &node_dsc,&usr_dsc,0,&pwd_dsc,0,0, CIA$M_IGNORE_RETURN|CIA$M_REAL_USERNAME); return slfax_log(ctx,SLFAX_ERRLOGIN,LGI$_INVPWD); } /* ** Set last non-interactive login time in SYSUAF.DAT. */ if ( !(1 & (status = sys$setuai(0,0,&usr_dsc,&set_itmlst,0,0,0))) ) return slfax_log(ctx,SLFAX_ERRLOGIN,status); if ( !(1 & (status = slfax__chkid(&slfax_right,uai_uic.uic$l_uic))) ) return slfax_log(ctx,SLFAX_ERRLOGIN,status); /* ** Now we can filling context additional user's data */ memcpy(ctx->usr,usr_dsc.dsc$a_pointer,usr_dsc.dsc$w_length); ctx->usrlen = (unsigned char) usr_dsc.dsc$w_length; return slfax_log(ctx,SLFAX_SESSOPEND); } int slfax__status ( struct thctx *ctx, ile2 *args ) { unsigned status,ulID = 0; struct dsc$descriptor pdUsername, pdDateTime,pdAdress,pdSubject1,pdSubject2,pdFrom, pdIDString; unsigned pulStatusFlags = 0, pulSuccess = 0,pulFail = 0,pulWarning = 0,pulRetry = 0; /* ** Is there ID arguments ? */ if ( args[SLF_ARG$K_ID-1].ile2$w_length && args[SLF_ARG$K_ID-1].ile2$ps_bufaddr ) { if ( !(1 & (status = lib$cvt_dtb(args[SLF_ARG$K_ID-1].ile2$w_length, args[SLF_ARG$K_ID-1].ile2$ps_bufaddr,&ulID))) ) return slfax_log(ctx,SLFAX_BADID,status); } else if ( !(ulID = ctx->jobid) ) return slfax_log(ctx,SLFAX_NOSTATUS); INIT_SDESC(pdUsername,ctx->usrlen,ctx->usr); INIT_DDESC(pdDateTime); INIT_DDESC(pdAdress); INIT_DDESC(pdSubject1); INIT_DDESC(pdSubject2); INIT_DDESC(pdFrom); INIT_DDESC(pdIDString); if ( !(1 & (status = gfax_status_job(&pdUsername,ulID,&pulStatusFlags, &pdDateTime,&pdAdress,&pdSubject1,&pdSubject2,&pdFrom, &pulSuccess,&pulFail,&pulWarning,pulRetry,NULL,NULL,&pdIDString))) ) return slfax_log(ctx,SLFAX_BADID,status); slfax_log(ctx,SLFAX_STATUS,ulID); lib$sfree1_dd(pdDateTime); lib$sfree1_dd(pdAdress); lib$sfree1_dd(pdSubject1); lib$sfree1_dd(pdSubject2); lib$sfree1_dd(pdFrom); lib$sfree1_dd(pdIDString); return status; } int slfax__send ( struct thctx *ctx, ile2 *args ) { unsigned status, ulFlags = 0; unsigned char faxfile [255],faxfilelen,*faxext,faxextlen,buf[128]; struct dsc$descriptor pdUsername,pdFileName,*pdAfterTime,pdDraftQueueName, pdDial,pdFrom,pdIdString, buf_dsc; /* ** Some base initialization */ ulFlags = GF_M_PAPERSIZE_A4 | GF_M_PORTRAIT | GF_M_VERTRES_FINE; INIT_SDESC(pdUsername,ctx->usrlen,ctx->usr); INIT_SDESC(pdDial,args[SLF_ARG$K_PHONE-1].ile2$w_length,args[SLF_ARG$K_PHONE-1].ile2$ps_bufaddr); pdAfterTime = NULL; /* ** Fax body format */ if ( args[SLF_ARG$K_FORMAT_PS-1].ile2$w_length ) { ulFlags |= GF_M_PS; faxext = ".PS"; faxextlen = 3; } else if ( args[SLF_ARG$K_FORMAT_HPPCL-1].ile2$w_length ) { ulFlags |= GF_M_HP; faxext = ".HP"; faxextlen = 3; } else { ulFlags |= GF_M_DRAFT; faxext = ".TXT"; faxextlen = 4; } /* ** When fax must to be sent ? */ if ( args[SLF_ARG$K_EVENING-1].ile2$w_length ) pdAfterTime = &slfax_evening; else if ( args[SLF_ARG$K_NIGHT-1].ile2$w_length ) pdAfterTime = &slfax_night; else if ( args[SLF_ARG$K_MORNING-1].ile2$w_length ) pdAfterTime = &slfax_morning; else pdAfterTime = NULL; /* ** Notifications ? */ if ( args[SLF_ARG$K_NOTIFY_ERROR-1].ile2$w_length ) ulFlags |= GF_M_MAIL_FAIL; else if ( args[SLF_ARG$K_NOTIFY_SUCCESS-1].ile2$w_length ) ulFlags |= GF_M_MAIL_SUCCESS; lib$signal(SS$_DEBUG); /* ** Generating a file name as SYS$SCRATCH:_YYYYMMDD-HHMMSS. */ { INIT_SDESC(buf_dsc,sizeof(buf),buf); INIT_SDESC(pdFileName,sizeof(faxfile),faxfile); $DESCRIPTOR(fnam_dsc,"SYS$SCRATCH:!AS_!AS!AD"); /* ** Convert a time in VMS binary format to YYYYMMDD-HHMMSS */ if ( !(1 & (status = lib$format_date_time (&buf_dsc,0,&tm_context,&buf_dsc.dsc$w_length,0))) ) lib$signal(status); if ( !(1 & (status = sys$fao(&fnam_dsc,&pdFileName.dsc$w_length,&pdFileName, &pdUsername,&buf_dsc,faxextlen,faxext))) ) lib$signal(status); } /* ** Now we ready to receiving a fax body itself */ slfax_log(ctx,SLFAX_STARTBODY,pdFileName.dsc$w_length,faxfile); if ( ulFlags && (GF_M_PS | GF_M_DRAFT) ) { /* ** For pure text fax bodies we will use TEXT-file-like RMS attributes */ } else { /* ** In other case opening a binary-like RMS-file */ } /* if ( !(1 & (status = gfax_status_job(&pdUsername,ulID,&pulStatusFlags, &pdDateTime,&pdAdress,&pdSubject1,&pdSubject2,&pdFrom, &pulSuccess,&pulFail,&pulWarning,pulRetry,NULL,NULL,&pdIDSrting))) ) return slfax_log(ctx,SLFAX_BADID,status); slfax_log(ctx,SLFAX_SENDSTA,status); */ return status; } void * slfax_thread (struct thctx *ctx) { int status,cmd = 0; ile2 args [] = { {0,SLF_ARG$K_USER,0},{0,SLF_ARG$K_PASS,0}, {0,SLF_ARG$K_PHONE,0}, {0,SLF_ARG$K_ID,0}, {0,SLF_ARG$K_FORMAT_PS,0},{0,SLF_ARG$K_FORMAT_HPPCL,0}, {0,SLF_ARG$K_FORMAT_G3,0},{0,SLF_ARG$K_FORMAT_TIFF,0},{0,SLF_ARG$K_FORMAT_TEXT,0}, {0,SLF_ARG$K_NOTIFY_ERROR,0},{0,SLF_ARG$K_NOTIFY_SUCCESS,0}, {0,SLF_ARG$K_EVENING,0},{0,SLF_ARG$K_NIGHT,0},{0,SLF_ARG$K_NOW,0},{0,SLF_ARG$K_MORNING,0}, {0,0,0}}; char buf[255]; struct dsc$descriptor_s buf_dsc; /* ** Print out WELCOME message */ slfax_log(ctx,SLFAX_WELCOME); /* ** Main session command processing loop */ while ( status != SS$_DISCONNECT ) { /* ** Start reading a command from network client */ netlib_writeline(&ctx->chan,&prompt_dsc,0,0,0); /* ** Start reading a command from network client */ INIT_SDESC(buf_dsc,sizeof(buf),buf); if ( !(1 & (status = netlib_readline(&ctx->chan,&buf_dsc,&buf_dsc.dsc$w_length,0,&iotmo,0,0,0))) ) slfax_log(ctx,status); str$upcase(&buf_dsc,&buf_dsc); /* ** Process gotten command line */ { struct tp_block tblock = {{TPA$K_COUNT0},&cmd,&args}; tblock.tpb.tpa$l_stringcnt = buf_dsc.dsc$w_length; tblock.tpb.tpa$l_stringptr = buf_dsc.dsc$a_pointer; for(int i = 0;args[i].ile2$w_code;i++) { args[i].ile2$w_length = 0; args[i].ile2$ps_bufaddr = NULL; } status = lib$table_parse( &tblock,&ufd_state,&ufd_key); } DEBUG("cmd = %u,status = %u\n",cmd,status); for(int i = 0;args[i].ile2$w_code;i++) if ( args[i].ile2$w_length && args[i].ile2$ps_bufaddr ) { DEBUG("args [%u]/%u = '%.*s'\n",i,args[i].ile2$w_code, args[i].ile2$w_length,args[i].ile2$ps_bufaddr); } /* ** Check that it's a legal command */ if ( !cmd || !(1 & status) ) { slfax_log(ctx,SLFAX_BADCMD); continue; } /* ** Check that the user has been logged */ if ( (!ctx->usrlen) && (cmd != SLF_CMD$K_LOGIN) && (cmd != SLF_CMD$K_HELP) && (cmd != SLF_CMD$K_LOGOUT) ) { slfax_log(ctx,SLFAX_NOTLOGGED); continue; } /* ** Processing a command */ switch (cmd) { case SLF_CMD$K_LOGIN: slfax_login(ctx,&args); break; case SLF_CMD$K_LOGOUT: status = SS$_DISCONNECT; slfax_log(ctx,SLFAX_BYE); break; case SLF_CMD$K_STATUS: slfax__status(ctx,&args); break; case SLF_CMD$K_SEND: slfax__send(ctx,&args); break; case SLF_CMD$K_CAPABILITY: /* ** HELP and default action - the same */ case SLF_CMD$K_HELP: } }; /* while (1) */ /* ** Close network stuff */ if ( !(1 & (status = netlib_close (&ctx->chan))) ) lib$signal(status); /* ** Release context and put into the "free list" */ if ( !(1 & (status = lib$insqti(&ctx,&BusyCtxPool,&RETRY_COUNT))) ) lib$signal(status); pthread_exit(&status); } int main (void) { int status,len = 0,chan = 0,component = LIB$K_OUTPUT_FORMAT; struct SINDEF sin; struct thctx *newctx; $DESCRIPTOR(busy_dsc, "SLFAX_BUSY-F-BUSY, Server is too busy, try again just later."); struct dsc$descriptor_s tmp_dsc; pthread_attr_t tattr; /* ** Convert a network I/O timeout */ if ( !(1 & (status = sys$bintim (&iotmo_dsc,&iotmo))) ) return status; /* ** Initialize a context for date/time manipulations */ if ( !(1 & (status = lib$init_date_time_context (&tm_context,&component,&tm_fmt))) ) sys$exit(status); /* ** Preallocating contexts pool */ for (int i = 255; i ; i--) { if ( !(1 & (status = lib$get_vm(&sizeof(struct thctx),&newctx,0))) ) lib$signal(status); if ( !(1 & (status = lib$insqti(newctx,&FreeCtxPool,&RETRY_COUNT))) ) lib$signal(status); } /* ** Initalize attributes for threads and multithreaded environment of the C RTL */ decc$set_reentrancy(C$C_MULTITHREAD); status = pthread_attr_init(&tattr); status = pthread_attr_setdetachstate(&tattr,PTHREAD_CREATE_JOINABLE); status = pthread_attr_setstacksize(&tattr,96000); /* ** Initialize network socket to listening incomming connection request */ if ( !(1 & (status = netlib_socket (&netchan,0,0))) ) lib$signal(status); memset(&sin, 0, sizeof(sin)); sin.sin_w_port = netlib_hton_word(&SL$K_PORT); if ( !(1 & (status = netlib_bind (&netchan,&sin,&sizeof(sin),0,0,0))) ) lib$signal(status); if ( !(1 & (status = netlib_listen (&netchan,0,0,0,0))) ) lib$signal(status); /* ** A main loop */ while (!exit_flag) { if ( !(1 & (status = netlib_accept(&netchan,&chan,&sin, &sizeof(sin), &len,0,0,0))) ) lib$signal(status); if ( !(1 & (status = lib$remqhi(&FreeCtxPool,&newctx,&RETRY_COUNT))) ) { slfax_log(NULL,status); netlib_writeline(&chan,&busy_dsc,0,0,0); netlib_close(&chan); continue; } /* ** Filling new context area */ memset(newctx,0,sizeof(struct thctx)); INIT_SDESC(tmp_dsc,sizeof(newctx->ip),&newctx->ip); netlib_addrtostr(&sin.sin_x_addr,&tmp_dsc,&len); newctx->iplen = (unsigned char) len; newctx->chan = chan; /* ** Start worker thread */ if ( status = pthread_create(&newctx->tid,&tattr,(void*) slfax_thread,(void *)newctx) ) { slfax_log(NULL,SLFAX_ERRTHREAD, strerror(status)); netlib_close(&chan); if ( !(1 & (status = lib$insqti(&newctx,&FreeCtxPool,&RETRY_COUNT))) ) lib$signal(status); continue; } /* ** Place a context of new thread to "busy list" */ if ( !(1 & (status = lib$insqti(&newctx,&BusyCtxPool,&RETRY_COUNT))) ) lib$signal(status); } /* ** Close network stuff */ if ( !(1 & (status = netlib_close (&netchan))) ) lib$signal(status); }