#pragma module SYSLOG "SYSLOG_API-1-X" #define __MODULE__ "SYSLOG" #pragma __nomember_alignment QUADWORD /* **++ ** FACILITY: SysLog Client API ** ** MODULE DESCRIPTION: ** ** This module contains a set of rutines to cover the SysLog client functionality. ** See more in the : http://www.faqs.org/rfcs/rfc3164.html ** ** AUTHORS: ** ** Ruslan R. Laishev ** ** CREATION DATE: 5-FEB-2004 ** ** DESIGN ISSUES: ** ** {@tbs@} ** ** [@optional module tags@]... ** ** MODIFICATION HISTORY: ** ** 30-AUG-2005 RRL Removed unneeded pthread_detach(); added some more comments. ** {@tbs@}... **-- */ /* ** ** INCLUDE FILES ** */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define __NEW_STARLET 1 #include #include "syslogdef.h" #ifdef __DECC #include #else #pragma builtins #endif static $DESCRIPTOR(dsc_ucxdev,"UCX$DEVICE"); static $DESCRIPTOR(dsc_tcpipdev,"TCPIP$DEVICE"); static $DESCRIPTOR(VMZoneName_ENT,"SysLog Messages"); static int VMZoneId_ENT,chan = 0, exit_flag = 0, RETRY_COUNT = -1; pthread_mutex_t sign_mtx = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t sign_cnd = PTHREAD_COND_INITIALIZER; pthread_attr_t tattr; pthread_t tid; $DESCRIPTOR(syslog_fao," !%D !AS !AS"); static struct dsc$descriptor_s nodename; #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 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 = NULL;} /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Process entries from the queues. ** ** FORMAL PARAMETERS: ** ** ctx: a context ** ** RETURN VALUE: ** ** VMS condition code ** **-- */ static void * syslog_thread ( SLOG_CTX * ctx) { int status,count = 0, qidx = 0; SLOG_MSG *entry; ILE2 r_adr_item = {sizeof(struct sockaddr_in),0,&ctx->slog_ctx$l_raddr}; iosb netiosb; struct timespec delta= {5,0},abstime; /* ** Main processing loop */ for (qidx = 0; !exit_flag; qidx++, count = 0 ) { if ( qidx == SLOG_PRIO$K_MAX ) { qidx = 0; /* ** Wait for a condition or a timeout */ status = pthread_mutex_lock (&sign_mtx); status = pthread_get_expiration_np (&delta,&abstime); status = pthread_cond_timedwait( &sign_cnd,&sign_mtx,&abstime); status = pthread_mutex_unlock (&sign_mtx); } while ( (1 & (status = lib$remqhi(&ctx->slog_ctx$r_queue[qidx],&entry,&RETRY_COUNT))) ) { /* ** Send the message */ if ( !(1 & (status = sys$qiow(0,chan,IO$_WRITEVBLK, &netiosb, 0,0,entry->slog_msg$b_data,entry->slog_msg$w_size,&r_adr_item,0,0,0))) || !(1 & netiosb.iosb$w_status) ) lib$signal((1 & status)?netiosb.iosb$w_status:status); /* ** Free memory has been allocated for the entry */ if ( !(1 & (status = lib$free_vm(&sizeof(SLOG_MSG),&entry,&VMZoneId_ENT))) ) lib$signal(status); count++; } } pthread_exit(&status); return NULL; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Initialize SYSLOG API internal context, creates network socket, initialize ** internal queues. Must be called once for a particluar host & port pair. ** ** FORMAL PARAMETERS: ** ** newctx: a context to be created ** host: a host IP address, etxt string ** port: a UDP port of the target host ** ** RETURN VALUE: ** ** VMS condition code ** **-- */ int syslog_init ( void * * newctx, void * host, unsigned short port ) { int status; iosb netiosb; struct { short proto; char type; char domain; } sck_parm = {INET$C_UDP,INET_PROTYP$C_DGRAM,INET$C_AF_INET}; static struct SOCKADDRIN s_adr = {UCX$C_AF_INET,0,0,0}; ILE2 s_adr_item = {sizeof(struct sockaddr_in),0,&s_adr}; int VMZoneAlg = LIB$K_VM_FIXED, VMZoneFlags = LIB$M_VM_EXTEND_AREA | LIB$M_VM_GET_FILL0, VMZoneBlockSz,VMZoneSz; struct hostent *hp; /* ** Get current VMS Node name */ INIT_DDESC(nodename); if ( !(1 & (status = lib$getsyi (&SYI$_NODENAME,0,&nodename,0,0,0))) ) return status; /* ** Open a network device */ if ( !(1 & (status = sys$assign( &dsc_ucxdev,&chan,0,0))) ) { if ( status != SS$_NOSUCHDEV ) return status; if ( !(1 & (status = sys$assign( &dsc_tcpipdev,&chan,0,0))) ) return status; } /* ** */ if ( !(1 & (status = sys$qiow (0,chan,IO$_SETMODE,&netiosb, 0,0,&sck_parm,0,&s_adr_item,0,0,0))) || !(1 & netiosb.iosb$w_status) ) { sys$dassgn (chan); return (1 & status)?netiosb.iosb$w_status:status; } /* ** Allocate a memory for the new context, ** filling context area */ if ( !(1 & (status = lib$get_vm(&sizeof(SLOG_CTX),newctx,0))) ) lib$signal(status); memset(*newctx,0,sizeof(SLOG_CTX)); /* ** Check input args */ if ( !host ) return SS$_INSFARG; else if ( -1UL != inet_addr(host) ) s_adr.SIN$L_ADDR = inet_addr(host); else if ( hp = gethostbyname(host) ) s_adr.SIN$L_ADDR = *(int *)hp->h_addr; else return SS$_INSFARG; s_adr.SIN$W_PORT = port?ntohs(port):htons(SLOG_PORT$K_PORT); memcpy(&((SLOG_CTX *)*newctx)->slog_ctx$l_raddr,&s_adr,sizeof(struct SOCKADDRIN)); /* ** Initialize special VMS memory zone */ VMZoneBlockSz = sizeof(SLOG_MSG); VMZoneSz = VMZoneBlockSz * 32; status = lib$create_vm_zone(&VMZoneId_ENT,&VMZoneAlg,&VMZoneBlockSz,&VMZoneFlags,0, &VMZoneSz,0,0,0,0,&VMZoneName_ENT,0,0); if ( !(1 & status) ) 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); /* ** Start a processor thread 6922752 */ if ( status = pthread_create(&tid,&tattr,(void*) syslog_thread,*newctx) ) { sys$dassgn (chan); if ( !(1 & (status = lib$free_vm(&sizeof(SLOG_CTX),newctx,0))) ) lib$signal(status); if ( !(1 & (status = lib$delete_vm_zone(&VMZoneId_ENT))) ) lib$signal(status); } return status?status:SS$_NORMAL; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Close network socket, release a momory allocated for the context. ** ** FORMAL PARAMETERS: ** ** ctx: a created context ** ** RETURN VALUE: ** ** VMS condition code ** **-- */ int syslog_shut ( void * ctx ) { int status,ret_code; /* ** Set global exit_flag */ exit_flag = 1; /* ** Lets finished tasks to all threads */ /* ** Send a signal to waiters... */ status = pthread_mutex_lock (&sign_mtx); status = pthread_cond_signal(&sign_cnd); status = pthread_mutex_unlock (&sign_mtx); /* ** Stop thread */ status = pthread_join(tid,(void *)&ret_code); /* ** Close network I/O chanel */ status = sys$dassgn (chan); /* ** Destroy context area, release memory */ if ( ctx && !(1 & (status = lib$free_vm(&sizeof(SLOG_CTX),&ctx,0))) ) lib$signal(status); if ( !(1 & (status = lib$delete_vm_zone(&VMZoneId_ENT))) ) lib$signal(status); return status; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Enqueue a SYSLOG message to send to a SYSLOG server targeted by the created context. ** ** FORMAL PARAMETERS: ** ** ctx: a created context ** fac: a facility code, see SLOG_FAC$* constants set ** sev: a severity level/prioroty, see SLOG_SEV$* constants set ** timestamp: a time stamt of the event ** hostname: a host name IP address/name, text string ** msg: a message text string ** ** RETURN VALUE: ** ** VMS condition code ** **-- */ int syslog_enq ( void * ctx, unsigned short fac, unsigned short sev, void * timestamp, void * hostname, void * msg ) { int status; SLOG_MSG * entry; struct dsc$descriptor tmp_dsc; /* ** Allocate from the special VMS memory zone a memory for ** new entry */ if ( !(1 & (status = lib$get_vm(&sizeof(SLOG_MSG),&entry,&VMZoneId_ENT))) ) return status; /* ** Format a message: ** $DESCRIPTOR(syslog_fao," !%D !AS !AS"); */ INIT_SDESC(tmp_dsc,sizeof(entry->slog_msg$b_data),&entry->slog_msg$b_data); if ( !(1 & (status = sys$fao(&syslog_fao,&entry->slog_msg$w_size,&tmp_dsc, (fac*8)+sev,timestamp,hostname?hostname:&nodename,msg))) ) lib$signal(status); /* ** Put new entry to corresponding queue */ if ( !(1 & (status = lib$insqti(entry,&((SLOG_CTX *)ctx)->slog_ctx$r_queue[(sev & 0x7)],&RETRY_COUNT))) ) lib$signal(status); /* ** Send a signal to waiters... */ status = pthread_mutex_lock (&sign_mtx); status = pthread_cond_signal(&sign_cnd); status = pthread_mutex_unlock (&sign_mtx); return exit_flag?SS$_ABORT:SS$_NORMAL; } #if 0 void main (void) { int status; void *ctx = NULL; $DESCRIPTOR(hostname,"STARLET::"); $DESCRIPTOR(msg,"Hello Wrold!!!"); struct timespec delta= {405,0}; if ( !(1 & (status = syslog_init (&ctx,"starlet",514))) ) lib$signal(status); if ( !(1 & (status = syslog_enq(ctx,SLOG_FAC$K_KERNEL,SLOG_SEV$K_CRITICAL,NULL, &hostname,&msg))) ) lib$signal(status); pthread_delay_np(&delta); if ( !(1 & (status = syslog_shut (ctx))) ) lib$signal(status); } #endif