#pragma module ADC_SRV "ADC-SRV-1-A" #define __MODULE__ "ADC-SRV" /* **++ ** FACILITY: StarLet ADC server - Advanced Direct Connection implementation for OpenVMS ** ** MODULE DESCRIPTION: ** ** This is a main module of the ADC Server. ** ** AUTHORS: ** ** Ruslan R. Laishev ** ** CREATION DATE: 14-JUL-2009 ** ** DESIGN ISSUES: ** ** ** ** MODIFICATION HISTORY: ** ** ** 27-OCT-2009 RRL Added logicals ADC_MINSHAREGB,ADC_MINFILES ** {@tbs@}... **-- */ /* ** ** OpenVMS Includes ** */ #include #include #include #include #include #include #include #include #include #include "md5.h" #include "sha.h" #define __NEW_STARLET 1 #include #include #include #include #include "adcdef.h" #include "adc_msg.h" #include "macros.h" /* ** Globals */ int exit_flag = 0,mainchan = 0; #pragma __member_alignment __save #pragma __nomember_alignment #pragma __nomember_alignment QUADWORD ADC_ENT ctx_tbl[8192]; const int ctx_tblsz = sizeof(ctx_tbl)/sizeof(ctx_tbl[0]); QUE work = {0,0,0}; tobekilled = {0,0,0}; ADC_VEC vec = { {$ascic("StarLet\\sADC\Hub")}, {$ascic("OpenVMS\\sforever!")}, {$ascic("StarLet\\sADC\\Hub\\s\\for\\sOpenVMS/IA64\\s1-A")}, {$ascic("adc://adc.deltatel.ru:412")}, {$ascic("http://www.StarLet.SPb.RU")}, {$ascic("Ruslan\\sR.\\sLaishev")}}; #pragma __member_alignment __restore static int __adc_getctx ( ADC_CTX ** ctx ) { int status,i,nonce[2]; MD5_CTX md; for (i = 0; i < sizeof(ctx_tbl)/sizeof(ctx_tbl[0]); i++) { if ( !ctx_tbl[i].ctx$l_flag ) break; } if ( i > sizeof(ctx_tbl)/sizeof(ctx_tbl[0]) ) return SS$_ABORT; ctx_tbl[i].ctx$l_flag = CTX$M_USED; /* ** Allocate memory for new context */ if ( !(1 & (status = _adc_getvm(ctx,sizeof(ADC_CTX)))) ) lib$signal(status); ctx_tbl[i].ctx$a_ptr = *ctx; (*ctx)->ctx$v_sid = i; /* ** Salt... */ sys$gettim(&nonce); MD5_Init(&md); MD5_Update(&md,&nonce,2*sizeof(int)); MD5_Final(&(*ctx)->ctx$b_salt,&md); MD5_Init(&md); MD5_Update(&md,ctx,sizeof(ctx)); MD5_Final(&(*ctx)->ctx$b_salt[MD5_DIGEST_LENGTH],&md); return SS$_NORMAL; } static int __adc_freectx ( ADC_CTX * ctx ) { int status; /* ** Release memory has been allocated for context */ if ( !(1 & (status = _adc_freevm(ctx,sizeof(ADC_CTX)))) ) lib$signal(status); ctx_tbl[ctx->ctx$v_sid].ctx$l_flag = 0; ctx_tbl[ctx->ctx$v_sid].ctx$a_ptr = NULL; return SS$_NORMAL; } int adc_getcmd ( ADC_CTX * ctx ) { int status; /* ** Reading.... */ if ( !(1 & (status = netio_readln(ctx->ctx$l_chan, &ctx->buf_b_buf[ctx->buf_w_len], sizeof(ctx->buf_b_buf) - ctx->buf_w_len, &ctx->buf_w_len, adc_getcmd,ctx))) ) { if ( status == SS$_ENDOFFILE ) { /* ** Got a command line, insert the context into the ** "to process" queue, wake up a main processing loop */ if (!(1 & (status = lib$insqti(ctx,&work,&RETRY_COUNT))) ) lib$signal(status); } else if ( !(1 & (status = lib$insqti(ctx,&tobekilled,&RETRY_COUNT))) ) lib$signal(status); //return status; } return sys$wake(0,0); } void * lstn_adc (void) { int status,i = 0; unsigned chan = 0, port = 0; ADC_CTX *newctx = NULL; struct in_addr addr; /* ** A main loop */ while ( !exit_flag ) { /* ** Start waiting for new connection request */ if ( !(1 & (status = netio_accept (mainchan,&chan,&addr,&port))) ) { /* ** Error checking. */ if ( (status == SS$_CANCEL) || (SS$_ABORT) ) break; else lib$signal(status); } /* ** Get new context from the table */ if ( !(1 & (status = __adc_getctx(&newctx))) ) { lib$signal(status); netio_close(chan); continue; } /* ** Fill new context */ newctx->ctx$l_chan = chan; newctx->ctx$w_port = port; memcpy(&newctx->ctx$l_addr,&addr,sizeof(struct in_addr)); newctx->addr_b_len = (unsigned char) sprintf(newctx->addr_t_sts,"%u.%u.%u.%u", addr.S_un.S_un_b.s_b1,addr.S_un.S_un_b.s_b2, addr.S_un.S_un_b.s_b3,addr.S_un.S_un_b.s_b4); /* ** Start AST-driven reading from the channel */ if ( !(1 & (status = sys$dclast (adc_getcmd,newctx,0))) ) { lib$signal(status); netio_close(chan); if ( !(1 & (status = __adc_freectx(newctx))) ) lib$signal(status); } vec.vec$w_uc++; }; pthread_exit(&status); return NULL; } /* ** Main */ int main (void) { int status = 0,port = ADC$PORT_ADC,bufl = 0; pthread_attr_t tattr; pthread_t tid; ADC_CTX *ctx; ADC_MSG *msg; char *cp; /* ** Initalize attributes for threads */ status = pthread_attr_init(&tattr); status = pthread_attr_setdetachstate(&tattr,PTHREAD_CREATE_JOINABLE); status = pthread_attr_setstacksize(&tattr,128000); /* ** Reading configuration */ if ( cp = getenv("ADC_MINSHAREGB") ) status = atoi(cp); vec.vec$q_minss = status*1024*1024; if ( cp = getenv("ADC_MINFILES") ) vec.vec$l_minsf = atoi(cp); if ( cp = getenv("ADC_MINSLOTS") ) vec.vec$l_minsl = atoi(cp); /* ** Open channel to UDP device, is used for network requests */ if ( !(1 & (status = netio_start (&mainchan,port))) ) { _adc_log(ADC_ERRNETOPEN,port,status); sys$exit(status); } /* ** Start listener */ if ( status = pthread_create(&tid,&tattr,(void *)lstn_adc,NULL) ) return _adc_log(ADC_ERRTHREAD,strerror(status)); /* ** Main processing loop */ _adc_log(ADC_READY,port); while ( !exit_flag ) { while ( 1 & (status = lib$remqhi(&work,&ctx,&RETRY_COUNT)) ) { /* ** Skip processing "Keep-Alive" zero-length messages */ if ( !ctx->buf_w_len ) { if ( !(1 & (status = sys$dclast (adc_getcmd,ctx,0))) ) lib$signal(status); continue; } /* ** Parse received message */ _adc_trace(ctx,"CMD[0:!UW] = '!AD'", ctx->buf_w_len,ctx->buf_w_len,ctx->buf_b_buf); if ( 1 & (status = _adc_decode(&msg,ctx->buf_b_buf,ctx->buf_w_len)) ) { /* ** Processing parsed message */ msg->msg$v_sid = ctx->ctx$v_sid; status = _adc_proc(ctx,msg); } else _adc_log(ADC_MALFORMED,ctx->buf_w_len,ctx->buf_b_buf); ctx->buf_w_len = 0; /* ** Free processed message, set buffer data length to zero, ** start reading input */ if ( !(1 & (status = _adc_freevm(msg,sizeof(ADC_MSG)))) ) lib$signal(status); /* ** Enqueue readig for message */ if ( !(1 & (status = sys$dclast (adc_getcmd,ctx,0))) ) lib$signal(status); } /* ** Process disconnected sessions, free contexts */ while ( 1 & (status = lib$remqhi(&tobekilled,&ctx,&RETRY_COUNT)) ) { netio_close(ctx->ctx$l_chan); _adc_trace(ctx,"Disconnect."); _adc_qui(ctx); __adc_freectx(ctx); vec.vec$w_uc--; } sys$hiber(); } return status; }