diff --git a/src/ca/access.c b/src/ca/access.c index 03e896986..ea844650f 100644 --- a/src/ca/access.c +++ b/src/ca/access.c @@ -6,22 +6,29 @@ /* */ /* Copyright, 1986, The Regents of the University of California. */ /* */ +/* Author: Jeffrey O. Hill */ /* */ /* History */ /* ------- */ /* */ -/* Date Programmer Comments */ -/* ---- ---------- -------- */ -/* 8/87 Jeff Hill Init Release */ -/* 1/90 Jeff HIll switched order in task exit */ -/* so events are deleted first */ -/* then closed */ -/* 3/90 Jeff Hill Changed error message strings */ -/* to allocate in this module only */ -/* & further improved vx task exit */ -/* 021291 joh fixed potential problem with strncpy and */ +/* Date Person Comments */ +/* ---- ------ -------- */ +/* 8/87 joh Init Release */ +/* 1/90 joh switched order in task exit */ +/* so events are deleted first then closed */ +/* 3/90 joh Changed error message strings */ +/* to allocate in this module only */ +/* & further improved vx task exit */ +/* 021291 joh fixed potential problem with strncpy and */ /* the vxWorks task name. */ -/* 022791 mda integration of ANL/LANL db code */ +/* 022291 joh read sync not incremented when conn is down */ +/* 030791 joh vx lcl event buf free prior to first alloc fix */ +/* 030791 joh made lcl buffer safe in ca_event_handler() */ +/* 031291 joh added DBR_LONG to ca_put, made UNIX and vxWorks */ +/* ca_put less sensitive to future data type */ +/* additions, added better string bounds checking */ +/* 060591 joh delinting */ +/* 061391 joh RISC alignment in outgoing messages */ /* */ /*_begin */ /************************************************************************/ @@ -42,7 +49,7 @@ /* ------- -------- */ /* Things that could be done to improve this code */ /* 1) Check timeouts on ca_pend for values to large */ -/* 2) Allow them to recieve channel A when channel B changes */ +/* 2) Allow them to recv channel A when channel B changes */ /* */ /************************************************************************/ /*_end */ @@ -60,8 +67,11 @@ #include #ifdef vxWorks -#include -#include +# include +/* +# include +*/ +# include #endif /* @@ -85,47 +95,23 @@ /****************************************************************/ /* Macros for syncing message insertion into send buffer */ /****************************************************************/ +#define EXTMSGPTR(PIIU)\ + ((struct extmsg *) &(PIIU)->send->buf[(PIIU)->send->stk]) -#define SNDBEG(STRUCTURE) \ -SND_BEG(STRUCTURE, &iiu[chix->iocix]) +#define CAC_ALLOC_MSG(PIIU, EXTSIZE) cac_alloc_msg((PIIU), (EXTSIZE)) +/* + * Make sure string is aligned for the most restrictive architecture + * VAX none required + * 680xx binary rounding + * SPARC octal rounding + */ +#define CAC_ADD_MSG(PIIU) \ + EXTMSGPTR(PIIU)->m_postsize = \ + CA_MESSAGE_ALIGN(EXTMSGPTR(PIIU)->m_postsize),\ + (PIIU)->send->stk += sizeof(struct extmsg) + \ + EXTMSGPTR(PIIU)->m_postsize, \ + EXTMSGPTR(PIIU)->m_postsize = htons(EXTMSGPTR(PIIU)->m_postsize); -#define SNDBEG_NOLOCK(STRUCTURE) \ -SND_BEG_NOLOCK(STRUCTURE, &iiu[chix->iocix]) - -#define SND_BEG(STRUCTURE, PIIU)\ -LOCK SND_BEG_NOLOCK(STRUCTURE,PIIU) - -#define SND_BEG_NOLOCK(STRUCTURE,PIIU) \ -{ \ - void send_msg(); \ - register struct STRUCTURE *mptr; \ - register unsigned short msgsize = sizeof(*mptr); \ - register struct ioc_in_use *psendiiu = (PIIU); \ - if(psendiiu->send->stk + msgsize > psendiiu->max_msg)send_msg(); \ - mptr = (struct STRUCTURE *) (psendiiu->send->buf + psendiiu->send->stk); - - -#define SNDEND \ -SNDEND_NOLOCK UNLOCK - - -#define SNDEND_NOLOCK \ -psendiiu->send->stk += msgsize;} - - -#define SNDBEG_VARIABLE(POSTSIZE) \ -LOCK SNDBEG_VARIABLE_NOLOCK(POSTSIZE) - - -#define SNDBEG_VARIABLE_NOLOCK(POSTSIZE) \ -{ \ - void send_msg(); \ - register struct extmsg *mptr; \ - register unsigned short msgsize = sizeof(*mptr) + POSTSIZE; \ - register struct ioc_in_use *psendiiu = &iiu[chix->iocix]; \ - if(psendiiu->send->stk+sizeof(*mptr)+POSTSIZE > psendiiu->max_msg) \ - send_msg(); \ - mptr = (struct extmsg *) (psendiiu->send->buf + psendiiu->send->stk); @@ -138,11 +124,11 @@ LOCK SNDBEG_VARIABLE_NOLOCK(POSTSIZE) #define CHIXCHK(CHIX) \ { \ - register unsigned short iocix = (CHIX)->iocix; \ - if( iocix == BROADCAST_IIU || \ - (iocix >= nxtiiu && iocix != LOCAL_IIU) || \ - INVALID_DB_REQ((CHIX)->type) ) \ - return ECA_BADCHID; \ + register unsigned short iocix = (CHIX)->iocix; \ + if( iocix == BROADCAST_IIU || \ + (iocix >= nxtiiu && iocix != LOCAL_IIU) || \ + INVALID_DB_REQ((CHIX)->type) ) \ + return ECA_BADCHID; \ } /* type to detect them using deallocated channel in use block */ @@ -151,31 +137,65 @@ LOCK SNDBEG_VARIABLE_NOLOCK(POSTSIZE) /* allow them to add monitors to a disconnected channel */ #define LOOSECHIXCHK(CHIX) \ { \ - register unsigned short iocix = CHIX->iocix; \ - if( (iocix >= nxtiiu && iocix != LOCAL_IIU) || \ - (CHIX)->type==TYPENOTINUSE ) \ - return ECA_BADCHID; \ + register unsigned short iocix = CHIX->iocix; \ + if( (iocix >= nxtiiu && iocix != LOCAL_IIU) || \ + (CHIX)->type==TYPENOTINUSE ) \ + return ECA_BADCHID; \ } -#define INITCHK if(!ca_static) ca_task_initialize(); +#define INITCHK \ +if(!ca_static) \ + ca_task_initialize(); static struct extmsg nullmsg; - +/* + * local functions + */ void ca_default_exception_handler(); void *db_init_events(); void ca_default_exception_handler(); -void ca_repeater_task(); int ca_import(); - +void spawn_repeater(); +void ca_task_exit_tcbx(); #ifdef vxWorks -static check_for_fp(); -static ca_add_task_variable(); -static void ca_task_exit_tid(); -static void issue_get_callback(); -static void ca_event_handler(); +void ca_task_exit_tid(); +#else +void ca_process_exit(); #endif +void check_for_fp(); +int ca_add_task_variable(); +void issue_get_callback(); +void ca_event_handler(); + + +/* + * + * cac_alloc_msg() + * + * return a pointer to reserved message buffer space or + * nill if the message will not fit + * + * + */ +struct extmsg *cac_alloc_msg(piiu, extsize) +struct ioc_in_use *piiu; +unsigned extsize; +{ + unsigned msgsize = sizeof(*cac_alloc_msg())+extsize; + struct extmsg *pmsg; + + if(piiu->send->stk+msgsize > piiu->max_msg){ + cac_send_msg(); + if(piiu->send->stk+msgsize > piiu->max_msg){ + return NULL; + } + } + pmsg = (struct extmsg *) (piiu->send->buf + piiu->send->stk); + pmsg->m_postsize = extsize; + return pmsg; +} /* @@ -191,173 +211,198 @@ ca_task_initialize () #endif { - int status; - char name[15]; - if(!ca_static){ + if (!ca_static) { - /* - Spawn the repeater task as needed - */ - if(!repeater_installed()){ -# ifdef UNIX - /* - * This method of spawn places a path name in the code so it has been - * avoided for now - * - * use of fork makes ca and repeaters image larger than required - * - * system("/path/repeater &"); - */ - status = fork(); - if(status<0) - SEVCHK(ECA_INTERNAL,"couldnt spawn the repeater task"); - if(!status) - ca_repeater_task(); -# endif -# ifdef vxWorks - status = taskSpawn( - CA_REPEATER_NAME, - CA_REPEATER_PRI, - CA_REPEATER_OPT, - CA_REPEATER_STACK, - ca_repeater_task - ); - if(status<0) - SEVCHK(ECA_INTERNAL,"couldnt spawn the repeater task"); -# endif -# ifdef VMS - { - static $DESCRIPTOR(image, "LAACS_CA_REPEATER"); - static $DESCRIPTOR(name, "CA repeater"); - static $DESCRIPTOR(in, "CONSOLE"); - static $DESCRIPTOR(out, "CONSOLE"); - static $DESCRIPTOR(err, "CONSOLE"); - int privs = ~0; - unsigned long pid; + if (repeater_installed()==FALSE) { + spawn_repeater(); + } +#ifdef vxWorks + check_for_fp(); + if (ca_add_task_variable() == ERROR) + abort(); +#endif - status = sys$creprc( - &pid, - &image, - &in, - &out, - &err, - &privs, - NULL, - &name, - 4, /*base priority */ - NULL, - NULL, - PRC$M_DETACH); - if(status != SS$_NORMAL) - lib$signal(status); -printf("spawning repeater %x\n", pid); - } -# endif - } + ca_static = (struct ca_static *) calloc(1, sizeof(*ca_static)); + if (!ca_static) + abort(); -# ifdef vxWorks - check_for_fp(); - if(ca_add_task_variable() == ERROR) - abort(); -# endif + ca_static->ca_exception_func = ca_default_exception_handler; + ca_static->ca_exception_arg = NULL; - ca_static = (struct ca_static *) calloc(1, sizeof(*ca_static)); - if(!ca_static) - abort(); - - ca_static->ca_exception_func = ca_default_exception_handler; - ca_static->ca_exception_arg = NULL; +#ifdef VMS + { + int status; + status = lib$get_ef(&io_done_flag); + if (status != SS$_NORMAL) + lib$signal(status); + } +#endif -# ifdef VMS - status = lib$get_ef(&io_done_flag); - if(status != SS$_NORMAL) - lib$signal(status); -# endif +#ifdef vxWorks + { + char name[15]; + int status; -# ifdef vxWorks - { - char *taskName(); - ca_static->ca_tid = taskIdSelf(); + ca_static->ca_tid = taskIdSelf(); - FASTLOCKINIT(&client_lock); + FASTLOCKINIT(&client_lock); - evuser = (void *) db_init_events(); - if(!evuser) - abort(); + evuser = (void *) db_init_events(); + if (!evuser) + abort(); + + strcpy(name, "EV "); + strncat( + name, + taskName(VXTHISTASKID), + sizeof(name) - strlen(name) - 1); + status = db_start_events( + evuser, + name, + ca_import, + taskIdSelf()); + if (status != OK) + abort(); + } +#endif - strcpy(name, "EV "); - strncat( - name, - taskName(VXTHISTASKID), - sizeof(name)-strlen(name)-1); - status = db_start_events( - evuser, - name, - ca_import, - taskIdSelf()); - if(status != OK) - abort(); } -# endif - - } - - return ECA_NORMAL; + return ECA_NORMAL; } + /* + * spawn_repeater() * - * CHECK_FOR_FP() - * - * + * Spawn the repeater task as needed + */ +static void spawn_repeater() +{ + +#ifdef UNIX + { + int status; + + /* + * use of fork makes ca and repeater images larger than + * required but a path is not required in the code. + * + * This method of spawn places a path name in the + * code so it has been avoided for now: + * system("/path/repeater &"); + */ + status = fork(); + if (status < 0) + SEVCHK(ECA_NOREPEATER, NULL); + if (status == 0) + ca_repeater_task(); + } +#endif +#ifdef vxWorks + { + int status; + + status = taskSpawn( + CA_REPEATER_NAME, + CA_REPEATER_PRI, + CA_REPEATER_OPT, + CA_REPEATER_STACK, + ca_repeater_task); + if (status < 0){ + SEVCHK(ECA_NOREPEATER, NULL); + } + } +#endif +#ifdef VMS + { + static $DESCRIPTOR(image, "EPICS_CA_REPEATER"); + static $DESCRIPTOR(io, "EPICS_LOG_DEVICE"); + static $DESCRIPTOR(name, "CA repeater"); + int status; + unsigned long pid; + + status = sys$creprc( + &pid, + &image, + NULL, /* input (none) */ + &io, /* output */ + &io, /* error */ + NULL, /* use parents privs */ + NULL, /* use default quotas */ + &name, + 4, /* base priority */ + NULL, + NULL, + PRC$M_DETACH); + if (status != SS$_NORMAL){ + SEVCHK(ECA_NOREPEATER, NULL); +#ifdef DEBUG + lib$signal(status); +#endif + } + } +#endif +} + + + +/* + * CHECK_FOR_FP() + * + * */ #ifdef vxWorks -static check_for_fp() +static void +check_for_fp() { - { - int options; + { + int options; - if(taskOptionsGet(taskIdSelf(),&options)==ERROR) - abort(); - if(!(options & VX_FP_TASK)){ - ca_signal(ECA_NEEDSFP, NULL); + if (taskOptionsGet(taskIdSelf(), &options) == ERROR) + abort(); + if (!(options & VX_FP_TASK)) { + ca_signal(ECA_NEEDSFP, NULL); - if(taskOptionsSet(taskIdSelf(),VX_FP_TASK,VX_FP_TASK)==ERROR) - abort(); - } - } + if (taskOptionsSet( + taskIdSelf(), + VX_FP_TASK, + VX_FP_TASK) == ERROR) + { + abort(); + } + } + } } #endif /* - * - * CA_IMPORT() - * - * + * CA_IMPORT() + * + * */ #ifdef vxWorks ca_import(moms_tid) -int moms_tid; + int moms_tid; { - int status; - struct ca_static *pcas; - - pcas = (struct ca_static*) taskVarGet(moms_tid, &ca_static); - if(pcas == (struct ca_static*) ERROR) - return ECA_NOCACTX; + int status; + struct ca_static *pcas; - status = taskVarAdd(VXTHISTASKID, &ca_static); - if(status == ERROR) - abort(); - - ca_static = pcas; + pcas = (struct ca_static *) taskVarGet(moms_tid, &ca_static); + if (pcas == (struct ca_static *) ERROR) + return ECA_NOCACTX; - check_for_fp(); + status = taskVarAdd(VXTHISTASKID, &ca_static); + if (status == ERROR) + abort(); - return ECA_NORMAL; + ca_static = pcas; + + check_for_fp(); + + return ECA_NORMAL; } #endif @@ -366,33 +411,31 @@ int moms_tid; /* - * - * CA_ADD_TASK_VARIABLE() - * + * CA_ADD_TASK_VARIABLE() + * */ #ifdef vxWorks -static ca_add_task_variable() -{ - static void ca_task_exit_tcbx(); - static char ca_installed; - int status; +static int +ca_add_task_variable() +{ + static char ca_installed; + int status; - status = taskVarAdd(VXTHISTASKID, &ca_static); - if(status == ERROR) - abort(); + status = taskVarAdd(VXTHISTASKID, &ca_static); + if (status == ERROR) + abort(); - /* - only one delete hook for all CA tasks - */ - if(vxTas(&ca_installed)){ - status = taskDeleteHookAdd(ca_task_exit_tcbx); - if(status == ERROR){ - logMsg("ca_init_task: could not add CA delete routine\n"); - abort(); - } - } - - return ECA_NORMAL; + /* + * only one delete hook for all CA tasks + */ + if (vxTas(&ca_installed)) { + status = taskDeleteHookAdd(ca_task_exit_tcbx); + if (status == ERROR) { + logMsg("ca_init_task: could not add CA delete routine\n"); + abort(); + } + } + return ECA_NORMAL; } #endif @@ -411,31 +454,34 @@ ca_task_exit () #endif { - void ca_task_exit_tid(); -# ifdef vxWorks - ca_task_exit_tid(VXTHISTASKID); -# else - ca_task_exit_tid(NULL); +#ifdef vxWorks + ca_task_exit_tid(VXTHISTASKID); +#else + ca_process_exit(); #endif - return ECA_NORMAL; + return ECA_NORMAL; } + +/* + * CA_TASK_EXIT_TCBX() + * + */ #ifdef vxWorks static void ca_task_exit_tcbx(ptcbx) TCBX *ptcbx; { - void ca_task_exit_tid(); - - ca_task_exit_tid((int) ptcbx->taskId); + ca_task_exit_tid((int) ptcbx->taskId); } #endif + /* * - * CA_TASK_EXIT_TID + * CA_TASK_EXIT_TID() / CA_PROCESS_EXIT() * attempts to release all resources alloc to a channel access client * * NOTE: on vxWorks if a CA task is deleted or crashes while a @@ -443,167 +489,179 @@ TCBX *ptcbx; * */ static void +#ifdef vxWorks ca_task_exit_tid(tid) -int tid; + int tid; +#else +ca_process_exit() +#endif { - int i; - chid chix; - struct ca_static *ca_temp; - evid monix; - int status; + int i; + chid chix; + struct ca_static *ca_temp; + evid monix; +#ifdef vxWorks + int status; +#endif -# ifdef vxWorks - ca_temp = (struct ca_static *) taskVarGet(tid, &ca_static); - if(ca_temp == (struct ca_static *) ERROR) - return; +#ifdef vxWorks + ca_temp = (struct ca_static *) taskVarGet(tid, &ca_static); + if (ca_temp == (struct ca_static *) ERROR) + return; -# else - ca_temp = ca_static; -# endif +#else + ca_temp = ca_static; +#endif - /* if allready in the exit state just NOOP */ -# ifdef vxWorks - if(!vxTas(&ca_temp->ca_exit_in_progress)) - return; -# else - if(ca_temp->ca_exit_in_progress) - return; - ca_temp->ca_exit_in_progress = TRUE; -# endif + /* if allready in the exit state just NOOP */ +#ifdef vxWorks + if (!vxTas(&ca_temp->ca_exit_in_progress)) + return; +#else + if (ca_temp->ca_exit_in_progress) + return; + ca_temp->ca_exit_in_progress = TRUE; +#endif - if(ca_temp){ -# ifdef vxWorks - logMsg("ca_task_exit: Removing task %x from CA\n",tid); -# endif + if (ca_temp) { +#ifdef vxWorks + logMsg("ca_task_exit: Removing task %x from CA\n", tid); +#endif - LOCK; - /* - Fist I must stop any source of further activity - on vxWorks - */ + LOCK; + /* + * Fist I must stop any source of further activity on vxWorks + */ - /* - The main task is prevented from further CA activity - by the LOCK placed above - */ + /* + * The main task is prevented from further CA activity by the + * LOCK placed above + */ - /* - stop socket recv tasks - */ -# ifdef vxWorks - for(i=0; i< ca_temp->ca_nxtiiu; i++){ - /* - dont do a task delete if the - exit handler is running for this task - - it botches vxWorks - - */ - if(tid != ca_temp->ca_iiu[i].recv_tid) - taskDelete(ca_temp->ca_iiu[i].recv_tid); - } -# endif + /* + * stop socket recv tasks + */ +#ifdef vxWorks + for (i = 0; i < ca_temp->ca_nxtiiu; i++) { + /* + * dont do a task delete if the exit handler is + * running for this task - it botches vxWorks - + */ + if (tid != ca_temp->ca_iiu[i].recv_tid) + taskDelete(ca_temp->ca_iiu[i].recv_tid); + } +#endif - /* - Cancel all local events - */ -# ifdef vxWorks - chix = (chid) &ca_temp->ca_local_chidlist; - while(chix = (chid) chix->node.next) - while(monix = (evid) lstGet(&chix->eventq)){ - status = db_cancel_event(monix+1); - if(status==ERROR) - abort(); - if(free(monix)<0) - ca_signal(ECA_INTERNAL, "Corrupt conn evid list"); - } -# endif + /* + * Cancel all local events + */ +#ifdef vxWorks + chix = (chid) & ca_temp->ca_local_chidlist; + while (chix = (chid) chix->node.next) + while (monix = (evid) lstGet(&chix->eventq)) { + status = db_cancel_event(monix + 1); + if (status == ERROR) + abort(); + if (free(monix) < 0) + ca_signal( + ECA_INTERNAL, + "Corrupt conn evid list"); + } +#endif - /* - All local events must be canceled prior to closing the - local event facility - */ -# ifdef vxWorks - { - status = db_close_events(ca_temp->ca_evuser); - if(status==ERROR) - ca_signal(ECA_INTERNAL, "could not close event facility by id"); - } + /* + * All local events must be canceled prior to closing the + * local event facility + */ +#ifdef vxWorks + { + status = db_close_events(ca_temp->ca_evuser); + if (status == ERROR) + ca_signal( + ECA_INTERNAL, + "could not close event facility by id"); + } - if(ca_temp->ca_event_buf) - if(free(ca_temp->ca_event_buf)) - abort(); -# endif + lstFree(&ca_temp->ca_lcl_buff_list); +#endif - /* - after activity eliminated: - */ - /* - close all sockets before clearing chid blocks - and remote event blocks - */ - for(i=0; i< ca_temp->ca_nxtiiu; i++){ - if(ca_temp->ca_iiu[i].conn_up) - if(socket_close(ca_temp->ca_iiu[i].sock_chan)<0) - ca_signal(ECA_INTERNAL, "Corrupt iiu list- at close"); - if(free(ca_temp->ca_iiu[i].send)<0) - ca_signal(ECA_INTERNAL, "Corrupt iiu list- send free"); - if(free(ca_temp->ca_iiu[i].recv)<0) - ca_signal(ECA_INTERNAL, "Corrupt iiu list- recv free"); - } + /* + * after activity eliminated: + */ + /* + * close all sockets before clearing chid blocks and remote + * event blocks + */ + for (i = 0; i < ca_temp->ca_nxtiiu; i++) { + if (ca_temp->ca_iiu[i].conn_up) + if (socket_close(ca_temp->ca_iiu[i].sock_chan) < 0) + ca_signal( + ECA_INTERNAL, + "Corrupt iiu list- at close"); + if (free((char *)ca_temp->ca_iiu[i].send) < 0) + ca_signal(ECA_INTERNAL, "Corrupt iiu list- send free"); + if (free((char *)ca_temp->ca_iiu[i].recv) < 0) + ca_signal(ECA_INTERNAL, "Corrupt iiu list- recv free"); + } - /* - remove remote chid blocks and event blocks - */ - for(i=0; i< ca_temp->ca_nxtiiu; i++){ - while(chix = (chid) lstGet(&ca_temp->ca_iiu[i].chidlist)){ - while(monix = (evid) lstGet(&chix->eventq)){ - if(free(monix)<0) - ca_signal(ECA_INTERNAL, "Corrupt conn evid list"); - } - if(free(chix)<0) - ca_signal(ECA_INTERNAL, "Corrupt connected chid list"); - } - } + /* + * remove remote chid blocks and event blocks + */ + for (i = 0; i < ca_temp->ca_nxtiiu; i++) { + while (chix = (chid) lstGet(&ca_temp->ca_iiu[i].chidlist)) { + while (monix = (evid) lstGet(&chix->eventq)) { + if (free((char *)monix) < 0) + ca_signal( + ECA_INTERNAL, + "Corrupt conn evid list"); + } + if (free((char *)chix) < 0) + ca_signal( + ECA_INTERNAL, + "Corrupt connected chid list"); + } + } - /* - remove local chid blocks, paddr blocks, waiting ev blocks - */ -# ifdef vxWorks - while(chix = (chid) lstGet(&ca_temp->ca_local_chidlist)) - if(free(chix)<0) - ca_signal(ECA_INTERNAL, "Corrupt connected chid list"); - lstFree(&ca_temp->ca_dbfree_ev_list); -# endif + /* + * remove local chid blocks, paddr blocks, waiting ev blocks + */ +#ifdef vxWorks + while (chix = (chid) lstGet(&ca_temp->ca_local_chidlist)) + if (free((char *)chix) < 0) + ca_signal(ECA_INTERNAL, "Corrupt connected chid list"); + lstFree(&ca_temp->ca_dbfree_ev_list); +#endif - /* remove remote waiting ev blocks */ - lstFree(&ca_temp->ca_free_event_list); - /* remove any pending read blocks */ - lstFree(&ca_temp->ca_pend_read_list); + /* remove remote waiting ev blocks */ + lstFree(&ca_temp->ca_free_event_list); + /* remove any pending read blocks */ + lstFree(&ca_temp->ca_pend_read_list); - UNLOCK; + UNLOCK; - if(free(ca_temp)<0) - ca_signal(ECA_INTERNAL, "Unable to free task static variables"); + if (free((char *)ca_temp) < 0) + ca_signal(ECA_INTERNAL, "Unable to free task static variables"); -/* - Only remove task variable if user is calling this - from ca_task_exit with the task id = 0 + /* + * Only remove task variable if user is calling this from + * ca_task_exit with the task id = 0 + * + * This is because if I delete the task variable from a vxWorks + * exit handler it botches vxWorks task exit + */ +#ifdef vxWorks + if (tid == taskIdSelf()) { + int status; + status = taskVarDelete(tid, &ca_static); + if (status == ERROR) + ca_signal(ECA_INTERNAL, "Unable to remove ca_static from task var list"); + } +#endif - This is because if I delete the task variable from - a vxWorks exit handler it botches vxWorks task exit -*/ -# ifdef vxWorks - if(tid == taskIdSelf()) - {int status; - status = taskVarDelete(tid, &ca_static); - if(status == ERROR) - ca_signal(ECA_INTERNAL, "Unable to remove ca_static from task var list"); - } -# endif + ca_static = (struct ca_static *) NULL; - ca_static = (struct ca_static *) NULL; - - } + } } @@ -618,390 +676,410 @@ int tid; ca_build_and_connect #ifdef VAXC ( -char *name_str, -chtype get_type, -unsigned int get_count, -chid *chixptr, -void *pvalue, -void (*conn_func)(), -void *puser + char *name_str, + chtype get_type, + unsigned int get_count, + chid * chixptr, + void *pvalue, + void (*conn_func) (), + void *puser ) #else -(name_str,get_type,get_count,chixptr,pvalue,conn_func,puser) -char *name_str; -chtype get_type; -unsigned int get_count; -chid *chixptr; -void *pvalue; -void (*conn_func)(); -void *puser; +(name_str, get_type, get_count, chixptr, pvalue, conn_func, puser) + char *name_str; + chtype get_type; + unsigned int get_count; + chid *chixptr; + void *pvalue; + void (*conn_func) (); + void *puser; #endif { - long status; - chid chix; - int strcnt; - unsigned short castix; - struct in_addr broadcast_addr(); + long status; + chid chix; + int strcnt; + struct in_addr castaddr; - /* - make sure that chix is NULL on fail - */ - *chixptr = NULL; + /* + * make sure that chix is NULL on fail + */ + *chixptr = NULL; - INITCHK; + INITCHK; - if(INVALID_DB_REQ(get_type) && get_type != TYPENOTCONN) - return ECA_BADTYPE; + if (INVALID_DB_REQ(get_type) && get_type != TYPENOTCONN) + return ECA_BADTYPE; - /* - Cant check his count on build since we dont know the - native count yet. - */ + /* + * Cant check his count on build since we dont know the native count + * yet. + */ - /* Put some reasonable limit on user supplied string size */ - strcnt = strlen(name_str) + 1; - if(strcnt > MAX_STRING_SIZE) - return ECA_STRTOBIG; - if(strcnt == 1) - return ECA_EMPTYSTR; + /* Put some reasonable limit on user supplied string size */ + strcnt = strlen(name_str) + 1; + if (strcnt > MAX_STRING_SIZE) + return ECA_STRTOBIG; + if (strcnt == 1) + return ECA_EMPTYSTR; + /* + * only for IOCs + */ +#ifdef vxWorks + { + struct db_addr tmp_paddr; + struct connection_handler_args args; - if(strcnt==1 ) - return ECA_BADSTR; + /* Find out quickly if channel is on this node */ + status = db_name_to_addr(name_str, &tmp_paddr); + if (status == OK) { + /* + * allocate CHIU (channel in use) block + * + * also allocate enough for the channel name & paddr + * block + */ + *chixptr = chix = (chid) malloc(sizeof(*chix) + + strcnt + sizeof(struct db_addr)); + if (!chix) + abort(); - /* Make sure string is aligned to short word boundaries for MC68000 */ - strcnt = BI_ROUND(strcnt)<<1; + chix->paddr = (void *) (strcnt + (char *) (chix + 1)); + *(struct db_addr *) chix->paddr = tmp_paddr; + chix->puser = puser; + chix->connection_func = conn_func; + chix->type = ((struct db_addr *) + chix->paddr)->field_type; + chix->count = ((struct db_addr *) + chix->paddr)->no_elements; + chix->iocix = LOCAL_IIU; + chix->state = cs_conn; + lstInit(&chix->eventq); + strncpy(chix + 1, name_str, strcnt); -# ifdef vxWorks /* only for IO machines */ - { - struct db_addr tmp_paddr; - struct connection_handler_args args; + /* check for just a search */ + if (get_count && get_type != TYPENOTCONN && pvalue) { + status = db_get_field( + &tmp_paddr, + get_type, + pvalue, + get_count, + NULL); + if (status != OK) { + *chixptr = (chid) free((char *)chix); + return ECA_GETFAIL; + } + } + LOCK; + lstAdd(&local_chidlist, chix); + UNLOCK; - /* Find out quickly if channel is on this node */ - status = db_name_to_addr(name_str, &tmp_paddr); - if(status==OK){ + if (chix->connection_func) { + args.chid = chix; + args.op = CA_OP_CONN_UP; - /* allocate CHIU (channel in use) block */ - /* also allocate enough for the channel name & paddr block*/ - *chixptr = chix = (chid) malloc(sizeof(*chix) - + strcnt + sizeof(struct db_addr)); - if(!chix) - abort(); - - chix->paddr = (void *) (strcnt + (char *)(chix+1)); - *(struct db_addr *)chix->paddr = tmp_paddr; - chix->puser = puser; - chix->connection_func = conn_func; - chix->type = ( (struct db_addr *)chix->paddr )->field_type; - chix->count = ( (struct db_addr *)chix->paddr )->no_elements; - chix->iocix = LOCAL_IIU; - chix->state = cs_conn; - lstInit(&chix->eventq); - strncpy(chix+1, name_str, strcnt); - - /* check for just a search */ - if(get_count && get_type != TYPENOTCONN && pvalue){ - status=db_get_field(&tmp_paddr, get_type, pvalue, get_count); - if(status!=OK){ - free(chix->paddr); - *chixptr = (chid) free(chix); - return ECA_GETFAIL; + (*chix->connection_func) (args); + } + return ECA_NORMAL; + } } - } - LOCK; - lstAdd(&local_chidlist, chix); - UNLOCK; +#endif - if(chix->connection_func){ - args.chid = chix; - args.op = CA_OP_CONN_UP; + /* allocate CHIU (channel in use) block */ + /* also allocate enough for the channel name */ + *chixptr = chix = (chid) malloc(sizeof(*chix) + strcnt); + if (!chix) + return ECA_ALLOCMEM; - (*chix->connection_func)(args); - } + LOCK; + castaddr = broadcast_addr(); + status = alloc_ioc( + &castaddr, + IPPROTO_UDP, + &chix->iocix + ); + if (~status & CA_M_SUCCESS) { + *chixptr = (chid) free((char *)chix); + goto exit; + } + chix->puser = puser; + chix->connection_func = conn_func; + chix->type = TYPENOTCONN; /* invalid initial type */ + chix->count = 0; /* invalid initial count */ + chix->paddr = (void *) NULL; /* invalid initial paddr */ - return ECA_NORMAL; - } - } -# endif - - /* allocate CHIU (channel in use) block */ - /* also allocate enough for the channel name */ - *chixptr = chix = (chid) malloc(sizeof(*chix) + strcnt); - if(!chix) - return ECA_ALLOCMEM; + /* save stuff for build retry if required */ + chix->build_type = get_type; + chix->build_count = get_count; + chix->build_value = (void *) pvalue; + chix->name_length = strcnt; + chix->state = cs_never_conn; + lstInit(&chix->eventq); - LOCK; + /* Save this channels name for retry if required */ + strncpy(chix + 1, name_str, strcnt); - status = alloc_ioc ( - broadcast_addr(), - IPPROTO_UDP, - &chix->iocix - ); - if(~status & CA_M_SUCCESS){ - *chixptr = (chid) free(chix); - goto exit; - } - - chix->puser = puser; - chix->connection_func = conn_func; - chix->type = TYPENOTCONN; /* invalid initial type */ - chix->count = 0; /* invalid initial count */ - chix->paddr = (void *)NULL; /* invalid initial paddr */ - - /* save stuff for build retry if required */ - chix->build_type = get_type; - chix->build_count = get_count; - chix->build_value = (void *) pvalue; - chix->name_length = strcnt; - chix->state = cs_never_conn; - lstInit(&chix->eventq); - - /* Save this channels name for retry if required */ - strncpy(chix+1, name_str, strcnt); - - lstAdd(&iiu[BROADCAST_IIU].chidlist, chix); - /* set the conn tries back to zero so this channel can be found */ - iiu[BROADCAST_IIU].nconn_tries = 0; - - status = build_msg(chix, FALSE, DONTREPLY); - if(!chix->connection_func){ - SETPENDRECV; - if(VALID_BUILD(chix)) - SETPENDRECV; - } + lstAdd(&iiu[BROADCAST_IIU].chidlist, chix); + /* + * set the conn tries back to zero so this channel's location can be + * found + */ + iiu[BROADCAST_IIU].nconn_tries = 0; + iiu[BROADCAST_IIU].next_retry = CA_CURRENT_TIME; + iiu[BROADCAST_IIU].retry_delay = 1; /* sec */ + build_msg(chix, DONTREPLY); + if (!chix->connection_func) { + SETPENDRECV; + if (VALID_BUILD(chix)) + SETPENDRECV; + } exit: - UNLOCK; + UNLOCK; - return status; + return status; } /* - * BUILD_MSG() - * - * NOTE: *** lock must be applied while in this routine *** + * BUILD_MSG() + * + * NOTE: *** lock must be applied while in this routine *** * */ -build_msg(chix,reply_type) -chid chix; -int reply_type; +void build_msg(chix, reply_type) + chid chix; + int reply_type; { - register int size; - register int cmd; + register int size; + register int cmd; + register struct extmsg *mptr; - if(VALID_BUILD(chix)){ - size = chix->name_length + sizeof(struct extmsg); - cmd = IOC_BUILD; - } - else{ - size = chix->name_length; - cmd = IOC_SEARCH; - } + if (VALID_BUILD(chix)) { + size = chix->name_length + sizeof(struct extmsg); + cmd = IOC_BUILD; + } else { + size = chix->name_length; + cmd = IOC_SEARCH; + } + mptr = CAC_ALLOC_MSG(&iiu[chix->iocix], size); - SNDBEG_VARIABLE_NOLOCK(size) + mptr->m_cmmd = htons(cmd); + mptr->m_available = (int) chix; + mptr->m_type = reply_type; + mptr->m_count = 0; + mptr->m_pciu = (void *) chix; - mptr->m_cmmd = htons(cmd); - mptr->m_postsize = htons(size); - mptr->m_available = (int) chix; - mptr->m_type = reply_type; - mptr->m_count = 0; - mptr->m_pciu = (void *) chix; - - if(cmd == IOC_BUILD){ - /* msg header only on db read req */ - mptr++; - mptr->m_postsize = 0; - mptr->m_cmmd = htons(IOC_READ_BUILD); - mptr->m_type = htons(chix->build_type); - mptr->m_count = htons(chix->build_count); - mptr->m_available = (int) chix->build_value; - mptr->m_pciu = 0; - - - } - - /* channel name string */ - /* forces a NULL at the end because strcnt is allways >= strlen + 1 */ - mptr++; - strncpy(mptr, chix+1, chix->name_length); - - SNDEND_NOLOCK; - - return ECA_NORMAL; + if (cmd == IOC_BUILD) { + /* msg header only on db read req */ + mptr++; + mptr->m_postsize = 0; + mptr->m_cmmd = htons(IOC_READ_BUILD); + mptr->m_type = htons(chix->build_type); + mptr->m_count = htons(chix->build_count); + mptr->m_available = (int) chix->build_value; + mptr->m_pciu = 0; + } + /* + * channel name string - forces a NULL at the end because + * strcnt is allways >= strlen + 1 + */ + mptr++; + strncpy(mptr, chix + 1, chix->name_length); + CAC_ADD_MSG(&iiu[chix->iocix]); } /* - * - * CA_ARRAY_GET() - * - * + * CA_ARRAY_GET() + * + * */ ca_array_get #ifdef VAXC ( -chtype type, -unsigned int count, -chid chix, -register void *pvalue + chtype type, + unsigned int count, + chid chix, + register void *pvalue ) #else -(type,count,chix,pvalue) -chtype type; -unsigned int count; -chid chix; -register void *pvalue; +(type, count, chix, pvalue) + chtype type; + unsigned int count; + chid chix; + register void *pvalue; #endif { - CHIXCHK(chix); + register struct extmsg *mptr; + unsigned size=0; - if(INVALID_DB_REQ(type)) - return ECA_BADTYPE; + CHIXCHK(chix); - if(count > chix->count) - return ECA_BADCOUNT; + if (INVALID_DB_REQ(type)) + return ECA_BADTYPE; -# ifdef vxWorks - { - int status; + if (count > chix->count) + return ECA_BADCOUNT; + +#ifdef vxWorks + { + int status; + + if (chix->iocix == LOCAL_IIU) { + status = db_get_field( + chix->paddr, + type, + pvalue, + count, + NULL); + if (status == OK) + return ECA_NORMAL; + else + return ECA_GETFAIL; + } + } +#endif + + LOCK; + mptr = CAC_ALLOC_MSG(&iiu[chix->iocix], size); + + /* + * msg header only on db read req + */ + mptr->m_cmmd = htons(IOC_READ); + mptr->m_type = htons(type); + mptr->m_available = (long) pvalue; + mptr->m_count = htons(count); + mptr->m_pciu = chix->paddr; + + CAC_ADD_MSG(&iiu[chix->iocix]); + UNLOCK; + + SETPENDRECV; - if(chix->iocix == LOCAL_IIU){ - status = db_get_field( - chix->paddr, - type, - pvalue, - count ); - if(status==OK) return ECA_NORMAL; - else - return ECA_GETFAIL; - } - } -# endif - - - SNDBEG(extmsg) - - /* msg header only on db read req */ - mptr->m_postsize = 0; - mptr->m_cmmd = htons(IOC_READ); - mptr->m_type = htons(type); - mptr->m_available = (long) pvalue; - mptr->m_count = htons(count); - mptr->m_pciu = chix->paddr; - SNDEND - - SETPENDRECV; - return ECA_NORMAL; } + /* - * - * CA_ARRAY_GET_CALLBACK() - * - * - * + * CA_ARRAY_GET_CALLBACK() + * + * + * */ ca_array_get_callback #ifdef VAXC ( -chtype type, -unsigned int count, -chid chix, -void (*pfunc)(), -void *arg + chtype type, + unsigned int count, + chid chix, + void (*pfunc) (), + void *arg ) #else -(type,count,chix,pfunc,arg) -chtype type; -unsigned int count; -chid chix; -void (*pfunc)(); -void *arg; +(type, count, chix, pfunc, arg) + chtype type; + unsigned int count; + chid chix; + void (*pfunc) (); + void *arg; #endif { - int status; - evid monix; - void ca_event_handler(); - void issue_get_callback(); + int status; + evid monix; - CHIXCHK(chix); + CHIXCHK(chix); - if(INVALID_DB_REQ(type)) - return ECA_BADTYPE; + if (INVALID_DB_REQ(type)) + return ECA_BADTYPE; - if(count > chix->count) - return ECA_BADCOUNT; + if (count > chix->count) + return ECA_BADCOUNT; -# ifdef vxWorks - if(chix->iocix == LOCAL_IIU){ - struct pending_event ev; - ev.usr_func = pfunc; - ev.usr_arg = arg; - ev.chan = chix; - ev.type = type; - ev.count = count; - ca_event_handler(&ev, chix->paddr, NULL); - return ECA_NORMAL; - } -# endif +#ifdef vxWorks + if (chix->iocix == LOCAL_IIU) { + struct pending_event ev; - LOCK; - if(!(monix = (evid) lstGet(&free_event_list))) - monix = (evid) malloc(sizeof *monix); + ev.usr_func = pfunc; + ev.usr_arg = arg; + ev.chan = chix; + ev.type = type; + ev.count = count; + ca_event_handler(&ev, chix->paddr, NULL, NULL); + return ECA_NORMAL; + } +#endif - if(monix){ + LOCK; + if (!(monix = (evid) lstGet(&free_event_list))) + monix = (evid) malloc(sizeof *monix); - monix->chan = chix; - monix->usr_func = pfunc; - monix->usr_arg = arg; - monix->type = type; - monix->count = count; + if (monix) { - lstAdd(&pend_read_list, monix); + monix->chan = chix; + monix->usr_func = pfunc; + monix->usr_arg = arg; + monix->type = type; + monix->count = count; - issue_get_callback(monix); + lstAdd(&pend_read_list, monix); - status = ECA_NORMAL; - }else - status = ECA_ALLOCMEM; + issue_get_callback(monix); - UNLOCK; - return status; + status = ECA_NORMAL; + } else + status = ECA_ALLOCMEM; + + UNLOCK; + return status; } + /* * * ISSUE_GET_CALLBACK() * (lock must be on) */ -static void issue_get_callback(monix) -register evid monix; +static void +issue_get_callback(monix) + register evid monix; { - register chid chix = monix->chan; + register chid chix = monix->chan; + unsigned size = 0; + unsigned count; + register struct extmsg *mptr; - SNDBEG_NOLOCK(extmsg) + /* + * set to the native count if they specify zero + */ + if (monix->count == 0 || monix->count > chix->count){ + count = chix->count; + } + else{ + count = monix->count; + } + + mptr = CAC_ALLOC_MSG(&iiu[chix->iocix], size); - /* msg header only on db read notify req */ - mptr->m_cmmd = htons(IOC_READ_NOTIFY); - mptr->m_type = htons(monix->type); - mptr->m_available = (long) monix; - mptr->m_count = htons(monix->count); - mptr->m_pciu = chix->paddr; - mptr->m_postsize = 0; + /* msg header only on db read notify req */ + mptr->m_cmmd = htons(IOC_READ_NOTIFY); + mptr->m_type = htons(monix->type); + mptr->m_available = (long) monix; + mptr->m_count = htons(count); + mptr->m_pciu = chix->paddr; - SNDEND_NOLOCK; + CAC_ADD_MSG(&iiu[chix->iocix]); } @@ -1026,119 +1104,150 @@ chid chix; register void *pvalue; #endif { - register int postcnt; - register int tmp; - register void *pdest; - register int i; - register int size; - - CHIXCHK(chix); - - if(INVALID_DB_REQ(type)) - return ECA_BADTYPE; - - if(count > chix->count) - return ECA_BADCOUNT; - -# ifdef vxWorks - { - int status; - - if(chix->iocix == LOCAL_IIU){ - status = db_put_field( chix->paddr, - type, - pvalue, - count); - if(status==OK) - return ECA_NORMAL; - else - return ECA_PUTFAIL; - } - } -# endif - - size = dbr_value_size[type]; - postcnt = dbr_size[type] + size*(count-1); - SNDBEG_VARIABLE(postcnt) - pdest = (void *)(mptr+1); - - for(i=0; i< count; i++){ - - switch(type){ - case DBR_INT: - case DBR_ENUM: - *(short *)pdest = htons(*(short *)pvalue); - break; - - case DBR_FLOAT: - case DBR_DOUBLE: - /* most compilers pass all floats as doubles */ - htonf(pvalue, pdest); - break; - - case DBR_STRING: + register struct extmsg *mptr; + register int postcnt; + register void *pdest; + register unsigned size_of_one; + register int i; /* - If arrays of strings are passed I assume each is MAX_STRING_SIZE - or less and copy count * MAX_STRING_SIZE bytes into the outgoing - IOC message. - */ - if(count>1){ - memcpy(pdest,pvalue,postcnt); - goto array_loop_exit; + * valid channel id test + */ + CHIXCHK(chix); + + /* + * compound types not allowed + */ + if(INVALID_DB_FIELD(type)) + return ECA_BADTYPE; + + /* + * check for valid count + */ + if(count > chix->count || count == 0) + return ECA_BADCOUNT; + +#ifdef vxWorks + { + int status; + + if(chix->iocix == LOCAL_IIU){ + status = db_put_field( chix->paddr, + type, + pvalue, + count); + if(status==OK) + return ECA_NORMAL; + else + return ECA_PUTFAIL; + } } +#endif - /* Put some reasonable limit on user supplied string size */ - { unsigned int strsize; - strsize = strlen(pvalue) + 1; - /* Make sure string is aligned to short word boundaries for MC68000 */ - /* forces a NULL at the end because strcnt is allways >= strlen + 1 */ - strsize = BI_ROUND(strsize+1)<<1; - if(strsize>MAX_STRING_SIZE) - return ECA_STRTOBIG; - memcpy(pdest,pvalue,strsize); + size_of_one = dbr_size[type]; + postcnt = size_of_one*count; + + /* + * + * Each of their strings is checked for prpoper size + * so there is no chance that they could crash the + * CA server. + */ + if(type == DBR_STRING){ + char *pstr = (char *)pvalue; + + if(count == 1) + postcnt = strlen(pstr)+1; + + for(i=0; i< count; i++){ + unsigned int strsize; + + strsize = strlen(pstr) + 1; + + if(strsize>size_of_one) + return ECA_STRTOBIG; + + pstr += size_of_one; + } } - break; - /* record transfer and convert */ - case DBR_STS_STRING: - case DBR_STS_INT: - case DBR_STS_FLOAT: - case DBR_STS_DOUBLE: - case DBR_STS_ENUM: - case DBR_GR_INT: - case DBR_GR_FLOAT: - case DBR_GR_DOUBLE: - case DBR_CTRL_INT: - case DBR_CTRL_FLOAT: - case DBR_CTRL_DOUBLE: - case DBR_CTRL_ENUM: -# ifdef VAX - (*cvrt[type])(pvalue,pdest,TRUE,count); -# else - if(pdest != pvalue) - memcpy(pdest,pvalue,postcnt); -# endif - goto array_loop_exit; - default: - return ECA_BADTYPE; - } - (char *) pdest += size; - (char *) pvalue += size; - } + LOCK; + mptr = CAC_ALLOC_MSG(&iiu[chix->iocix], postcnt); + pdest = (void *)(mptr+1); -array_loop_exit: - mptr->m_cmmd = htons(IOC_WRITE); - mptr->m_postsize = htons(postcnt); - mptr->m_type = htons(type); - mptr->m_count = htons(count); - mptr->m_pciu = chix->paddr; - mptr->m_available = (long) chix; - SNDEND +#ifdef VAX + /* + * No compound types here because these types are read only + * and therefore only appropriate for gets or monitors + */ + for(i=0; i< count; i++){ + switch(type){ + case DBR_LONG: + *(long *)pdest = htonl(*(long *)pvalue); + break; - return ECA_NORMAL; + case DBR_CHAR: + *(char *)pdest = *(char *)pvalue; + break; + + case DBR_ENUM: + case DBR_SHORT: +#if DBR_INT != DBR_SHORT + case DBR_INT: +#endif + *(short *)pdest = htons(*(short *)pvalue); + break; + + case DBR_FLOAT: + /* most compilers pass all floats as doubles */ + htonf(pvalue, pdest); + break; + + case DBR_STRING: + /* + * string size checked above + */ + strcpy(pdest,pvalue); + break; + + case DBR_DOUBLE: /* no cvrs for double yet */ + default: + return ECA_BADTYPE; + } + (char *) pdest += size_of_one; + (char *) pvalue += size_of_one; + } +#else + /* in line is a little faster */ + if(postcnt==sizeof(long)){ + *(long *)pdest = *(long *)pvalue; + } + else if(postcnt==sizeof(short)){ + *(short *)pdest = *(short *)pvalue; + } + else if(postcnt==sizeof(char)){ + *(char *)pdest = *(char *)pvalue; + } + else if(postcnt==sizeof(double)){ + *(double *)pdest = *(double *)pvalue; + } + else{ + memcpy(pdest,pvalue,postcnt); + } +#endif + + mptr->m_cmmd = htons(IOC_WRITE); + mptr->m_type = htons(type); + mptr->m_count = htons(count); + mptr->m_pciu = chix->paddr; + mptr->m_available = (long) chix; + + CAC_ADD_MSG(&iiu[chix->iocix]); + UNLOCK; + + return ECA_NORMAL; } @@ -1297,7 +1406,6 @@ unsigned mask; { register evid monix; void ca_request_event(); - int evsize; register int status; LOOSECHIXCHK(chix); @@ -1305,10 +1413,6 @@ unsigned mask; if(INVALID_DB_REQ(type)) return ECA_BADTYPE; - /* - * - * - */ if(count > chix->count && chix->type != TYPENOTCONN) return ECA_BADCOUNT; @@ -1359,7 +1463,6 @@ unsigned mask; # ifdef vxWorks { struct monops mon; - void ca_event_handler(); if(chix->iocix == LOCAL_IIU){ status = db_add_event( evuser, @@ -1425,34 +1528,42 @@ unlock_rtn: * * LOCK must be applied while in this routine */ -void ca_request_event(monix) -evid monix; +void +ca_request_event(monix) + evid monix; { - register chid chix = monix->chan; /* for SNDBEG */ + register chid chix = monix->chan; + unsigned size = sizeof(struct mon_info); + unsigned count; + register struct monops *mptr; - /* - * clip to the native count - */ - if(monix->count > chix->count || monix->count == 0) - monix->count = chix->count; + /* + * clip to the native count and set to the native count if they + * specify zero + */ + if (monix->count > chix->count || monix->count == 0){ + count = chix->count; + } + else{ + count = monix->count; + } - SNDBEG_NOLOCK(monops) + mptr = (struct monops *) CAC_ALLOC_MSG(&iiu[chix->iocix], size); - /* msg header */ - mptr->m_header.m_cmmd = htons(IOC_EVENT_ADD); - mptr->m_header.m_available = (long) monix; - mptr->m_header.m_postsize = htons(sizeof(struct mon_info)); - mptr->m_header.m_type = htons(monix->type); - mptr->m_header.m_count = htons(monix->count); - mptr->m_header.m_pciu = chix->paddr; + /* msg header */ + mptr->m_header.m_cmmd = htons(IOC_EVENT_ADD); + mptr->m_header.m_available = (long) monix; + mptr->m_header.m_type = htons(monix->type); + mptr->m_header.m_count = htons(count); + mptr->m_header.m_pciu = chix->paddr; - /* msg body */ - htonf(&monix->p_delta, &mptr->m_info.m_hval); - htonf(&monix->n_delta, &mptr->m_info.m_lval); - htonf(&monix->timeout, &mptr->m_info.m_toval); - mptr->m_info.m_mask = htons(monix->mask); + /* msg body */ + htonf(&monix->p_delta, &mptr->m_info.m_hval); + htonf(&monix->n_delta, &mptr->m_info.m_lval); + htonf(&monix->timeout, &mptr->m_info.m_toval); + mptr->m_info.m_mask = htons(monix->mask); - SNDEND_NOLOCK + CAC_ADD_MSG(&iiu[chix->iocix]); } @@ -1463,64 +1574,144 @@ evid monix; * */ #ifdef vxWorks -static void ca_event_handler(monix, paddr, hold, pfl) +static void +ca_event_handler(monix, paddr, hold, pfl) register evid monix; register struct db_addr *paddr; int hold; -caddr_t pfl; +void *pfl; { - register int status; - register int count = monix->count; - register chtype type = monix->type; - union db_access_val valbuf; - void *pval; - register unsigned size; + register int status; + register int count; + register chtype type = monix->type; + union db_access_val valbuf; + void *pval; + register unsigned size; + struct tmp_buff{ + NODE node; + unsigned size; + }; + struct tmp_buff *pbuf = NULL; - if(type == paddr->field_type){ - pval = paddr->pfield; - status = OK; - } - else{ - if(count == 1) - size = dbr_size[type]; - else - size = (count-1)*dbr_value_size[type]+dbr_size[type]; + /* + * clip to the native count + * and set to the native count if they specify zero + */ + if(monix->count > monix->chan->count || monix->count == 0){ + count = monix->chan->count; + } + else{ + count = monix->count; + } - if( size <= sizeof(valbuf) ) - pval = (void *) &valbuf; - else if( size <= event_buf_size ) - pval = event_buf; - else{ - if(free(event_buf)) - abort(); - pval = event_buf = (void *) malloc(size); - if(!pval) - abort(); - event_buf_size = size; - } - status = db_event_get_field(paddr, + if(type == paddr->field_type){ + pval = paddr->pfield; + status = OK; + } + else{ + if(count == 1) + size = dbr_size[type]; + else + size = (count-1)*dbr_value_size[type]+dbr_size[type]; + + if( size <= sizeof(valbuf) ){ + pval = (void *) &valbuf; + } + else{ + + /* + * find a preallocated block which fits + * (stored with lagest block first) + */ + LOCK; + pbuf = (struct tmp_buff *) + lcl_buff_list.node.next; + if(pbuf->size >= size){ + lstDelete( + &lcl_buff_list, + pbuf); + }else + pbuf = NULL; + UNLOCK; + + /* + * test again so malloc is not inside LOCKED + * section + */ + if(!pbuf){ + pbuf = (struct tmp_buff *) + malloc(sizeof(*pbuf)+size); + if(!pbuf) + abort(); + pbuf->size = size; + } + + pval = (void *) (pbuf+1); + } + } + + + status = db_get_field( paddr, type, pval, count, pfl); - } - /* - * @@@@@@ should tell um with the event handler ? - * or run an exception -@@@@@@@@@@@@@@@@ - */ - if(status == ERROR){ - SEVCHK(ECA_GETFAIL,"Event lost due to local get fail\n"); - } - else - (*monix->usr_func)( monix->usr_arg, + /* + * I would like to tell um with the event handler but this would + * not be upward compatible. so I run the exception handler. + */ + if(status == ERROR){ + if(ca_static->ca_exception_func){ + struct exception_handler_args args; + + args.usr = ca_static->ca_exception_arg; + args.chid = monix->chan; + args.type = type; + args.count = count; + args.addr = NULL; + args.stat = ECA_GETFAIL; + args.op = CA_OP_GET; + args.ctx = "Event lost due to local get fail\n"; + + (*ca_static->ca_exception_func)(args); + } + } + else + (*monix->usr_func)( + monix->usr_arg, monix->chan, type, count, pval); - return; + /* + * + * insert the buffer back into the que in size order if + * one was used. + */ + if(pbuf){ + struct tmp_buff *ptbuf; + LOCK; + for( ptbuf = (struct tmp_buff *) lcl_buff_list.node.next; + ptbuf; + ptbuf = (struct tmp_buff *) pbuf->node.next){ + + if(ptbuf->size <= pbuf->size){ + break; + } + } + if(ptbuf) + ptbuf = (struct tmp_buff *) ptbuf->node.previous; + + lstInsert( + &lcl_buff_list, + ptbuf, + pbuf); + UNLOCK; + } + + return; } #endif @@ -1543,74 +1734,73 @@ caddr_t pfl; */ ca_clear_event #ifdef VAXC -(register evid monix) +(register evid monix) #else (monix) -register evid monix; + register evid monix; #endif { - register chid chix = monix->chan; /* for SNDBEG */ - - LOOSECHIXCHK(chix); + register chid chix = monix->chan; + register struct extmsg *mptr; - /* disable any further events from this event block */ - monix->usr_func = NULL; + LOOSECHIXCHK(chix); -# ifdef vxWorks - if(chix->iocix == LOCAL_IIU){ - register int status; + /* disable any further events from this event block */ + monix->usr_func = NULL; - /* - dont allow two threads to delete the same moniitor at once - */ - LOCK; - status = lstFind(&chix->eventq, monix); - if(status != ERROR){ - lstDelete(&chix->eventq, monix); - status = db_cancel_event(monix+1); - } - UNLOCK; - if(status == ERROR) - return ECA_BADMONID; +#ifdef vxWorks + if (chix->iocix == LOCAL_IIU) { + register int status; - lstAdd(&dbfree_ev_list, monix); + /* + * dont allow two threads to delete the same moniitor at once + */ + LOCK; + status = lstFind(&chix->eventq, monix); + if (status != ERROR) { + lstDelete(&chix->eventq, monix); + status = db_cancel_event(monix + 1); + } + UNLOCK; + if (status == ERROR) + return ECA_BADMONID; - return ECA_NORMAL; - } -# endif + lstAdd(&dbfree_ev_list, monix); - /* - dont send the message if the conn is down - (just delete from the queue and return) + return ECA_NORMAL; + } +#endif - check for conn down while locked to avoid a race - */ - LOCK; - if(!iiu[chix->iocix].conn_up || chix->iocix == BROADCAST_IIU) - lstDelete(&monix->chan->eventq, monix); - UNLOCK; + /* + * dont send the message if the conn is down (just delete from the + * queue and return) + * + * check for conn down while locked to avoid a race + */ + LOCK; + if (!iiu[chix->iocix].conn_up || chix->iocix == BROADCAST_IIU){ + lstDelete(&monix->chan->eventq, monix); + }else{ - if(chix->iocix == BROADCAST_IIU) - return ECA_NORMAL; - if(!iiu[chix->iocix].conn_up) - return ECA_NORMAL; + mptr = CAC_ALLOC_MSG(&iiu[chix->iocix], 0); - SNDBEG(extmsg) + /* msg header */ + mptr->m_cmmd = htons(IOC_EVENT_CANCEL); + mptr->m_available = (long) monix; + mptr->m_type = chix->type; + mptr->m_count = chix->count; + mptr->m_pciu = chix->paddr; + + /* + * NOTE: I free the monitor block only + * after confirmation from IOC + */ + CAC_ADD_MSG(&iiu[chix->iocix]); + } + UNLOCK; - /* msg header */ - mptr->m_cmmd = htons(IOC_EVENT_CANCEL); - mptr->m_available = (long) monix; - mptr->m_postsize = 0; - mptr->m_type = chix->type; - mptr->m_count = chix->count; - mptr->m_pciu = chix->paddr; - - /* NOTE: I free the monitor block only after confirmation from IOC */ - - SNDEND - return ECA_NORMAL; + return ECA_NORMAL; } - /* * @@ -1629,109 +1819,109 @@ register evid monix; */ ca_clear_channel #ifdef VAXC -(register chid chix) +(register chid chix) #else (chix) -register chid chix; + register chid chix; #endif { - register evid monix; - struct ioc_in_use *piiu = &iiu[chix->iocix]; + register evid monix; + struct ioc_in_use *piiu = &iiu[chix->iocix]; + register struct extmsg *mptr; - LOOSECHIXCHK(chix); + LOOSECHIXCHK(chix); - /* disable their further use of deallocated channel */ - chix->type = TYPENOTINUSE; + /* disable their further use of deallocated channel */ + chix->type = TYPENOTINUSE; - /* the while is only so I can break to the lock exit */ - LOCK; - while(TRUE){ - /* disable any further events from this channel */ - for( monix = (evid) chix->eventq.node.next; - monix; - monix = (evid) monix->node.next) - monix->usr_func = NULL; - /* disable any further get callbacks from this channel */ - for( monix = (evid) pend_read_list.node.next; - monix; - monix = (evid) monix->node.next) - if(monix->chan == chix) - monix->usr_func = NULL; - -# ifdef vxWorks - if(chix->iocix == LOCAL_IIU){ - int status; + /* the while is only so I can break to the lock exit */ + LOCK; + while (TRUE) { + /* disable any further events from this channel */ + for (monix = (evid) chix->eventq.node.next; + monix; + monix = (evid) monix->node.next) + monix->usr_func = NULL; + /* disable any further get callbacks from this channel */ + for (monix = (evid) pend_read_list.node.next; + monix; + monix = (evid) monix->node.next) + if (monix->chan == chix) + monix->usr_func = NULL; - /* - clear out the events for this channel - */ - while(monix = (evid) lstGet(&chix->eventq)){ - status = db_cancel_event(monix+1); - if(status==ERROR) - abort(); - lstAdd(&dbfree_ev_list, monix); - } +#ifdef vxWorks + if (chix->iocix == LOCAL_IIU) { + int status; - /* - clear out this channel - */ - lstDelete(&local_chidlist, chix); - if(free(chix)<0) - abort(); + /* + * clear out the events for this channel + */ + while (monix = (evid) lstGet(&chix->eventq)) { + status = db_cancel_event(monix + 1); + if (status == ERROR) + abort(); + lstAdd(&dbfree_ev_list, monix); + } - break; /* to unlock exit */ - } -# endif + /* + * clear out this channel + */ + lstDelete(&local_chidlist, chix); + if (free((char *) chix) < 0) + abort(); - /* - dont send the message if the conn is down - (just delete from the queue and return) + break; /* to unlock exit */ + } +#endif - check for conn down while locked to avoid a race - */ - if(!piiu->conn_up || chix->iocix == BROADCAST_IIU){ - lstConcat(&free_event_list, &chix->eventq); - lstDelete(&piiu->chidlist, chix); - if(free(chix)<0) - abort(); - if(chix->iocix != BROADCAST_IIU && !piiu->chidlist.count) - close_ioc(piiu); - } + /* + * dont send the message if the conn is down (just delete + * from the queue and return) + * + * check for conn down while locked to avoid a race + */ + if (!piiu->conn_up || chix->iocix == BROADCAST_IIU) { + lstConcat(&free_event_list, &chix->eventq); + lstDelete(&piiu->chidlist, chix); + if (free((char *) chix) < 0) + abort(); + if (chix->iocix != BROADCAST_IIU && !piiu->chidlist.count) + close_ioc(piiu); + } + if (chix->iocix == BROADCAST_IIU) + break; /* to unlock exit */ + if (!iiu[chix->iocix].conn_up) + break; /* to unlock exit */ - if(chix->iocix == BROADCAST_IIU) - break; /* to unlock exit */ - if(!iiu[chix->iocix].conn_up) - break; /* to unlock exit */ + /* + * clear events and all other resources for this chid on the + * IOC + */ + mptr = CAC_ALLOC_MSG(&iiu[chix->iocix], 0); - /* - clear events and all other resources for this chid on the IOC - */ - SNDBEG_NOLOCK(extmsg) + /* msg header */ + mptr->m_cmmd = htons(IOC_CLEAR_CHANNEL); + mptr->m_available = (int) chix; + mptr->m_type = 0; + mptr->m_count = 0; + mptr->m_pciu = chix->paddr; - /* msg header */ - mptr->m_cmmd = htons(IOC_CLEAR_CHANNEL); - mptr->m_available = (int) chix; - mptr->m_type = 0; - mptr->m_count = 0; - mptr->m_pciu = chix->paddr; - mptr->m_postsize = 0; + /* + * NOTE: I free the chid and monitor blocks only after + * confirmation from IOC + */ - /* - NOTE: I free the chid and monitor blocks only after - confirmation from IOC - */ + CAC_ADD_MSG(&iiu[chix->iocix]); - SNDEND_NOLOCK - - break; /* to unlock exit */ - } + break; /* to unlock exit */ + } /* * message about unexecuted code from SUN's cheaper cc is a compiler * bug */ - UNLOCK; + UNLOCK; - return ECA_NORMAL; + return ECA_NORMAL; } @@ -1765,122 +1955,140 @@ ca_real timeout; int early; #endif { - void send_msg(); - time_t beg_time; - time_t clock(); + time_t beg_time; -# ifdef vxWorks - static int sysfreq; +#ifdef vxWorks + static int sysfreq; - if(!sysfreq) - sysfreq = SYSFREQ; -# endif - - INITCHK; - - if(post_msg_active) - return ECA_EVDISALLOW; - - - /* Flush the send buffers */ - LOCK; - send_msg(); - UNLOCK; - - if(pndrecvcnt<1) - if(early) - return ECA_NORMAL; - - if(timeoutcur_read_seq++; - SND_BEG_NOLOCK(extmsg, piiu) - *mptr = nullmsg; - mptr->m_cmmd = htons(IOC_READ_SYNC); - SNDEND_NOLOCK + beg_time = time(NULL); + + while(TRUE){ +#ifdef UNIX + { + struct timeval itimeout; + + itimeout.tv_usec = SYSFREQ * DELAYVAL; + itimeout.tv_sec = 0; + LOCK; + recv_msg_select(&itimeout); + UNLOCK; + } +#endif +#ifdef vxWorks + { + int dummy; + unsigned int clockticks = DELAYVAL * sysfreq; + vrtxPend(&io_done_flag,clockticks,&dummy); + } +#endif +#ifdef VMS + { + int status; + unsigned int systim[2]={-SYSFREQ*DELAYVAL,~0}; + + status = sys$setimr( + io_done_flag, + systim, + NULL, + MYTIMERID, + NULL); + if(status != SS$_NORMAL) + lib$signal(status); + status = sys$waitfr(io_done_flag); + if(status != SS$_NORMAL) + lib$signal(status); + } +#endif + if(pndrecvcnt<1) + if(early) + return ECA_NORMAL; + + LOCK; + manage_conn(TRUE); + UNLOCK; + + if(timeout != 0.0){ + if(timeout < time(NULL)-beg_time){ + struct ioc_in_use *piiu; + + LOCK; + manage_conn(FALSE); + + /* + * set pending IO count back to zero and + * send a sync to each IOC and back. dont + * count reads until we recv the sync + */ + for( piiu = &iiu[BROADCAST_IIU+1]; + piiu<&iiu[nxtiiu]; + piiu++){ + + if(piiu->conn_up){ + struct extmsg *mptr; + + piiu->cur_read_seq++; + mptr = CAC_ALLOC_MSG(piiu, 0); + *mptr = nullmsg; + mptr->m_cmmd = + htons(IOC_READ_SYNC); + CAC_ADD_MSG(piiu); + } + } + pndrecvcnt = 0; + UNLOCK; + + return ECA_TIMEOUT; + } + } } - pndrecvcnt = 0; - UNLOCK; - - return ECA_TIMEOUT; - } - } - } @@ -1900,13 +2108,12 @@ ca_flush_io () #endif { - void send_msg(); INITCHK; /* Flush the send buffers */ LOCK; - send_msg(); + cac_send_msg(); UNLOCK; return ECA_NORMAL; @@ -1919,7 +2126,7 @@ ca_flush_io * * */ -ca_signal(ca_status,message) +void ca_signal(ca_status,message) int ca_status; char *message; { @@ -1971,9 +2178,6 @@ char *message; ti(VXTHISTASKID); tt(VXTHISTASKID); # endif -/*** - abort(ca_status); - ***/ abort(); } @@ -1991,55 +2195,57 @@ char *message; * CA_BUSY_MSG() * */ +void ca_busy_message(piiu) -register struct ioc_in_use *piiu; + register struct ioc_in_use *piiu; { - void send_msg(); - - LOCK; - SND_BEG_NOLOCK(extmsg, piiu) - *mptr = nullmsg; - mptr->m_cmmd = htons(IOC_EVENTS_OFF); - SNDEND_NOLOCK - send_msg(); - UNLOCK; + struct extmsg *mptr; + LOCK; + mptr = CAC_ALLOC_MSG(piiu, 0); + *mptr = nullmsg; + mptr->m_cmmd = htons(IOC_EVENTS_OFF); + CAC_ADD_MSG(piiu); + cac_send_msg(); + UNLOCK; } /* - * CA_READY_MSG() - * + * CA_READY_MSG() + * */ +void ca_ready_message(piiu) -register struct ioc_in_use *piiu; + register struct ioc_in_use *piiu; { - void send_msg(); + struct extmsg *mptr; - LOCK; - SND_BEG_NOLOCK(extmsg, piiu) - *mptr = nullmsg; - mptr->m_cmmd = htons(IOC_EVENTS_ON); - SNDEND_NOLOCK - send_msg(); - UNLOCK; + LOCK; + mptr = CAC_ALLOC_MSG(piiu, 0); + *mptr = nullmsg; + mptr->m_cmmd = htons(IOC_EVENTS_ON); + CAC_ADD_MSG(piiu); + cac_send_msg(); + UNLOCK; } /* - * NOOP_MSG - * (lock must be on) - * + * NOOP_MSG (lock must be on) + * */ void noop_msg(piiu) -register struct ioc_in_use *piiu; + register struct ioc_in_use *piiu; { - SND_BEG_NOLOCK(extmsg, piiu) - *mptr = nullmsg; - mptr->m_cmmd = htons(IOC_NOOP); - SNDEND_NOLOCK + struct extmsg *mptr; + + mptr = CAC_ALLOC_MSG(piiu, 0); + *mptr = nullmsg; + mptr->m_cmmd = htons(IOC_NOOP); + CAC_ADD_MSG(piiu); } @@ -2066,6 +2272,7 @@ struct exception_handler_args args; /* + * CA_ADD_FD_REGISTRATION * * call their function with their argument whenever a new fd is added or removed * (for a manager of the select system call under UNIX) @@ -2084,14 +2291,12 @@ void *arg; /* + * CA_DEFUNCT * - * call their function with their argument whenever a new fd is added or removed - * (for a manager of the select system call under UNIX) + * what is called by vacated entries in the VMS share image jump table * */ -ca_defunct(func, arg) -void (*func)(); -void *arg; +ca_defunct() { #ifdef VMS SEVCHK(ECA_DEFUNCT, "you must have a VMS share image mismatch\n"); diff --git a/src/ca/acctst.c b/src/ca/acctst.c index 3838b9bd7..9fcc65f13 100644 --- a/src/ca/acctst.c +++ b/src/ca/acctst.c @@ -13,16 +13,15 @@ #include #include -/* -#define CA_TEST_CHNL "AI_T2000" -*/ #define CA_TEST_CHNL "ca:ai_2000" -#define CA_TEST_CHNL4 "ca:ai_2000" +#define CA_TEST_CHNL4 "ca:bo_000" -#define EVENT_ROUTINE null_event /* #define EVENT_ROUTINE ca_test_event +#define CONN_ROUTINE NULL */ +#define EVENT_ROUTINE null_event +#define CONN_ROUTINE conn #define NUM 1 @@ -50,6 +49,7 @@ main() void ca_test_event(); void null_event(); struct dbr_gr_float *ptr; + struct dbr_gr_float *pgrfloat; float delay = .003; long status; @@ -60,6 +60,7 @@ main() char string[41]; float value; float *pfloat; + double *pdouble; struct dbr_ctrl_float *pctrl; char pstring[NUM][MAX_STRING_SIZE]; void write_event(); @@ -92,7 +93,7 @@ main() 0, &chix4, NULL, - conn, + CONN_ROUTINE, NULL),NULL); SEVCHK(ca_build_and_connect( CA_TEST_CHNL, @@ -100,7 +101,7 @@ main() 0, &chix2, NULL, - conn, + CONN_ROUTINE, NULL),NULL); SEVCHK(ca_build_and_connect( CA_TEST_CHNL, @@ -108,7 +109,7 @@ main() 0, &chix1, NULL, - conn, + CONN_ROUTINE, NULL),NULL); status = ca_pend_io(10.0); SEVCHK(status,NULL); @@ -137,7 +138,7 @@ main() 0, &chix4, NULL, - conn, + CONN_ROUTINE, NULL),NULL); SEVCHK(ca_build_and_connect( CA_TEST_CHNL, @@ -145,7 +146,7 @@ main() 0, &chix2, NULL, - conn, + CONN_ROUTINE, NULL),NULL); SEVCHK(ca_build_and_connect( CA_TEST_CHNL, @@ -153,10 +154,10 @@ main() 0, &chix1, NULL, - conn, + CONN_ROUTINE, NULL),NULL); - status = ca_pend_io(1.0); + status = ca_pend_io(10.0); SEVCHK(status,NULL); if(INVALID_DB_REQ(chix1->type)) @@ -190,6 +191,8 @@ main() status = ca_add_event(DBR_FLOAT, chix4, EVENT_ROUTINE, 0xaaaaaaaa, &monix); SEVCHK(status,NULL); SEVCHK(ca_clear_event(monix),NULL); + status = ca_add_event(DBR_FLOAT, chix4, EVENT_ROUTINE, 0xaaaaaaaa, &monix); + SEVCHK(status,NULL); } if(VALID_DB_REQ(chix4->type)){ status = ca_add_event(DBR_FLOAT, chix4, EVENT_ROUTINE, 0xaaaaaaaa, &monix); @@ -206,6 +209,8 @@ main() pfloat = (float *) malloc(sizeof(float)*NUM); + pdouble = (double *) malloc(sizeof(double)*NUM); + pgrfloat = (struct dbr_gr_float *) malloc(sizeof(*pgrfloat)*NUM); if(VALID_DB_REQ(chix1->type)) @@ -215,6 +220,8 @@ main() sprintf(&pstring[j][0],"%d",j+100); SEVCHK(ca_array_put(DBR_STRING,NUM,chix1,pstring),NULL) SEVCHK(ca_array_get(DBR_FLOAT,NUM,chix1,pfloat),NULL) + SEVCHK(ca_array_get(DBR_DOUBLE,NUM,chix1,pdouble),NULL) + SEVCHK(ca_array_get(DBR_GR_FLOAT,NUM,chix1,pgrfloat),NULL) } else abort(); @@ -224,18 +231,22 @@ main() # ifdef VMS lib$show_timer(); # endif - for(i=0;i100){ - printf("100 occured\n"); + if(i++>1000){ + printf("1000 occured\n"); i = 0; } } diff --git a/src/ca/conn.c b/src/ca/conn.c index 7d554bb11..e602e3b0e 100644 --- a/src/ca/conn.c +++ b/src/ca/conn.c @@ -9,17 +9,15 @@ /* */ /* History */ /* ------- */ -/* */ -/* Date Programmer Comments */ -/* ---- ---------- -------- */ -/* 6/89 Jeff Hill Init Release */ +/* .00 06xx89 joh Init Release */ +/* .01 060591 joh delinting */ /* */ /*_begin */ /************************************************************************/ /* */ /* Title: IOC connection automation */ /* File: atcs:[ca]conn.c */ -/* Environment: VMS, UNIX, VRTX */ +/* Environment: VMS, UNIX, vxWorks */ /* Equipment: VAX, SUN, VME */ /* */ /* */ @@ -36,10 +34,11 @@ #include #include + /* * - * CHID_RETRY + * MANAGE_CONN * * retry disconnected channels * @@ -47,29 +46,45 @@ * NOTES: * Lock must be applied while in this routine */ -chid_retry(silent) +void manage_conn(silent) char silent; { register chid chix; register unsigned int retry_cnt = 0; + register unsigned int keepalive_cnt = 0; unsigned int retry_cnt_no_handler = 0; - char string[100]; + char string[128]; + ca_time current; int i; - int search_type; - /* - * CASTTMO+pndrecvcnt*LKUPTMO)/DELAYVAL + 1 - */ -#define CASTTMO 0.150 /* 150 mS */ -#define LKUPTMO 0.015 /* 15 mS */ + current = time(NULL); for(i=0; i< nxtiiu; i++){ - if(i != BROADCAST_IIU && iiu[i].conn_up) + int search_type; + + if(iiu[i].next_retry > current) + continue; + + /* + * periodic keepalive on unused channels + */ + if(i != BROADCAST_IIU && iiu[i].conn_up){ + + /* + * reset of delay to the next keepalive + * occurs when the message is sent + */ + noop_msg(&iiu[i]); + keepalive_cnt++; continue; + } if(iiu[i].nconn_tries++ > MAXCONNTRIES) continue; + iiu[i].retry_delay += iiu[i].retry_delay; + iiu[i].next_retry = current + iiu[i].retry_delay; + search_type = (i==BROADCAST_IIU? DONTREPLY: DOREPLY); chix = (chid) &iiu[i].chidlist; @@ -80,14 +95,13 @@ char silent; retry_cnt++; if(!(silent || chix->connection_func)){ - ca_signal(ECA_CHIDNOTFND, chix+1); + ca_signal(ECA_CHIDNOTFND, chix+1); retry_cnt_no_handler++; } } } if(retry_cnt){ - send_msg(); printf(" "); #ifdef UNIX fflush(stdout); @@ -99,7 +113,10 @@ char silent; } } - return ECA_NORMAL; + if(keepalive_cnt|retry_cnt){ + cac_send_msg(); + } + } @@ -115,49 +132,96 @@ char silent; * */ void -mark_server_available(net_addr) -struct in_addr net_addr; +mark_server_available(pnet_addr) +struct in_addr *pnet_addr; { - int i; - void noop_msg(); + unsigned port; + int i; + + /* + * if timers have expired take care of them + * before they are reset + */ + manage_conn(TRUE); + +#ifdef DEBUG + printf("<%s> ",host_from_addr(pnet_addr)); +#ifdef UNIX + fflush(stdout); +#endif +#endif for(i=0;is_addr == iiu[i].sock_addr.sin_addr.s_addr)){ - /* - * reset the retry count out - * - */ - iiu[i].nconn_tries = 0; - - /* - * Check if the conn is down but TCP - * has not informed me by sending a NULL msg - */ if(iiu[i].conn_up){ + /* + * Check if the conn is down but TCP + * has not informed me by sending a NULL msg + */ noop_msg(&iiu[i]); - send_msg(); + cac_send_msg(); } + else{ + /* + * reset the delay to the next retry + */ + iiu[i].next_retry = CA_CURRENT_TIME; + iiu[i].nconn_tries = 0; + iiu[i].retry_delay = 1; + manage_conn(TRUE); + } return; } /* - * Not on a known IOC so try a directed UDP + * never connected to this IOC before * + * We end up here when the client starts before the server + * + * It would be best if this used a directed UDP + * reply rather than a broadcast */ -/* -@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - This connects when the client starts before the server - 1) uses a broadcast- should use a directed UDP messaage - 2) many clients with nonexsistent channels could - cause a flood here - + /* + * reset the retry cnt to 3 + */ + iiu[BROADCAST_IIU].nconn_tries = MAXCONNTRIES-3; + /* + * This part is very important since many machines + * could have channels in a disconnected state which + * dont exist anywhere on the network. This insures + * that we dont have many CA clients synchronously + * flooding the network with broadcasts. + * + * I fetch the local port number and use the low order bits + * as a pseudo random delay to prevent every one + * from replying at once. + */ + { + struct sockaddr_in saddr; + unsigned saddr_length = sizeof(saddr); + int status; + status = getsockname( + iiu[BROADCAST_IIU].sock_chan, + &saddr, + &saddr_length); + if(status<0) + abort(); + port = saddr.sin_port; + } + + iiu[BROADCAST_IIU].retry_delay = (port&0xf) + 1; + iiu[BROADCAST_IIU].next_retry = time(NULL) + iiu[BROADCAST_IIU].retry_delay; +#ifdef DEBUG + printf(" ", + iiu[BROADCAST_IIU].retry_delay); +#ifdef UNIX + fflush(stdout); +#endif +#endif - iiu[BROADCAST_IIU].nconn_tries = MAXCONNTRIES-1; -@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -*/ } diff --git a/src/ca/flow_control.c b/src/ca/flow_control.c index feecd37a3..0ce015d55 100644 --- a/src/ca/flow_control.c +++ b/src/ca/flow_control.c @@ -9,10 +9,8 @@ /* */ /* History */ /* ------- */ -/* */ -/* Date Programmer Comments */ -/* ---- ---------- -------- */ -/* 6/89 Jeff Hill Init Release */ +/* 06xx89 joh First Release */ +/* 060591 joh delinting */ /* */ /*_begin */ /************************************************************************/ @@ -47,38 +45,46 @@ #include #include - + /* -Keep track of how many times messages have come with out a break in between -*/ + * FLOW CONTROL + * + * Keep track of how many times messages have + * come with out a break in between and + * suppress monitors if we are behind + * (an update is sent when we catch up) + */ +void flow_control(piiu) -struct ioc_in_use *piiu; -{ - unsigned nbytes; - register int status; - register int busy = piiu->client_busy; + struct ioc_in_use *piiu; +{ + unsigned nbytes; + register int status; + register int busy = piiu->client_busy; - status = socket_ioctl( piiu->sock_chan, - FIONREAD, - &nbytes); - if(status < 0) - return ERROR; + status = socket_ioctl(piiu->sock_chan, + FIONREAD, + &nbytes); + if (status < 0) { + close_ioc(piiu); + return; + } - if(nbytes){ - piiu->contiguous_msg_count++; - if(!busy) - if(piiu->contiguous_msg_count > MAX_CONTIGUOUS_MSG_COUNT){ - piiu->client_busy = TRUE; - ca_busy_message(piiu); - } - } - else{ - piiu->contiguous_msg_count=0; - if(busy){ - ca_ready_message(piiu); - piiu->client_busy = FALSE; - } - } + if (nbytes) { + piiu->contiguous_msg_count++; + if (!busy) + if (piiu->contiguous_msg_count > + MAX_CONTIGUOUS_MSG_COUNT) { + piiu->client_busy = TRUE; + ca_busy_message(piiu); + } + } else { + piiu->contiguous_msg_count = 0; + if (busy) { + ca_ready_message(piiu); + piiu->client_busy = FALSE; + } + } - return; + return; } diff --git a/src/ca/iocinf.c b/src/ca/iocinf.c index fbe107d77..f3b163443 100644 --- a/src/ca/iocinf.c +++ b/src/ca/iocinf.c @@ -9,15 +9,20 @@ /* */ /* History */ /* ------- */ -/* 8/87 joh Init Release */ +/* xx0887 joh Init Release */ /* 021291 joh Fixed vxWorks task name creation bug */ +/* 032291 joh source cleanup */ +/* 041591 joh added channel exsits routine */ +/* 060591 joh delinting */ +/* 060691 joh removed 4 byte count from the beginning of */ +/* each message */ /* */ /*_begin */ /************************************************************************/ /* */ /* Title: IOC socket interface module */ -/* File: atcs:[ca]iocinf.c */ -/* Environment: VMS. UNIX, VRTX */ +/* File: /.../ca/iocinf.c */ +/* Environment: VMS. UNIX, vxWorks */ /* Equipment: VAX, SUN, VME */ /* */ /* */ @@ -29,11 +34,13 @@ /* */ /* Special comments */ /* ------- -------- */ +/* NOTE: Wallangong select does not return early if IO is */ +/* present prior to the timeout expiration. */ /* */ /************************************************************************/ /*_end */ - + /* Allocate storage for global variables in this module */ #define CA_GLBLSOURCE #ifdef VMS @@ -61,6 +68,13 @@ #include #include +static struct timeval notimeout = {0,0}; + +void close_ioc(); +void tcp_recv_msg(); +void udp_recv_msg(); + + /* * used to be that some TCP/IPs did not include this */ @@ -99,365 +113,422 @@ typedef struct fd_set { } #endif - -static struct timeval notimeout = {0,0}; - -void close_ioc(); +#ifdef VMS +void vms_recv_msg_ast(); +#endif /* - LOCK should be on while in this routine -*/ - alloc_ioc(net_addr, net_proto, iocix) -struct in_addr net_addr; + * ALLOC_IOC() + * + * LOCK should be on while in this routine + */ +alloc_ioc(pnet_addr, net_proto, iocix) +struct in_addr *pnet_addr; int net_proto; unsigned short *iocix; { - int i; - int status; + int i; + int status; - /**********************************************************************/ - /* IOC allready allocated ? */ - /**********************************************************************/ - for(i=0;is_addr == iiu[i].sock_addr.sin_addr.s_addr) + && (net_proto == iiu[i].sock_proto)){ - if(!iiu[i].conn_up){ - /* an old connection is resumed */ - status = create_net_chan(&iiu[i]); - if(status != ECA_NORMAL) - return status; - ca_signal(ECA_NEWCONN,host_from_addr(net_addr)); - } + if(!iiu[i].conn_up){ + /* an old connection is resumed */ + status = create_net_chan(&iiu[i]); + if(status != ECA_NORMAL) + return status; + ca_signal(ECA_NEWCONN,host_from_addr(pnet_addr)); + } - *iocix = i; - return ECA_NORMAL; - } + *iocix = i; + return ECA_NORMAL; + } - /* is there an IOC In Use block available to allocate */ - if(nxtiiu>=MAXIIU) - return ECA_MAXIOC; + /* is there an IOC In Use block available to allocate */ + if(nxtiiu>=MAXIIU) + return ECA_MAXIOC; - /* set network address block */ - iiu[nxtiiu].sock_addr.sin_addr = net_addr; - iiu[nxtiiu].sock_proto = net_proto; - status = create_net_chan(&iiu[nxtiiu]); - if(status != ECA_NORMAL) - return status; + /* set network address block */ + iiu[nxtiiu].sock_addr.sin_addr = *pnet_addr; + iiu[nxtiiu].sock_proto = net_proto; + status = create_net_chan(&iiu[nxtiiu]); + if(status != ECA_NORMAL) + return status; - *iocix = nxtiiu++; + *iocix = nxtiiu++; - return ECA_NORMAL; + return ECA_NORMAL; } + +/* + * client_channel_exists() + * (usually will find it in the first piiu) + * + * LOCK should be on while in this routine + * + * iocix field in the chid block not used here because + * I dont trust the chid ptr yet. + */ +STATUS +client_channel_exists(chan) + chid chan; +{ + register struct ioc_in_use *piiu; + register struct ioc_in_use *pnext_iiu = &iiu[nxtiiu]; + STATUS status; + + for (piiu = iiu; piiu < pnext_iiu; piiu++) { + /* + * lstFind returns the node number or ERROR + */ + status = lstFind(&piiu->chidlist, chan); + if (status != ERROR) { + return TRUE; + } + } + return FALSE; +} -/**********************************************************************/ -/* allocate and initialize an IOC info block for unallocated IOC */ -/**********************************************************************/ /* - LOCK should be on while in this routine -*/ + * CREATE_NET_CHANNEL() + * + * allocate and initialize an IOC info block for unallocated IOC + * + * LOCK should be on while in this routine + */ create_net_chan(piiu) struct ioc_in_use *piiu; { - int status; - int sock; - int true = TRUE; - struct sockaddr_in saddr; - int i; + int status; + int sock; + int true = TRUE; + struct sockaddr_in saddr; + int i; - struct sockaddr_in *local_addr(); + struct sockaddr_in *local_addr(); - /* set socket domain */ - piiu->sock_addr.sin_family = AF_INET; + /* set socket domain */ + piiu->sock_addr.sin_family = AF_INET; - /* set the port */ - piiu->sock_addr.sin_port = htons(CA_SERVER_PORT); + /* set the port */ + piiu->sock_addr.sin_port = htons(CA_SERVER_PORT); - switch(piiu->sock_proto) - { - case IPPROTO_TCP: + /* + * reset the delay to the next retry or keepalive + */ + piiu->next_retry = CA_CURRENT_TIME; + piiu->nconn_tries = 0; + piiu->retry_delay = 1; - /* allocate a socket */ - sock = socket( AF_INET, /* domain */ - SOCK_STREAM, /* type */ - 0); /* deflt proto */ - if(sock == ERROR) - return ECA_SOCK; + switch(piiu->sock_proto) + { + case IPPROTO_TCP: - piiu->sock_chan = sock; + /* allocate a socket */ + sock = socket( AF_INET, /* domain */ + SOCK_STREAM, /* type */ + 0); /* deflt proto */ + if(sock == ERROR) + return ECA_SOCK; - /* - see TCP(4P) this seems to make unsollicited single - events much faster. I take care of queue up as load - increases. - */ - status = setsockopt( sock, + piiu->sock_chan = sock; + + /* + * see TCP(4P) this seems to make unsollicited single events + * much faster. I take care of queue up as load increases. + */ + status = setsockopt( + sock, IPPROTO_TCP, TCP_NODELAY, &true, sizeof true); - if(status < 0){ - socket_close(sock); - return ECA_ALLOCMEM; - } + if(status < 0){ + status = socket_close(sock); + if(status<0){ + SEVCHK(ECA_INTERNAL,NULL); + } + return ECA_SOCK; + } #ifdef KEEPALIVE - /* - This should cause the connection to be checked periodically - and an error to be returned if it is lost. - - In practice it is not much use since the conn is checked very - infrequently. - */ - status = setsockopt( sock, + /* + * This should cause the connection to be checked + * periodically and an error to be returned if it is lost? + * + * In practice the conn is checked very infrequently. + */ + status = setsockopt( + sock, SOL_SOCKET, SO_KEEPALIVE, &true, sizeof true); - if(status < 0){ - socket_close(sock); - return ECA_ALLOCMEM; - } + if(status < 0){ + status = socket_close(sock); + if(status<0){ + SEVCHK(ECA_INTERNAL,NULL); + } + return ECA_SOCK; + } #endif #ifdef JUNKYARD -{ -struct linger linger; -int linger_size = sizeof linger; - status = getsockopt( sock, + { + struct linger linger; + int linger_size = sizeof linger; + status = getsockopt( + sock, SOL_SOCKET, SO_LINGER, &linger, &linger_size); - if(status < 0){ - abort(); - } -printf("linger was on:%d linger:%d\n", linger.l_onoff, linger.l_linger); -} + if(status < 0){ + abort(); + } + printf( "linger was on:%d linger:%d\n", + linger.l_onoff, + linger.l_linger); + } #endif - /* set TCP buffer sizes only if BSD 4.3 sockets */ - /* temporarily turned off */ -# ifdef JUNKYARD + /* set TCP buffer sizes only if BSD 4.3 sockets */ + /* temporarily turned off */ +#ifdef JUNKYARD - i = (MAX_MSG_SIZE+sizeof(int)) * 2; - status = setsockopt( sock, + i = (MAX_MSG_SIZE+sizeof(int)) * 2; + status = setsockopt( + sock, SOL_SOCKET, SO_SNDBUF, &i, sizeof(i)); - if(status < 0){ - socket_close(sock); - return ECA_ALLOCMEM; - } - status = setsockopt( sock, + if(status < 0){ + status = socket_close(sock); + if(status<0){ + SEVCHK(ECA_INTERNAL,NULL); + } + return ECA_SOCK; + } + status = setsockopt( + sock, SOL_SOCKET, SO_RCVBUF, &i, sizeof(i)); - if(status < 0){ - socket_close(sock); - return ECA_ALLOCMEM; - } -# endif + if(status < 0){ + status = socket_close(sock); + if(status<0){ + SEVCHK(ECA_INTERNAL,NULL); + } + return ECA_SOCK; + } +#endif - /* connect */ - status = connect( - sock, - &piiu->sock_addr, - sizeof(piiu->sock_addr)); - if(status < 0){ - printf("no conn errno %d\n", MYERRNO); - socket_close(sock); - return ECA_CONN; - } + /* connect */ + status = connect( + sock, + &piiu->sock_addr, + sizeof(piiu->sock_addr)); + if(status < 0){ + printf("no conn errno %d\n", MYERRNO); + status = socket_close(sock); + if(status<0){ + SEVCHK(ECA_INTERNAL,NULL); + } + return ECA_CONN; + } - piiu->max_msg = MAX_TCP; + piiu->max_msg = MAX_TCP; - /* - place the broadcast addr/port in the stream so the - ioc will know where this is coming from. - */ - i = sizeof(saddr); - status = getsockname( iiu[BROADCAST_IIU].sock_chan, + /* + * place the broadcast addr/port in the stream so the ioc + * will know where this is coming from. + */ + + i = sizeof(saddr); + status = getsockname( + iiu[BROADCAST_IIU].sock_chan, &saddr, &i); - if(status == ERROR){ - printf("alloc_ioc: cant get my name %d\n",MYERRNO); - abort(); - } - saddr.sin_addr.s_addr = - (local_addr(iiu[BROADCAST_IIU].sock_chan))->sin_addr.s_addr; - status = send( piiu->sock_chan, - &saddr, - sizeof(saddr), - 0); + if(status == ERROR){ + printf("alloc_ioc: cant get my name %d\n",MYERRNO); + abort(); + } - /* Set non blocking IO for UNIX to prevent dead locks */ -# ifdef UNIX - status = socket_ioctl( piiu->sock_chan, + saddr.sin_addr.s_addr = + (local_addr(iiu[BROADCAST_IIU].sock_chan))->sin_addr.s_addr; + status = send( piiu->sock_chan, + &saddr, + sizeof(saddr), + 0); + + /* Set non blocking IO for UNIX to prevent dead locks */ +#ifdef UNIX + status = socket_ioctl( + piiu->sock_chan, FIONBIO, &true); -# endif +#endif - break; - case IPPROTO_UDP: - /* allocate a socket */ - sock = socket( AF_INET, /* domain */ - SOCK_DGRAM, /* type */ - 0); /* deflt proto */ - if(sock == ERROR) - return ECA_SOCK; + break; + case IPPROTO_UDP: + /* allocate a socket */ + sock = socket( AF_INET, /* domain */ + SOCK_DGRAM, /* type */ + 0); /* deflt proto */ + if(sock == ERROR) + return ECA_SOCK; - piiu->sock_chan = sock; - - /* - The following only needed on BSD 4.3 machines - */ - status = setsockopt(sock,SOL_SOCKET,SO_BROADCAST,&true,sizeof(true)); - if(status<0){ - printf("%d\n",MYERRNO); - socket_close(sock); - return ECA_CONN; - } - - memset(&saddr,0,sizeof(saddr)); - saddr.sin_family = AF_INET; - saddr.sin_addr.s_addr = htonl(INADDR_ANY); /* let slib pick lcl addr */ - saddr.sin_port = htons(0); - - status = bind(sock, &saddr, sizeof(saddr)); - if(status<0){ - printf("%d\n",MYERRNO); - ca_signal(ECA_INTERNAL,"bind failed"); - } - - piiu->max_msg = MAX_UDP - sizeof(piiu->send->stk); - - break; - - default: - ca_signal(ECA_INTERNAL,"alloc_ioc: ukn protocol\n"); - } - /* setup send_msg(), recv_msg() buffers */ - if(!piiu->send) - if(! (piiu->send = (struct buffer *) malloc(sizeof(struct buffer))) ){ - socket_close(sock); - return ECA_ALLOCMEM; - } - piiu->send->stk = 0; - - if(!piiu->recv) - if(! (piiu->recv = (struct buffer *) malloc(sizeof(struct buffer))) ){ - socket_close(sock); - return ECA_ALLOCMEM; - } - - piiu->recv->stk = 0; - piiu->conn_up = TRUE; - if(fd_register_func) - (*fd_register_func)(fd_register_arg, sock, TRUE); + piiu->sock_chan = sock; - /* Set up recv thread for VMS */ -# ifdef VMS - { - void recv_msg_ast(); - status = sys$qio( NULL, + /* + * The following only needed on BSD 4.3 machines + */ + status = setsockopt(sock,SOL_SOCKET,SO_BROADCAST,&true,sizeof(true)); + if(status<0){ + printf("%d\n",MYERRNO); + status = socket_close(sock); + if(status < 0){ + SEVCHK(ECA_INTERNAL,NULL); + } + return ECA_CONN; + } + + memset(&saddr,0,sizeof(saddr)); + saddr.sin_family = AF_INET; + /* + * let slib pick lcl addr + */ + saddr.sin_addr.s_addr = htonl(INADDR_ANY); + saddr.sin_port = htons(0); + + status = bind( sock, + (struct sockaddr *) &saddr, + sizeof(saddr)); + if(status<0){ + printf("%d\n",MYERRNO); + ca_signal(ECA_INTERNAL,"bind failed"); + } + + piiu->max_msg = MAX_UDP - sizeof(piiu->send->stk); + + break; + + default: + ca_signal(ECA_INTERNAL,"alloc_ioc: ukn protocol\n"); + } + /* setup cac_send_msg(), recv_msg() buffers */ + if(!piiu->send) + if(! (piiu->send = (struct buffer *) + malloc(sizeof(struct buffer))) ){ + status = socket_close(sock); + if(status < 0){ + SEVCHK(ECA_INTERNAL,NULL); + } + return ECA_ALLOCMEM; + } + piiu->send->stk = 0; + + if(!piiu->recv) + if(! (piiu->recv = (struct buffer *) + malloc(sizeof(struct buffer))) ){ + status = socket_close(sock); + if(status < 0){ + SEVCHK(ECA_INTERNAL,NULL); + } + return ECA_ALLOCMEM; + } + + piiu->recv->stk = 0; + piiu->conn_up = TRUE; + if(fd_register_func) + (*fd_register_func)(fd_register_arg, sock, TRUE); + + + /* Set up recv thread for VMS */ +#ifdef VMS + { + /* + * request to be informed of future IO + */ + status = sys$qio( + NULL, sock, IO$_RECEIVE, &piiu->iosb, - recv_msg_ast, + vms_recv_msg_ast, piiu, - piiu->recv->buf, - sizeof(piiu->recv->buf), - NULL, + &peek_ast_buf, + sizeof(peek_ast_buf), + MSG_PEEK, &piiu->recvfrom, sizeof(piiu->recvfrom), NULL); - if(status != SS$_NORMAL){ - lib$signal(status); - exit(); - } - } + if(status != SS$_NORMAL){ + lib$signal(status); + exit(); + } + } # endif # ifdef vxWorks - { - void recv_task(); - int pri; - char name[15]; + { + void recv_task(); + int pri; + char name[15]; - status == taskPriorityGet(VXTASKIDSELF, &pri); - if(status<0) - ca_signal(ECA_INTERNAL,NULL); + status == taskPriorityGet(VXTASKIDSELF, &pri); + if(status<0) + ca_signal(ECA_INTERNAL,NULL); - strcpy(name,"RD "); - strncat(name, taskName(VXTHISTASKID), sizeof(name)-strlen(name)-1); + strcpy(name,"RD "); + strncat(name, taskName(VXTHISTASKID), sizeof(name)-strlen(name)-1); - status = taskSpawn( name, + status = taskSpawn( + name, pri-1, VX_FP_TASK, 4096, recv_task, piiu, taskIdSelf()); - if(status<0) - ca_signal(ECA_INTERNAL,NULL); + if(status<0) + ca_signal(ECA_INTERNAL,NULL); - piiu->recv_tid = status; + piiu->recv_tid = status; - } -# endif - -/* - testing testing -*/ -#ifdef ZEBRA /* vw does not have getsockopt */ -{ -int timeo; -int timeolen = sizeof(timeo); - - status = getsockopt(sock,SOL_SOCKET,SO_SNDTIMEO,&timeo,&timeolen); - if(status<0){ - printf("%d\n",MYERRNO); - } -if(timeolen != sizeof(timeo)) -printf("bomb\n"); - -printf("send %d\n",timeo); - status = getsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,&timeo,&timeolen); - if(status<0){ - printf("%d\n",MYERRNO); - } -if(timeolen != sizeof(timeo)) -printf("bomb\n"); - -printf("recv %d\n",timeo); -} + } #endif - - - return ECA_NORMAL; + return ECA_NORMAL; } /* - * NOTIFY_CA_REPEATER + * NOTIFY_CA_REPEATER() + * * tell the cast repeater that another client has come on line * * NOTES: * 1) local communication only (no LAN traffic) * + * LOCK should be on while in this routine + * (MULTINET TCP/IP routines are not reentrant) */ notify_ca_repeater() { @@ -484,100 +555,124 @@ notify_ca_repeater() /* - * SEND_MSG + * SEND_MSG() * - * NOTE: Wallangong select cant be called in an AST with a timeout since they - * use timer ASTs to implement thier timeout. - * - * NOTE: Wallangong select does not return early if IO is present prior to the - * timeout expiring. * * LOCK should be on while in this routine */ -void -send_msg() +void cac_send_msg() { - unsigned cnt; - void *pmsg; - int status; - register struct ioc_in_use *piiu; + unsigned cnt; + void *pmsg; + int status; + register struct ioc_in_use *piiu; - /**********************************************************************/ - /* Note: this routine must not be called at AST level */ - /**********************************************************************/ - if(!ca_static->ca_repeater_contacted) - notify_ca_repeater(); + if(!ca_static->ca_repeater_contacted) + notify_ca_repeater(); + + for(piiu=iiu;piiu<&iiu[nxtiiu];piiu++) + if(piiu->send->stk){ + int retry_count; - /* don't allow UDP recieve messages to que up under UNIX */ -# ifdef UNIX - { - void recv_msg_select(); - /* test for recieve allready in progress and NOOP if so */ - if(!post_msg_active) - recv_msg_select(¬imeout); - } -# endif + cnt = piiu->send->stk; + pmsg = (void *) piiu->send->buf; - for(piiu=iiu;piiu<&iiu[nxtiiu];piiu++) - if(piiu->send->stk){ + retry_count =500; + while(TRUE){ + if(piiu->conn_up){ + /* + * send UDP or TCP message depending + * on whether this channel has a TCP + * connection yet + * + */ + status = sendto( + piiu->sock_chan, + pmsg, + cnt, + 0, + &piiu->sock_addr, + sizeof(piiu->sock_addr)); + } + else{ + /* + * send UDP message + * + * NOTE: this does not use a broadcast + * if the location of the channel is + * known from a previous connection. + * + * (piiu->sock_addr points to the + * known address) + */ + status = sendto( + iiu[BROADCAST_IIU].sock_chan, + pmsg, + cnt, + 0, + &piiu->sock_addr, + sizeof(piiu->sock_addr)); + } + if(status == cnt) + break; - cnt = piiu->send->stk + sizeof(piiu->send->stk); - piiu->send->stk = htonl(cnt); /* convert for 68000 */ - pmsg = piiu->send; /* byte cnt then buf */ + if(status>=0){ + if(status>cnt) + ca_signal( + ECA_INTERNAL, + "more sent than requested"); + cnt = cnt-status; + pmsg = (void *) (status+(char *)pmsg); + } +#ifdef UNIX + else if(MYERRNO == EWOULDBLOCK){ + /* + * Ensure we do not accumulate extra recv + * messages (for TCP) + */ + /* + * free up push pull deadlock only + * if recv not allready in progress + */ + if(post_msg_active==0) + recv_msg_select(¬imeout); + } +#endif + else{ + if(MYERRNO != EPIPE && MYERRNO != ECONNRESET) + printf( "CA: error on socket send() %d\n", + MYERRNO); + close_ioc(piiu); + break; + } - while(TRUE){ - if(piiu->conn_up){ - status = sendto( piiu->sock_chan, - pmsg, - cnt, - 0, - &piiu->sock_addr, - sizeof(piiu->sock_addr)); - } - else{ - /* send a directed UDP message (for search retries) */ - status = sendto( iiu[BROADCAST_IIU].sock_chan, - pmsg, - cnt, - 0, - &piiu->sock_addr, - sizeof(piiu->sock_addr)); - } - if(status == cnt) - break; + if(retry_count-- <= 0){ + char *iocname; + struct in_addr *inaddr; + + inaddr = &piiu->sock_addr.sin_addr; + iocname = host_from_addr(inaddr); - if(status>=0){ - if(status>cnt) - ca_signal(ECA_INTERNAL,"more sent than requested"); - cnt = cnt-status; - pmsg = (void *) (status+(char *)pmsg); - } - else if(MYERRNO == EWOULDBLOCK){ - } - else{ - if(MYERRNO != EPIPE && MYERRNO != ECONNRESET) - printf("send_msg(): error on socket send() %d\n",MYERRNO); - close_ioc(piiu); - break; - } + ca_signal(ECA_DLCKREST, iocname); + + close_ioc(piiu); + break; + } + TCPDELAY; + } - /* - Ensure we do not accumulate extra recv messages (for TCP) - */ -# ifdef UNIX - { - void recv_msg_select(); - recv_msg_select(¬imeout); - } -# endif - TCPDELAY; - } + /* reset send stack */ + piiu->send->stk = 0; - /* reset send stack */ - piiu->send->stk = 0; - } + /* + * reset the delay to the next keepalive + */ + if(piiu != &iiu[BROADCAST_IIU] && piiu->conn_up){ + piiu->next_retry = time(NULL) + CA_RETRY_PERIOD; + } + } } @@ -648,42 +743,42 @@ struct timeval *ptimeout; #endif - -void -recv_msg(piiu) + +/* + * RECV_MSG() + * + * + */ +void recv_msg(piiu) struct ioc_in_use *piiu; { - void tcp_recv_msg(); - void udp_recv_msg(); - switch(piiu->sock_proto){ - case IPPROTO_TCP: + switch(piiu->sock_proto){ + case IPPROTO_TCP: - /* #### remove this statement after debug is complete #### */ - if(!piiu->conn_up) - ca_signal(ECA_INTERNAL,"TCP burp at conn close\n"); + tcp_recv_msg(piiu); + flow_control(piiu); - tcp_recv_msg(piiu); - flow_control(piiu); - - break; + break; - case IPPROTO_UDP: - udp_recv_msg(piiu); - break; + case IPPROTO_UDP: + udp_recv_msg(piiu); + break; - default: - printf("send_msg: ukn protocol\n"); - abort(); - } + default: + printf("cac_send_msg: ukn protocol\n"); + abort(); + } - return; + return; } - - -void -tcp_recv_msg(piiu) + +/* + * TCP_RECV_MSG() + * + */ +void tcp_recv_msg(piiu) struct ioc_in_use *piiu; { unsigned long byte_cnt; @@ -693,45 +788,42 @@ struct ioc_in_use *piiu; struct buffer *rcvb = piiu->recv; int sock = piiu->sock_chan; - - + if(!ca_static->ca_repeater_contacted){ + LOCK; + notify_ca_repeater(); + UNLOCK; + } status = recv( sock, - &rcvb->stk, - sizeof(rcvb->stk), + &rcvb->buf[rcvb->stk], + sizeof(rcvb->buf), 0); - if(status != sizeof(rcvb->stk)){ - - if( status > 0) - ca_signal( - ECA_INTERNAL, - "partial recv on request of only 4 bytes\n"); - else if(status == 0){ - printf("CA: recv of zero length?\n"); - LOCK; - close_ioc(piiu); - UNLOCK; + if(status == 0){ + printf("CA: recv of zero length?\n"); + LOCK; + close_ioc(piiu); + UNLOCK; + return; + } + else if(status <0){ + /* try again on status of -1 and EWOULDBLOCK */ + if(MYERRNO == EWOULDBLOCK){ + TCPDELAY; return; } - else{ - /* try again on status of 0 or -1 and EWOULDBLOCK */ - if(MYERRNO == EWOULDBLOCK) - return; - if(MYERRNO != EPIPE && MYERRNO != ECONNRESET) - printf( "unexpected recv error 1 = %d %d\n", - MYERRNO, - status); - - LOCK; - close_ioc(piiu); - UNLOCK; - return; - } - } + if(MYERRNO != EPIPE && MYERRNO != ECONNRESET){ + printf( "unexpected recv error 1 = %d %d\n", + MYERRNO, + status); + } + LOCK; + close_ioc(piiu); + UNLOCK; + return; + } - /* switch from 68000 to VAX byte order */ - byte_cnt = (unsigned long) ntohl(rcvb->stk) - sizeof(rcvb->stk); + byte_cnt = (unsigned long) status; if(byte_cnt>MAX_MSG_SIZE){ printf( "recv_msg(): message overflow %u\n", byte_cnt-MAX_MSG_SIZE); @@ -742,191 +834,194 @@ struct ioc_in_use *piiu; } - timeoutcnt = byte_cnt + 3000; - byte_sum = 0; - while(TRUE){ - -# ifdef DEBUG - if(byte_sum) - printf( "recv_msg(): Warning- %d leftover bytes \n", - byte_cnt-byte_sum); -# endif - - status = recv( sock, - &rcvb->buf[byte_sum], - byte_cnt - byte_sum, - 0); - if(status < 0){ - if(MYERRNO != EWOULDBLOCK){ - if(MYERRNO != EPIPE && MYERRNO != ECONNRESET) - printf("recv error 2 = %d\n",MYERRNO); - - LOCK; - close_ioc(piiu); - UNLOCK; - return; - } - - if(--timeoutcnt < 0){ - printf("recv_msg(): message bdy wait tmo\n"); - LOCK; - close_ioc(piiu); - UNLOCK; - abort(); - } - } - else{ - byte_sum += status; - if(byte_sum >= byte_cnt) - break; - } - - /* wait for TCP/IP to complete the message transfer */ - TCPDELAY; - } + rcvb->stk += byte_cnt; /* post message to the user */ - post_msg(rcvb->buf, byte_cnt, piiu->sock_addr.sin_addr, piiu); + byte_cnt = rcvb->stk; + post_msg( rcvb->buf, + &byte_cnt, + &piiu->sock_addr.sin_addr, + piiu); + if(byte_cnt){ + /* + * realign partial message + */ + memcpy( rcvb->buf, + rcvb->buf + rcvb->stk - byte_cnt, + byte_cnt); +#ifdef DEBUG + printf( "CA: realigned message of %d bytes\n", + byte_cnt); +#endif + } + rcvb->stk = byte_cnt; + + /* + * reset the delay to the next keepalive + */ + if(piiu != &iiu[BROADCAST_IIU] && piiu->conn_up){ + piiu->next_retry = time(NULL) + CA_RETRY_PERIOD; + } return; } - -void -udp_recv_msg(piiu) + +/* + * UDP_RECV_MSG() + * + */ +void udp_recv_msg(piiu) struct ioc_in_use *piiu; { - unsigned long byte_cnt; - int status; - struct buffer *rcvb = piiu->recv; - int sock = piiu->sock_chan; - struct sockaddr_in reply; - int reply_size = sizeof(reply); - char *ptr; - unsigned nchars; + int status; + struct buffer *rcvb = piiu->recv; + int sock = piiu->sock_chan; + int reply_size; + char *ptr; + unsigned nchars; + struct msglog{ + unsigned nbytes; + unsigned RISC_pad; + struct sockaddr_in addr; + }; + struct msglog *pmsglog; + - rcvb->stk =0; - do{ + rcvb->stk =0; + while(TRUE){ - status = recvfrom( + pmsglog = (struct msglog *) &rcvb->buf[rcvb->stk]; + rcvb->stk += sizeof(*pmsglog); + + reply_size = sizeof(struct sockaddr_in); + status = recvfrom( sock, &rcvb->buf[rcvb->stk], MAX_UDP, 0, - &reply, + &pmsglog->addr, &reply_size); - if(status < sizeof(int)){ - /* op would block which is ok to ignore till ready later */ - if(MYERRNO == EWOULDBLOCK) - break; - ca_signal(ECA_INTERNAL,"unexpected udp recv error"); - } + if(status < 0){ + /* + * op would block which is ok to ignore till ready + * later + */ + if(MYERRNO == EWOULDBLOCK) + break; + ca_signal(ECA_INTERNAL,"unexpected udp recv error"); + } + else if(status == 0){ + break; + } - /* switch from 68000 to VAX byte order */ - byte_cnt = (unsigned long) ntohl(*(int *)&rcvb->buf[rcvb->stk]); -# ifdef DEBUG - printf("recieved a udp reply of %d bytes\n",byte_cnt); -# endif - if(byte_cnt != status){ - printf("recv_cast(): corrupt UDP recv %d\n",MYERRNO); - printf("recv_cast(): header %d actual %d\n",byte_cnt,status); - return; - } - rcvb->stk += byte_cnt; + /* + * log the msg size + */ + rcvb->stk += status; + pmsglog->nbytes = (unsigned long) status; +#ifdef DEBUG + printf("recieved a udp reply of %d bytes\n",byte_cnt); +#endif + - *(struct in_addr *) &rcvb->buf[rcvb->stk] = reply.sin_addr; - rcvb->stk += sizeof(reply.sin_addr); - - if(rcvb->stk + MAX_UDP > MAX_MSG_SIZE) - break; + if(rcvb->stk + MAX_UDP + sizeof(*pmsglog) > MAX_MSG_SIZE) + break; - /* - More comming ? - */ - status = socket_ioctl( sock, - FIONREAD, - &nchars); - if(status<0) - ca_signal(ECA_INTERNAL,"unexpected udp ioctl err\n"); + /* + * More comming ? + */ + status = socket_ioctl( sock, + FIONREAD, + &nchars); + if(status<0) + ca_signal(ECA_INTERNAL,"unexpected udp ioctl err\n"); - }while(nchars); + if(nchars==0) + break; + } - for( ptr = rcvb->buf; - ptr < &rcvb->buf[rcvb->stk]; - ptr += byte_cnt + sizeof(reply.sin_addr)){ - byte_cnt = (unsigned long) ntohl(*(int *)ptr); + pmsglog = (struct msglog *) rcvb->buf; + while(pmsglog < (struct msglog *)&rcvb->buf[rcvb->stk]){ + unsigned long msgcount; - /* post message to the user */ - post_msg( ptr + sizeof(int), - byte_cnt - sizeof(int), - *(struct in_addr *)(ptr+byte_cnt), - piiu); - } + /* post message to the user */ + msgcount = pmsglog->nbytes; + post_msg( pmsglog+1, + &msgcount, + &pmsglog->addr.sin_addr, + piiu); + if(msgcount){ + printf( "CA: UDP alignment problem %d\n", + msgcount); + } + + pmsglog = (struct msglog *) + (pmsglog->nbytes + (char *) (pmsglog+1)); + } - return; + return; } - + #ifdef vxWorks -void -recv_task(piiu, moms_tid) +/* + * RECV_TASK() + * + */ +void recv_task(piiu, moms_tid) struct ioc_in_use *piiu; int moms_tid; { - int status; + int status; - status = taskVarAdd(VXTHISTASKID, &ca_static); - if(status == ERROR) - abort(); + status = taskVarAdd(VXTHISTASKID, &ca_static); + if(status == ERROR) + abort(); - ca_static = (struct ca_static *) taskVarGet(moms_tid, &ca_static); - if(ca_static == (struct ca_static*)ERROR) - abort(); + ca_static = (struct ca_static *) taskVarGet(moms_tid, &ca_static); + if(ca_static == (struct ca_static*)ERROR) + abort(); - while(piiu->conn_up) - recv_msg(piiu); + while(piiu->conn_up) + recv_msg(piiu); - /* - Exit recv task - NOTE on vxWorks I dont want the global channel access - exit handler to run for this pod of tasks when the recv - task exits so I delete the task variable here. - The CA exit handler ignores tasks with out the ca task - var defined. - */ + /* + * Exit recv task + * + * NOTE on vxWorks I dont want the global channel access exit handler to + * run for this pod of tasks when the recv task exits so I delete the + * task variable here. The CA exit handler ignores tasks with out the + * ca task var defined. + */ - status = taskVarDelete(VXTHISTASKID, &ca_static); - if(status == ERROR) - abort(); + status = taskVarDelete(VXTHISTASKID, &ca_static); + if(status == ERROR) + abort(); - exit(); + exit(); } #endif /* * - * RECV_MSG_AST() + * VMS_RECV_MSG_AST() * * */ #ifdef VMS -void -recv_msg_ast(piiu) +void vms_recv_msg_ast(piiu) struct ioc_in_use *piiu; { - short io_status = piiu->iosb.status; - int io_count = piiu->iosb.count; - struct sockaddr_in *paddr; - char *pbuf; - unsigned int *pcount= (unsigned int *) piiu->recv->buf; - int bufsize; - unsigned long byte_cnt; + short io_status; + + io_status = piiu->iosb.status; if(io_status != SS$_NORMAL){ close_ioc(piiu); @@ -934,107 +1029,30 @@ struct ioc_in_use *piiu; lib$signal(io_status); return; } + + if(!ca_static->ca_repeater_contacted) + notify_ca_repeater(); + + recv_msg(piiu); + /* - * NOTE: The following is a bug fix since WIN has returned the - * address structure missaligned by 16 bits - * - * the fix is reliable since this structure happens to be padded with - * zeros at the end by more than 16 bits + * request to be informed of future IO */ - if(piiu->sock_proto == IPPROTO_TCP) - paddr = (struct sockaddr_in *) &piiu->sock_addr; - else -#ifdef WINTCP - paddr = (struct sockaddr_in *) - ((char *)&piiu->recvfrom+sizeof(short)); -#else - paddr = (struct sockaddr_in *) - (char *)&piiu->recvfrom; -#endif - - piiu->recv->stk += io_count; - io_count = piiu->recv->stk; - - while(TRUE){ - pbuf = (char *) (pcount+1); - - /* switch from 68000 to VAX byte order */ - byte_cnt = (unsigned long) ntohl(*pcount); - if(byte_cnt>MAX_MSG_SIZE || byte_cntsin_addr, - piiu); - break; - } - else if(io_count > byte_cnt) - post_msg( - pbuf, - byte_cnt-sizeof(*pcount), - paddr->sin_addr, - piiu); - else{ - if(pcount != piiu->recv->buf){ - memcpy(piiu->recv->buf, pcount, io_count); - piiu->recv->stk = io_count; - } - - bufsize = sizeof(piiu->recv->buf) - piiu->recv->stk; - io_status = sys$qio( - NULL, - piiu->sock_chan, - IO$_RECEIVE, - &piiu->iosb, - recv_msg_ast, - piiu, - &piiu->recv->buf[piiu->recv->stk], - bufsize, - NULL, - &piiu->recvfrom, - sizeof(piiu->recvfrom), - NULL); - if(io_status != SS$_NORMAL){ - if(io_status == SS$_IVCHAN) - printf("CA: Unable to requeue AST?\n"); - else - lib$signal(io_status); - } - return; - } - io_count -= byte_cnt; - pcount = (int *) (byte_cnt + (char *)pcount); - - } - - if(piiu->sock_proto == IPPROTO_TCP) - flow_control(piiu); - - piiu->recv->stk = 0; io_status = sys$qio( NULL, piiu->sock_chan, IO$_RECEIVE, &piiu->iosb, - recv_msg_ast, + vms_recv_msg_ast, piiu, - piiu->recv->buf, - sizeof(piiu->recv->buf), - NULL, + &peek_ast_buf, + sizeof(peek_ast_buf), + MSG_PEEK, &piiu->recvfrom, sizeof(piiu->recvfrom), NULL); if(io_status != SS$_NORMAL) - lib$signal(io_status); - + lib$signal(io_status); return; } #endif @@ -1042,7 +1060,7 @@ struct ioc_in_use *piiu; /* * - * CLOSE_IOC + * CLOSE_IOC() * * set an iiu in the disconnected state * @@ -1054,53 +1072,66 @@ void close_ioc(piiu) struct ioc_in_use *piiu; { - register chid chix; - int status; - register evid monix; - struct connection_handler_args args; + register chid chix; + struct connection_handler_args args; + int status; - if(!piiu->conn_up) - return; + if(!piiu->conn_up) + return; - /* - * reset send stack- discard pending ops when the conn broke (assume - * use as UDP buffer during disconn) - */ - piiu->send->stk = 0; - piiu->max_msg = MAX_UDP; - piiu->conn_up = FALSE; + /* + * reset send stack- discard pending ops when the conn broke (assume + * use as UDP buffer during disconn) + */ + piiu->send->stk = 0; + piiu->recv->stk = 0; + piiu->max_msg = MAX_UDP; + piiu->conn_up = FALSE; -# ifdef UNIX - /* clear unused select bit */ - FD_CLR(piiu->sock_chan, &readch); -# endif + /* + * reset the delay to the next retry + */ + piiu->next_retry = CA_CURRENT_TIME; + piiu->nconn_tries = 0; + piiu->retry_delay = 1; - chix = (chid) &piiu->chidlist.node.next; - while(chix = (chid) chix->node.next){ - chix->type = TYPENOTCONN; - chix->count = 0; - chix->state = cs_prev_conn; - chix->paddr = NULL; - if(chix->connection_func){ - args.chid = chix; - args.op = CA_OP_CONN_DOWN; - (*chix->connection_func)(args); - } - } +# ifdef UNIX + /* clear unused select bit */ + FD_CLR(piiu->sock_chan, &readch); +# endif - if(fd_register_func) - (*fd_register_func)(fd_register_arg, piiu->sock_chan, FALSE); + chix = (chid) &piiu->chidlist.node.next; + while(chix = (chid) chix->node.next){ + chix->type = TYPENOTCONN; + chix->count = 0; + chix->state = cs_prev_conn; + chix->paddr = NULL; + if(chix->connection_func){ + args.chid = chix; + args.op = CA_OP_CONN_DOWN; + (*chix->connection_func)(args); + } + } - close(piiu->sock_chan); - piiu->sock_chan = -1; - if(piiu->chidlist.count) - ca_signal(ECA_DISCONN, host_from_addr(piiu->sock_addr.sin_addr)); + if(fd_register_func) + (*fd_register_func)(fd_register_arg, piiu->sock_chan, FALSE); + + status = socket_close(piiu->sock_chan); + if(status < 0){ + SEVCHK(ECA_INTERNAL,NULL); + } + piiu->sock_chan = -1; + if(piiu->chidlist.count) + ca_signal( + ECA_DISCONN, + host_from_addr(&piiu->sock_addr.sin_addr)); } - + /* + * REPEATER_INSTALLED() * * Test for the repeater allready installed * @@ -1141,15 +1172,19 @@ repeater_installed() bd.sin_family = AF_INET; bd.sin_addr.s_addr = htonl(INADDR_ANY); bd.sin_port = htons(CA_CLIENT_PORT); - status = bind(sock, &bd, sizeof bd); + status = bind( sock, + (struct sockaddr *) &bd, + sizeof bd); if(status<0) if(MYERRNO == EADDRINUSE) installed = TRUE; else abort(); - - close(sock); - + status = socket_close(sock); + if(status<0){ + SEVCHK(ECA_INTERNAL,NULL); + } + return installed; } diff --git a/src/ca/iocinf.h b/src/ca/iocinf.h index a9ebe650c..4d2446919 100644 --- a/src/ca/iocinf.h +++ b/src/ca/iocinf.h @@ -9,11 +9,9 @@ /* */ /* History */ /* ------- */ -/* */ -/* Date Programmer Comments */ -/* ---- ---------- -------- */ -/* 8/87 Jeff Hill Init Release */ -/* 1/90 Jeff Hill fd_set in the UNIX version only */ +/* .01 08xx87 joh Init Release */ +/* .02 01xx90 joh fd_set in the UNIX version only */ +/* .03 060691 joh Rearanged buffer struct for SPARC port */ /* */ /*_begin */ /************************************************************************/ @@ -60,7 +58,6 @@ # include #endif -void send_msg(); /* throw out requests prior to last ECA_TIMEOUT from ca_pend */ #define VALID_MSG(PIIU) (piiu->read_seq == piiu->cur_read_seq) @@ -87,25 +84,13 @@ enum channel_state{cs_never_conn, cs_prev_conn, cs_conn, closed}; #define SETPENDRECV {pndrecvcnt++;} #define CLRPENDRECV {if(--pndrecvcnt<1){IODONESUB; POST_IO_EV;}} -/* size of object in bytes rounded up to nearest long word */ -#define QUAD_ROUND(A) (((A)+3)>>2) -#define QUAD_SIZEOF(A) (QUAD_ROUND(sizeof(A))) - -/* size of object in bytes rounded up to nearest short word */ -#define BI_ROUND(A) (((A)+1)>>1) -#define BI_SIZEOF(A) (QUAD_ROUND(sizeof(A))) -/* -#define MAX(A,B) (((A)>(B))?(A):(B)) -#define MIN(A,B) (((A)>(B))?(B):(A)) -*/ /************************************************************************/ /* Structures */ /************************************************************************/ - /* stk must be above and contiguous with buf ! */ struct buffer{ - unsigned long stk; char buf[MAX_MSG_SIZE]; /* from iocmsg.h */ + unsigned long stk; }; @@ -121,6 +106,9 @@ struct pending_io_event{ void *io_done_arg; }; +typedef unsigned long ca_time; +#define CA_RETRY_PERIOD 5 /* sec to next keepalive */ +#define CA_CURRENT_TIME 0 #define MAX_CONTIGUOUS_MSG_COUNT 2 @@ -148,15 +136,16 @@ struct pending_io_event{ #define io_done_flag (ca_static->ca_io_done_flag) #define evuser (ca_static->ca_evuser) #define client_lock (ca_static->ca_client_lock) -#define event_buf (ca_static->ca_event_buf) -#define event_buf_size (ca_static->ca_event_buf_size) #define local_chidlist (ca_static->ca_local_chidlist) #define dbfree_ev_list (ca_static->ca_dbfree_ev_list) +#define lcl_buff_list (ca_static->ca_lcl_buff_list) #endif #ifdef VMS #define io_done_flag (ca_static->ca_io_done_flag) +#define peek_ast_buf (ca_static->ca_peek_ast_buf) #endif + struct ca_static{ unsigned short ca_nxtiiu; long ca_pndrecvcnt; @@ -166,7 +155,7 @@ struct ca_static{ void (*ca_connection_func)(); void *ca_connection_arg; void (*ca_fd_register_func)(); - void (*ca_fd_register_arg)(); + void *ca_fd_register_arg; short ca_exit_in_progress; unsigned short ca_post_msg_active; LIST ca_free_event_list; @@ -177,16 +166,16 @@ struct ca_static{ #endif #ifdef VMS int ca_io_done_flag; + char ca_peek_ast_buf; #endif #ifdef vxWorks int ca_io_done_flag; void *ca_evuser; FAST_LOCK ca_client_lock; - void *ca_event_buf; - unsigned ca_event_buf_size; int ca_tid; LIST ca_local_chidlist; LIST ca_dbfree_ev_list; + LIST ca_lcl_buff_list; #endif struct ioc_in_use{ unsigned contiguous_msg_count; @@ -200,10 +189,10 @@ struct ca_static{ unsigned read_seq; unsigned cur_read_seq; LIST chidlist; /* chans on this connection */ - unsigned nconn_wait; /* number delays before try */ - unsigned nconn_tries; /* number of times conn was tried */ int conn_up; /* boolean: T-conn /F-disconn */ - unsigned count_to_refresh; /* ndelays to conn retry */ + unsigned nconn_tries; + ca_time next_retry; + ca_time retry_delay; #define MAXCONNTRIES 3 #ifdef VMS /* for qio ASTs */ struct sockaddr_in recvfrom; @@ -236,12 +225,21 @@ struct ca_static{ GLBLTYPE struct ca_static *ca_static; -#ifdef VMS -GLBLTYPE -char ca_unique_address; -# define MYTIMERID (&ca_unique_address) -#endif - - - +/* + * CA internal functions + * + */ +void cac_send_msg(); +void build_msg(); +struct in_addr broadcast_addr(); +void manage_conn(); +void noop_msg(); +void ca_busy_message(); +void ca_ready_message(); +void flow_control(); +char *host_from_addr(); +int ca_repeater_task(); +void close_ioc(); +void recv_msg_select(); +void mark_server_available(); #endif diff --git a/src/ca/iocmsg.h b/src/ca/iocmsg.h index efd1a7c7d..cb1099f18 100644 --- a/src/ca/iocmsg.h +++ b/src/ca/iocmsg.h @@ -1,18 +1,21 @@ #ifndef __IOCMSG__ /* - History - 1/90 joh removed status field in favor of a seperate command- - saves space on every successful operation - - 4-13-90 joh moved server ports to above IPPORT_USERRESERVED - see in.h - -*/ + * History + * .01 01xx90 joh removed status field in favor of a independent m_cmmd- + * saves space on every successful operation + * + * .02 041390 joh moved server ports to above IPPORT_USERRESERVED + * see in.h + * + * .03 060391 joh Bumped protocol version to 4 to support changes for + * SPARC alignment in db_access.h + * + */ #define __IOCMSG__ /* TCP/UDP port number (bumped each protocol change) */ -#define CA_PROTOCOL_VERSION 3 +#define CA_PROTOCOL_VERSION 4 #define CA_PORT_BASE IPPORT_USERRESERVED + 56 #define CA_SERVER_PORT (CA_PORT_BASE+CA_PROTOCOL_VERSION*2) #define CA_CLIENT_PORT (CA_PORT_BASE+CA_PROTOCOL_VERSION*2+1) @@ -23,7 +26,6 @@ /* values for m_cmmd */ - #define IOC_NOOP 0 /* do nothing, but verify TCP */ #define IOC_EVENT_ADD 1 /* add an event */ #define IOC_EVENT_CANCEL 2 /* cancel an event */ @@ -45,20 +47,42 @@ #define IOC_READ_BUILD 16 /* read accompanying a build */ #define REPEATER_CONFIRM 17 /* registration confirmation */ - /* - for use with build and search and not_found - (if search fails and its not a broadcast tell - the client to look elesewhere) - */ +/* + * for use with build and search and not_found (if search fails and + * its not a broadcast tell the client to look elesewhere) + */ #define DOREPLY 10 #define DONTREPLY 5 - - /* extmsg - the nonvariant part of each message sent/recv - by the request server. - */ +/* size of object in bytes rounded up to nearest oct word */ +#define OCT_ROUND(A) (((A)+7)>>3) +#define OCT_SIZEOF(A) (OCT_ROUND(sizeof(A))) +/* size of object in bytes rounded up to nearest long word */ +#define QUAD_ROUND(A) (((A)+3)>>2) +#define QUAD_SIZEOF(A) (QUAD_ROUND(sizeof(A))) +/* size of object in bytes rounded up to nearest short word */ +#define BI_ROUND(A) (((A)+1)>>1) +#define BI_SIZEOF(A) (BI_ROUND(sizeof(A))) + +/* + * Required Message Alignment + * + * Determined by the architecture with the most restrictive + * alignment requirements (currently the SPARC). + * + * octal rounding + * + * NOTE: all structures declared in this file must have a + * byte count which is evenly divisible by 8 for the SPARC. + */ +#define CA_MESSAGE_ALIGN(A) (OCT_ROUND(A)<<3) + +/* + * the common part of each message sent/recv by the + * CA server. + */ struct extmsg { unsigned short m_cmmd; /* operation to be performed */ unsigned short m_postsize; /* size of message extension */ @@ -70,7 +94,9 @@ struct extmsg { }; - /* for monitor (event) message extension */ +/* + * for monitor (event) message extension + */ struct mon_info{ float m_lval; /* low delta */ float m_hval; /* high delta */ diff --git a/src/ca/os_depen.h b/src/ca/os_depen.h index 438d0e756..7530db235 100644 --- a/src/ca/os_depen.h +++ b/src/ca/os_depen.h @@ -96,15 +96,17 @@ extern int taskIdCurrent; #ifdef VMS struct iosb{ -short status; -unsigned short count; -void *device; + short status; + unsigned short count; + void *device; }; +static char ca_unique_address; +#define MYTIMERID (&ca_unique_address) #endif struct timeval{ - unsigned long tv_sec; - unsigned long tv_usec; + unsigned long tv_sec; + unsigned long tv_usec; }; #ifdef vxWorks @@ -137,15 +139,19 @@ struct timeval{ #endif #ifdef vxWorks -# define SYSFREQ sysClkRateGet() /* 60 Hz */ -# define TCPDELAY taskDelay((unsigned int)DELAYVAL*SYSFREQ); -# define time(A) (tickGet()/sysfreq) +# define SYSFREQ sysClkRateGet() /* usually 60 Hz */ +# define TCPDELAY taskDelay((unsigned int)DELAYVAL*SYSFREQ); +# define time(A) (tickGet()/SYSFREQ) #endif #ifdef UNIX -# define SYSFREQ 1000000 /* 1 MHz */ -# define TCPDELAY {if(select(0,NULL,NULL,NULL,&tcpdelayval)<0)abort();} -static struct timeval tcpdelayval = {0,(unsigned int)DELAYVAL*SYSFREQ}; +# define SYSFREQ 1000000 /* 1 MHz */ +# define TCPDELAY {if(select(0,NULL,NULL,NULL,&tcpdelayval)<0)abort();} +# ifndef CA_GLBLSOURCE + extern struct timeval tcpdelayval; +# else + struct timeval tcpdelayval = {0,(unsigned int)DELAYVAL*SYSFREQ}; +# endif #endif diff --git a/src/ca/repeater.c b/src/ca/repeater.c index 1af02908c..bffc314a0 100644 --- a/src/ca/repeater.c +++ b/src/ca/repeater.c @@ -36,18 +36,24 @@ * * This server does not gaurantee the reliability of * fanned out broadcasts in keeping with the nature of - * broadcasts. Therefore, CA provides a backup. + * broadcasts. Therefore, CA retransmitts lost msgs. * * UDP datagrams delivered between two processes on the same * machine dont travel over the LAN. * * - * Modification Log: - * ----------------- + * Modification Log: + * ----------------- + * .01 060691 joh Took out 4 byte count at message begin to + * in preparation for SPARC alignment + * */ #include #include +#ifdef VMS +#include +#endif #include #include @@ -60,9 +66,9 @@ struct sockaddr_in *local_addr(); /* - these can be external since there is only one instance - per machine so we dont care about reentrancy -*/ + * these can be external since there is only one instance + * per machine so we dont care about reentrancy + */ struct one_client{ NODE node; struct sockaddr_in from; @@ -72,9 +78,13 @@ static LIST client_list; static -char buf[MAX_UDP]; /* bigger than max TCP */ +char buf[MAX_UDP]; +int ca_repeater(); +#define NTRIES 100 + + /* * * Fan out broadcasts to several processor local tasks @@ -86,6 +96,38 @@ main() #else ca_repeater_task() #endif +{ + unsigned i,j; + + /* + * + * This allows the system inet support to takes it + * time releasing the bind I used to test if the repeater + * is up. + * + */ + for(i=0; i 0){ - if(size != ntohl(*pcount)) - printf("ca repeater: corrupt msg ignored\n"); - else if(from.sin_addr.s_addr != local.sin_addr.s_addr) + if(from.sin_addr.s_addr != local.sin_addr.s_addr) for( pclient = (struct one_client *) client_list.node.next; pclient; @@ -150,18 +194,17 @@ ca_repeater_task() 0, &pclient->from, sizeof pclient->from); - if(status < 0) - abort(); + if(status < 0){ + printf("CA Repeater: fanout err %d\n", + MYERRNO); + } #ifdef DEBUG printf("Sent\n"); #endif } } else if(size == 0){ - struct { - unsigned length; - struct extmsg extmsg; - }confirm; + struct extmsg confirm; /* * If this is a processor local message then add to @@ -189,9 +232,8 @@ ca_repeater_task() } memset(&confirm, NULL, sizeof confirm); - confirm.length = htonl(sizeof confirm); - confirm.extmsg.m_cmmd = htons(REPEATER_CONFIRM); - confirm.extmsg.m_available = local.sin_addr.s_addr; + confirm.m_cmmd = htons(REPEATER_CONFIRM); + confirm.m_available = local.sin_addr.s_addr; status = sendto( sock, &confirm, @@ -199,10 +241,15 @@ ca_repeater_task() 0, &from, /* reflect back to sender */ sizeof from); - if(status != sizeof confirm) - abort(); - }else - abort(); + if(status != sizeof confirm){ + printf("CA Repeater: confirm err %d\n", + MYERRNO); + } + } + else{ + printf("CA Repeater: recv err %d\n", + MYERRNO); + } /* remove any dead wood prior to pending */ for( pclient = (struct one_client *) @@ -217,7 +264,7 @@ ca_repeater_task() } } - + /* * * check to see if this client is still around @@ -236,8 +283,11 @@ struct one_client *pclient; sock = socket( AF_INET, /* domain */ SOCK_DGRAM, /* type */ 0); /* deflt proto */ - if(sock == ERROR) - abort(); + if(sock == ERROR){ + printf("CA Repeater: no socket err %d\n", + MYERRNO); + return ERROR; + } memset(&bd,0,sizeof bd); bd.sin_family = AF_INET; @@ -247,10 +297,12 @@ struct one_client *pclient; if(status<0){ if(MYERRNO == EADDRINUSE) present = TRUE; - else - abort(); + else{ + printf("CA Repeater: client cleanup err %d\n", + MYERRNO); + } } - close(sock); + socket_close(sock); if(!present){ lstDelete(&client_list, pclient); diff --git a/src/ca/service.c b/src/ca/service.c index ed6bc513c..67a651b2c 100644 --- a/src/ca/service.c +++ b/src/ca/service.c @@ -10,11 +10,17 @@ /* History */ /* ------- */ /* */ -/* Date Programmer Comments */ -/* ---- ---------- -------- */ -/* 8/87 Jeff Hill Init Release */ -/* 1/90 Jeff Hill Made cmmd for errors which */ +/* Date Person Comments */ +/* ---- ------ -------- */ +/* 8/87 joh Init Release */ +/* 1/90 joh Made cmmd for errors which */ /* eliminated the status field */ +/* 030791 joh Fixed problem where pend count was decremented */ +/* prior to connecting chan (setting the type). */ +/* 041591 joh added call to channel exsits routine */ +/* 060491 joh fixed structure pass for SPARC cc */ +/* 060691 jow reworked to remove 4 byte count before each */ +/* macro message */ /* */ /*_begin */ /************************************************************************/ @@ -55,420 +61,477 @@ #include void reconnect_channel(); +#define BUFSTAT printf("expected %d left %d\n",msgcnt,*pbufcnt); -void post_msg(hdrptr,bufcnt,net_addr,piiu) -register struct extmsg *hdrptr; -register long bufcnt; -struct in_addr net_addr; -struct ioc_in_use *piiu; + + +/* + * post_msg() + * + * + * + */ +void +post_msg(hdrptr, pbufcnt, pnet_addr, piiu) + register struct extmsg *hdrptr; + register unsigned long *pbufcnt; + struct in_addr *pnet_addr; + struct ioc_in_use *piiu; { - evid monix; - long msgcnt; - long tmp; + evid monix; + long msgcnt; - register void * t_available; - register unsigned short t_postsize; - register unsigned short t_cmmd; - register chtype t_type; - register unsigned short t_count; - register unsigned short t_size; - int status; + register void *t_available; + register unsigned short t_postsize; + register unsigned short t_cmmd; + register chtype t_type; + register unsigned short t_count; + int status; -# define BUFSTAT\ - printf("expected %d left %d\n",msgcnt,bufcnt); - - post_msg_active++; + post_msg_active++; - while(bufcnt>0){ -# ifdef DEBUG - printf( "processing message- bytes left %d, pending msgcnt %d\n", - bufcnt, - pndrecvcnt); -# endif - - /* byte swap the message up front */ - t_available = (void *) hdrptr->m_available; - t_postsize = ntohs(hdrptr->m_postsize); - t_cmmd = ntohs(hdrptr->m_cmmd); - t_type = ntohs(hdrptr->m_type); - t_count = ntohs(hdrptr->m_count); - t_size = dbr_size[t_type]; - -# ifdef DEBUG - printf( "MSG: cmd:%d type:%d cnt:%d size:%d npost:%d avail:%x\n", - t_cmmd, - t_type, - t_count, - t_size, - t_postsize, - t_available - ); -# endif - - msgcnt = sizeof(*hdrptr) + t_postsize; - if(bufcnt-msgcnt < 0){ - printf( - "post_msg(): expected msg size larger than actual msg %d %d\n", - bufcnt, - msgcnt); - post_msg_active--; - return; - } - - switch(t_cmmd){ - - case IOC_READ_NOTIFY: - { - /* run the user's event handler */ - /* m_available points to event descriptor */ - struct event_handler_args args; - - monix = (evid) t_available; - - - /* - * Currently only the VAXs need data conversion - */ -# ifdef VAX - (*cvrt[t_type])( hdrptr+1, hdrptr+1, FALSE, t_count); -# endif - - /* - * Orig version of CA didnt use this strucure. - * This would run faster if I had decided to - * pass a pointer to this structure rather - * than the structure itself early on. - * - * Pumping the arguments on the stack explicitly - * could cause problems if a small item is in - * the structure and we are on a SPARC processor. - * - * call handler, only if they did not clear the chid - * in the interim - */ - if(*monix->usr_func){ - args.usr = monix->usr_arg; - args.chid = monix->chan; - args.type = t_type; - args.count = t_count; - args.dbr = (void *) (hdrptr+1); - - (*monix->usr_func)(args); - } - - LOCK; - lstDelete(&pend_read_list, monix); - lstAdd(&free_event_list, monix); - UNLOCK; - - break; - } - case IOC_EVENT_ADD: - { - /* run the user's event handler */ - /* m_available points to event descriptor */ - struct event_handler_args args; - - monix = (evid) t_available; - - - /* m_postsize = 0 is a confirmation of a monitor cancel */ - if( !t_postsize ){ - LOCK; - lstDelete(&monix->chan->eventq, monix); - lstAdd(&free_event_list, monix); - UNLOCK; - - break; - } - - /* only call if not disabled */ - if(!monix->usr_func) - break; - - /* - * Currently only the VAXs need data conversion - */ -# ifdef VAX - (*cvrt[t_type])( hdrptr+1, hdrptr+1, FALSE, t_count); -# endif - - - - /* - * Orig version of CA didnt use this strucure. - * This would run faster if I had decided to - * pass a pointer to this structure rather - * than the structure itself early on. - * - * Pumping the arguments on the stack explicitly - * could cause problems if a small item is in - * the structure and we are on a SPARC processor. - * - */ - args.usr = monix->usr_arg; - args.chid = monix->chan; - args.type = t_type; - args.count = t_count; - args.dbr = (void *) (hdrptr+1); - - /* call their handler */ - (*monix->usr_func)(args); - - break; - } - case IOC_READ: - case IOC_READ_BUILD: - { - chid chan = (chid) hdrptr->m_pciu; - - /* only count get returns if from the current read seq */ - if(!VALID_MSG(piiu)) - break; - -if(t_postsize > (t_count-1) * dbr_value_size[t_type] + dbr_size[t_type]) - SEVCHK(ECA_INTERNAL,"about to violate user's buffer"); - - /* - * Currently only the VAXs need data conversion - */ -# ifdef VAX - (*cvrt[t_type])( hdrptr+1, t_available, FALSE, t_count); -# else - /* in line is a little faster */ - if(t_postsize<=sizeof(int)){ - if(t_postsize==sizeof(long)) - *(long *)t_available = *(long *)(hdrptr+1); - else if(t_postsize==sizeof(short)) - *(short *)t_available = *(short *)(hdrptr+1); - else if(t_postsize==sizeof(char)) - *(char *)t_available = *(char *)(hdrptr+1); - }else - memcpy( - t_available, - hdrptr+1, - t_postsize); -# endif - - /* - * decrement the outstanding IO count - * - * This relies on the IOC_READ_BUILD msg returning prior to the - * IOC_BUILD msg. - */ - if( t_cmmd != IOC_READ_BUILD || - (chan->connection_func == NULL && chan->state==cs_never_conn)) - CLRPENDRECV; - - break; - } - case IOC_SEARCH: - case IOC_BUILD: - { - chid chan = (chid) t_available; - struct ioc_in_use *chpiiu = &iiu[chan->iocix]; - - if( chan->paddr ){ - - if(chpiiu->sock_addr.sin_addr.s_addr==net_addr.s_addr){ - printf("burp "); -#ifdef UNIX - fflush(stdout); + while (*pbufcnt >= sizeof(*hdrptr)) { +#ifdef DEBUG + printf("bytes left %d, pending msgcnt %d\n", + *pbufcnt, + pndrecvcnt); #endif - } - else{ - char msg[256]; - char acc[64]; - char rej[64]; - sprintf(acc,"%s", - host_from_addr(chpiiu->sock_addr.sin_addr)); - sprintf(rej,"%s",host_from_addr(net_addr)); - sprintf( - msg, + /* byte swap the message up front */ + t_available = (void *) hdrptr->m_available; + t_postsize = ntohs(hdrptr->m_postsize); + t_cmmd = ntohs(hdrptr->m_cmmd); + t_type = ntohs(hdrptr->m_type); + t_count = ntohs(hdrptr->m_count); + +#ifdef DEBUG + printf("MSG: cmd:%d type:%d cnt:%d npost:%d avail:%x\n", + t_cmmd, + t_type, + t_count, + t_postsize, + t_available + ); +#endif + + msgcnt = sizeof(*hdrptr) + t_postsize; + if (*pbufcnt < msgcnt) { + post_msg_active--; + return; + } + + switch (t_cmmd) { + + case IOC_READ_NOTIFY: + { + /* + * run the user's event handler + * m_available points to event descriptor + */ + struct event_handler_args args; + + monix = (evid) t_available; + + + /* + * Currently only the VAXs need data + * conversion + */ +#ifdef VAX + (*cvrt[t_type]) ( + hdrptr + 1, + hdrptr + 1, + FALSE, + t_count); +#endif + + /* + * + * call handler, only if they did not clear the + * chid in the interim + */ + if (*monix->usr_func) { + args.usr = monix->usr_arg; + args.chid = monix->chan; + args.type = t_type; + args.count = t_count; + args.dbr = (void *) (hdrptr + 1); + + (*monix->usr_func) (args); + } + LOCK; + lstDelete(&pend_read_list, monix); + lstAdd(&free_event_list, monix); + UNLOCK; + + break; + } + case IOC_EVENT_ADD: + { + struct event_handler_args args; + + /* + * run the user's event handler m_available + * points to event descriptor + */ + monix = (evid) t_available; + + + /* + * m_postsize = 0 is a confirmation of a + * monitor cancel + */ + if (!t_postsize) { + LOCK; + lstDelete(&monix->chan->eventq, monix); + lstAdd(&free_event_list, monix); + UNLOCK; + + break; + } + /* only call if not disabled */ + if (!monix->usr_func) + break; + + /* + * Currently only the VAXs need data + * conversion + */ +#ifdef VAX + (*cvrt[t_type]) ( + hdrptr + 1, + hdrptr + 1, + FALSE, + t_count); +#endif + + /* + * Orig version of CA didnt use this + * strucure. This would run faster if I had + * decided to pass a pointer to this + * structure rather than the structure itself + * early on. + * + * Pumping the arguments on the stack explicitly + * could cause problems if a small item is in + * the structure. + * + */ + args.usr = monix->usr_arg; + args.chid = monix->chan; + args.type = t_type; + args.count = t_count; + args.dbr = (void *) (hdrptr + 1); + + /* call their handler */ + (*monix->usr_func) (args); + + break; + } + case IOC_READ: + case IOC_READ_BUILD: + { + chid chan = (chid) hdrptr->m_pciu; + unsigned size; + + /* + * only count get returns if from the current + * read seq + */ + if (!VALID_MSG(piiu)) + break; + + size = dbr_size_n(t_type, t_count); + + /* + * Currently only the VAXs need data + * conversion + */ +#ifdef VAX + (*cvrt[t_type]) ( + hdrptr + 1, + t_available, + FALSE, + t_count); +#else + /* + * in line is a little faster + */ + switch(size){ + case sizeof(char): + *(char *) t_available = + *(char *) (hdrptr + 1); + break; + case sizeof(short): + *(short *) t_available = + *(short *) (hdrptr + 1); + break; + case sizeof(long): + *(long *) t_available = + *(long *) (hdrptr + 1); + break; + case sizeof(double): + *(double *) t_available = + *(double *) (hdrptr + 1); + break; + default: + memcpy( + t_available, + hdrptr + 1, + size); + break; + } +#endif + + /* + * decrement the outstanding IO count + * + * This relies on the IOC_READ_BUILD msg + * returning prior to the IOC_BUILD msg. + */ + if (t_cmmd != IOC_READ_BUILD || + (chan->connection_func == NULL && + chan->state == cs_never_conn)) + CLRPENDRECV; + + break; + } + case IOC_SEARCH: + case IOC_BUILD: + { + chid chan = (chid) t_available; + struct ioc_in_use *chpiiu; + + /* + * ignore broadcast replies for deleted channels + * + */ + LOCK; + status = client_channel_exists(chan); + UNLOCK; + + if (!status) { + char msg[64]; + + sprintf( + msg, + "Search reply from %s", + host_from_addr(pnet_addr)); + ca_signal(ECA_NOCHANMSG,msg); + break; + } + + chpiiu = &iiu[chan->iocix]; + + if (chan->paddr) { + + if (chpiiu->sock_addr.sin_addr.s_addr == + pnet_addr->s_addr) { + printf(" "); +#ifdef UNIX + fflush(stdout); +#endif + } else { + char msg[256]; + char acc[64]; + char rej[64]; + + sprintf(acc, + "%s", + host_from_addr( + &chpiiu->sock_addr.sin_addr)); + sprintf(rej, + "%s", + host_from_addr(pnet_addr)); + sprintf( + msg, "Channel: %s Accepted: %s Rejected: %s ", - chan+1, - acc, - rej); - ca_signal(ECA_DBLCHNL, msg); + chan + 1, + acc, + rej); + ca_signal(ECA_DBLCHNL, msg); + } + + /* + * IOC_BUILD messages allways have a + * IOC_READ msg following. (IOC_BUILD + * messages are sometimes followed by + * error messages which are ignored + * on double replies) + */ + if (t_cmmd == IOC_BUILD) + msgcnt += sizeof(struct extmsg) + + (hdrptr + 1)->m_postsize; + + break; + } + reconnect_channel(hdrptr, pnet_addr); + + + break; + } + case IOC_READ_SYNC: + piiu->read_seq++; + break; + + case IOC_RSRV_IS_UP: + LOCK; + { + struct in_addr ina; + + ina.s_addr = (long) t_available; + mark_server_available(&ina); + } + UNLOCK; + break; + + case REPEATER_CONFIRM: + ca_static->ca_repeater_contacted = TRUE; +#ifdef DEBUG + printf("repeater confirmation recv\n"); +#endif + break; + + case IOC_NOT_FOUND: + { + chid chix = (chid) t_available; + struct ioc_in_use *piiu = &iiu[chix->iocix]; + + LOCK; + lstDelete(&piiu->chidlist, chix); + lstAdd(&iiu[BROADCAST_IIU].chidlist, chix); + chix->iocix = BROADCAST_IIU; + if (!piiu->chidlist.count) + close_ioc(piiu); + + /* + * reset the delay to the next retry or keepalive + */ + piiu->next_retry = CA_CURRENT_TIME; + piiu->nconn_tries = 0; + + manage_conn(TRUE); + UNLOCK; + + break; } - /* - * IOC_BUILD messages allways have a IOC_READ msg following. - * (IOC_BUILD messages are sometimes followed by error - * messages which are ignored on double replies) - */ - if(t_cmmd == IOC_BUILD) - msgcnt += sizeof(struct extmsg) + - (hdrptr+1)->m_postsize; - - break; - } + case IOC_CLEAR_CHANNEL: + { + chid chix = (chid) t_available; + struct ioc_in_use *piiu = &iiu[chix->iocix]; + register evid monix; + + + LOCK; + /* + * remove any orphaned get callbacks for this + * channel + */ + for (monix = (evid) pend_read_list.node.next; + monix; + monix = (evid) monix->node.next) + if (monix->chan == chix) { + lstDelete(&pend_read_list, monix); + lstAdd(&free_event_list, monix); + } + lstConcat(&free_event_list, &chix->eventq); + lstDelete(&piiu->chidlist, chix); + if (free(chix) < 0) + abort(); + if (!piiu->chidlist.count) + close_ioc(piiu); + UNLOCK; + break; + } + case IOC_ERROR: + { + char context[255]; + char *name; + struct extmsg *req = hdrptr + 1; + int op; + struct exception_handler_args args; + + + /* + * dont process the message if they have + * disable notification + */ + if (!ca_static->ca_exception_func){ + break; + } + + name = (char *) host_from_addr(pnet_addr); + if (!name){ + name = "an unregistered IOC"; + } + + if (t_postsize > sizeof(struct extmsg)){ + sprintf(context, + "detected by: %s for: %s", + name, + hdrptr + 2); + } + else{ + sprintf(context, "detected by: %s", name); + } + + /* + * Map internal op id to external op id so I + * can freely change the protocol in the + * future. This is quite wasteful of space + * however. + */ + switch (ntohs(req->m_cmmd)) { + case IOC_READ_NOTIFY: + case IOC_READ: + op = CA_OP_GET; + break; + case IOC_WRITE: + op = CA_OP_PUT; + break; + case IOC_SEARCH: + case IOC_BUILD: + op = CA_OP_SEARCH; + break; + case IOC_EVENT_ADD: + op = CA_OP_ADD_EVENT; + break; + case IOC_EVENT_CANCEL: + op = CA_OP_CLEAR_EVENT; + break; + default: + op = CA_OP_OTHER; + break; + } + + args.usr = ca_static->ca_exception_arg; + args.chid = (chid) hdrptr->m_pciu; + args.type = ntohs(req->m_type); + args.count = ntohs(req->m_count); + args.addr = (void *) (req->m_available); + args.stat = ntohl((int) t_available); args.op = op; + args.ctx = context; + (*ca_static->ca_exception_func) (args); + break; + } + default: + printf("post_msg(): Corrupt Cmd in msg %x\n", + t_cmmd); + abort(); + } + + *pbufcnt -= msgcnt; + hdrptr = (struct extmsg *) (msgcnt + (char *) hdrptr); - if(!chan->connection_func && chan->state==cs_never_conn){ - /* decrement the outstanding IO count */ - CLRPENDRECV; } - LOCK; - reconnect_channel(hdrptr,net_addr,piiu); - UNLOCK; - if(chan->connection_func){ - struct connection_handler_args args; + post_msg_active--; - args.chid = chan; - args.op = CA_OP_CONN_UP; - (*chan->connection_func)(args); - } - - break; - } - case IOC_READ_SYNC: - piiu->read_seq++; - break; - - case IOC_RSRV_IS_UP: -# ifdef DEBUG - printf( "IOC on line ->[%s]\n", - host_from_addr(t_available)); -# endif - LOCK; - mark_server_available(t_available); - chid_retry(TRUE); - UNLOCK; - break; - - case REPEATER_CONFIRM: - ca_static->ca_repeater_contacted = TRUE; -# ifdef DEBUG - printf("repeater confirmation\n"); -# endif - break; - - case IOC_NOT_FOUND: - { - chid chix = (chid) t_available; - struct ioc_in_use *piiu = &iiu[chix->iocix]; - - LOCK; - lstDelete(&piiu->chidlist, chix); - lstAdd(&iiu[BROADCAST_IIU].chidlist, chix); - chix->iocix = BROADCAST_IIU; - if(!piiu->chidlist.count) - close_ioc(piiu); - iiu[BROADCAST_IIU].nconn_tries = 0; - chid_retry(TRUE); - UNLOCK; - - break; - } - - case IOC_CLEAR_CHANNEL: - { - chid chix = (chid) t_available; - struct ioc_in_use *piiu = &iiu[chix->iocix]; - register evid monix; - - - LOCK; - /* remove any orphaned get callbacks for this channel */ - for( monix = (evid) pend_read_list.node.next; - monix; - monix = (evid) monix->node.next) - if(monix->chan == chix){ - lstDelete(&pend_read_list, monix); - lstAdd(&free_event_list, monix); - } - - lstConcat(&free_event_list, &chix->eventq); - lstDelete(&piiu->chidlist, chix); - if(free(chix)<0) - abort(); - if(!piiu->chidlist.count) - close_ioc(piiu); - UNLOCK; - break; - } - case IOC_ERROR: - { - char context[255]; - char *name; - struct extmsg *req = hdrptr+1; - int op; - struct exception_handler_args args; - - - /* - * dont process the message if they have disable notification - */ - if(!ca_static->ca_exception_func) - break; - - name = (char *) host_from_addr(net_addr); - if(!name) - name = "an unregistered IOC"; - - if(t_postsize>sizeof(struct extmsg)) - sprintf(context, "detected by: %s for: %s", name, hdrptr+2); - else - sprintf(context, "detected by: %s", name); - - /* - * Map internal op id to external op id so I can freely change the - * protocol in the future. This is quite wasteful of space however. - */ - switch(ntohs(req->m_cmmd)){ - case IOC_READ_NOTIFY: - case IOC_READ: - op = CA_OP_GET; - break; - case IOC_WRITE: - op = CA_OP_PUT; - break; - case IOC_SEARCH: - case IOC_BUILD: - op = CA_OP_SEARCH; - break; - case IOC_EVENT_ADD: - op = CA_OP_ADD_EVENT; - break; - case IOC_EVENT_CANCEL: - op = CA_OP_CLEAR_EVENT; - break; - default: - op = CA_OP_OTHER; - break; - } - - - args.usr = ca_static->ca_exception_arg; /* user arg */ - args.chid = hdrptr->m_pciu; /* the chid if appropriate */ - args.type = ntohs(req->m_type); /* req type if approp */ - args.count = ntohs(req->m_count); /* req count if approp */ - args.addr = (void *) (req->m_available);/* req user addr if approp */ - args.stat = ntohl((int)t_available); /* the CA message code */ - args.op = op; /* the CA operation */ - args.ctx = context; /* context string */ - (*ca_static->ca_exception_func)(args); - break; - } - default: - printf("post_msg(): Corrupt Cmd in msg %x\n",t_cmmd); - abort(); - } - - bufcnt -= msgcnt; - hdrptr = (struct extmsg *) (msgcnt + (char *) hdrptr); - - } - - - post_msg_active--; - -} +} /* @@ -477,10 +540,9 @@ if(t_postsize > (t_count-1) * dbr_value_size[t_type] + dbr_size[t_type]) * LOCK must be on * */ -void reconnect_channel(hdrptr,net_addr,piiu) +static void reconnect_channel(hdrptr,pnet_addr) register struct extmsg *hdrptr; -struct in_addr net_addr; -struct ioc_in_use *piiu; +struct in_addr *pnet_addr; { chid chan = (chid) hdrptr->m_available; unsigned short newiocix; @@ -489,15 +551,17 @@ struct ioc_in_use *piiu; void ca_request_event(); + + LOCK; status = alloc_ioc ( - net_addr, + pnet_addr, IPPROTO_TCP, &newiocix ); if(status != ECA_NORMAL){ printf("... %s ...\n", ca_message(status)); - printf("for %s on %s\n", chan+1, host_from_addr(net_addr)); - printf("ignored broadcast reply- proceeding\n"); + printf("for %s on %s\n", chan+1, host_from_addr(pnet_addr)); + printf("ignored search reply- proceeding\n"); return; } @@ -531,7 +595,7 @@ struct ioc_in_use *piiu; pevent = (evid) pevent->node.next) if(pevent->chan == chan){ issue_get_callback(pevent); - send_msg(); + cac_send_msg(); } } #endif @@ -542,8 +606,23 @@ struct ioc_in_use *piiu; pevent; pevent = (evid)pevent->node.next) ca_request_event(pevent); - send_msg(); + cac_send_msg(); } + + UNLOCK; + + if(chan->connection_func){ + struct connection_handler_args args; + + args.chid = chan; + args.op = CA_OP_CONN_UP; + (*chan->connection_func)(args); + } + else if(chan->state==cs_never_conn){ + /* decrement the outstanding IO count */ + CLRPENDRECV; + } + chan->state = cs_conn; } diff --git a/src/ca/test_event.c b/src/ca/test_event.c index db00a4d79..ee8b274ca 100644 --- a/src/ca/test_event.c +++ b/src/ca/test_event.c @@ -1,3 +1,18 @@ +/* + * + * T E S T _ E V E N T . C + * Author: Jeffrey O. Hill + * simple stub for testing monitors + * + * + * History + * joh 031891 printed type in decimanl instead of hex + * + * + * + * + */ + /* System includes */ #include @@ -8,22 +23,33 @@ void ca_test_event(args) struct event_handler_args args; { - printf("~~~### in test event for [%s] ###~~~\n",args.chid+1); printf("User argument\t%x\n", args.usr); - printf("Native channel data type\t%x\n", args.chid->type); - printf("Monitor data type\t%x\n", args.type); + printf("Native channel data type\t%d\n", args.chid->type); + printf("Monitor data type\t%d\n", args.type); switch(args.type){ case DBR_STRING: printf("Value:\t<%s>\n",args.dbr); break; + case DBR_CHAR: + printf("Value:\t<%d>\n",*(char *)args.dbr); + break; +#if DBR_INT != DBR_SHORT case DBR_INT: +#endif + case DBR_SHORT: case DBR_ENUM: - printf("Value:\t<%d>\n",*(int *)args.dbr); + printf("Value:\t<%d>\n",*(short *)args.dbr); + break; + case DBR_LONG: + printf("Value:\t<%d>\n",*(long *)args.dbr); break; case DBR_FLOAT: printf("Value:\t<%f>\n",*(float *)args.dbr); break; + case DBR_DOUBLE: + printf("Value:\t<%f>\n",*(double *)args.dbr); + break; case DBR_STS_STRING: printf("Value:\t<%s>\n",((struct dbr_sts_string *)args.dbr)->value); break; @@ -39,7 +65,6 @@ struct event_handler_args args; case DBR_GR_FLOAT: printf("Value:\t<%f>\n",((struct dbr_gr_float *)args.dbr)->value); break; - default: printf( "Sorry test_event does not handle data type %d yet\n", args.type); diff --git a/src/db/db_access.c b/src/db/db_access.c index 35c20df0a..439d8cadc 100644 --- a/src/db/db_access.c +++ b/src/db/db_access.c @@ -29,7 +29,7 @@ * * Modification Log: * ----------------- - * .01 mm-dd-yy iii Comment + * .01 06-25-91 joh inserted the RISC aligned db_access.h structures */ @@ -110,28 +110,16 @@ /* function declarations */ +/* + * database access address structure + */ +#include -/* database access address structure (removed from db_access.h and put here) */ -struct db_addr{ - char *precord; /* record number of specified type */ - char *pfield; /* offset from the record origin */ - char *pad0; /* not used by old */ - short pad1; /*not used by old */ - short no_elements; /* number of elements in arrays of data */ - short record_type; /* type of record being accessed */ - short pad2; /* not used by old */ - short field_size; /* size of the field being accessed */ - /* from database for values of waveforms */ - short special; /* special processing */ - short choice_set; /* index of choiceSet GBLCHOICE & RECCHOICE*/ - short field_type; /* field type as seen by database request*/ - /*DBR_STRING,...,DBR_ENUM,DBR_NOACCESS*/ -}; - - - -/* structures for old database access */ +#ifndef MAX_STRING_SIZE +#define MAX_STRING_SIZE 40 +#endif + /* VALUES WITH STATUS STRUCTURES */ /* structure for a string status field */ @@ -169,9 +157,10 @@ struct dbr_sts_enum{ /* structure for a char status field */ struct dbr_sts_char{ - short status; /* status of value */ - short severity; /* severity of alarm */ - unsigned char value; /* current value */ + short status; /* status of value */ + short severity; /* severity of alarm */ + char RISC_pad; /* RISC alignment */ + unsigned char value; /* current value */ }; /* structure for a long status field */ @@ -185,6 +174,7 @@ struct dbr_sts_long{ struct dbr_sts_double{ short status; /* status of value */ short severity; /* severity of alarm */ + long RISC_pad; /* RISC alignment */ double value; /* current value */ }; @@ -203,6 +193,7 @@ struct dbr_time_short{ short status; /* status of value */ short severity; /* severity of alarm */ TS_STAMP stamp; /* time stamp */ + short RISC_pad; /* RISC alignment */ short value; /* current value */ }; @@ -219,6 +210,7 @@ struct dbr_time_enum{ short status; /* status of value */ short severity; /* severity of alarm */ TS_STAMP stamp; /* time stamp */ + short RISC_pad; /* RISC alignment */ short value; /* current value */ }; @@ -227,6 +219,8 @@ struct dbr_time_char{ short status; /* status of value */ short severity; /* severity of alarm */ TS_STAMP stamp; /* time stamp */ + short RISC_pad0; /* RISC alignment */ + char RISC_pad1; /* RISC alignment */ unsigned char value; /* current value */ }; @@ -243,6 +237,7 @@ struct dbr_time_double{ short status; /* status of value */ short severity; /* severity of alarm */ TS_STAMP stamp; /* time stamp */ + long RISC_pad; /* RISC alignment */ double value; /* current value */ }; @@ -282,6 +277,7 @@ struct dbr_gr_float{ short status; /* status of value */ short severity; /* severity of alarm */ short precision; /* number of decimal places */ + short RISC_pad0; /* RISC alignment */ char units[8]; /* units of value */ float upper_disp_limit; /* upper limit of graph */ float lower_disp_limit; /* lower limit of graph */ @@ -303,16 +299,17 @@ struct dbr_gr_enum{ /* structure for a graphic char field */ struct dbr_gr_char{ - short status; /* status of value */ - short severity; /* severity of alarm */ - char units[8]; /* units of value */ - unsigned char upper_disp_limit; /* upper limit of graph */ - unsigned char lower_disp_limit; /* lower limit of graph */ - unsigned char upper_alarm_limit; - unsigned char upper_warning_limit; - unsigned char lower_warning_limit; - unsigned char lower_alarm_limit; - unsigned char value; /* current value */ + short status; /* status of value */ + short severity; /* severity of alarm */ + char units[8]; /* units of value */ + unsigned char upper_disp_limit; /* upper limit of graph */ + unsigned char lower_disp_limit; /* lower limit of graph */ + unsigned char upper_alarm_limit; + unsigned char upper_warning_limit; + unsigned char lower_warning_limit; + unsigned char lower_alarm_limit; + char RISC_pad; /* RISC alignment */ + unsigned char value; /* current value */ }; /* structure for a graphic long field */ @@ -334,6 +331,7 @@ struct dbr_gr_double{ short status; /* status of value */ short severity; /* severity of alarm */ short precision; /* number of decimal places */ + short RISC_pad0; /* RISC alignment */ char units[8]; /* units of value */ double upper_disp_limit; /* upper limit of graph */ double lower_disp_limit; /* lower limit of graph */ @@ -384,6 +382,7 @@ struct dbr_ctrl_float{ short status; /* status of value */ short severity; /* severity of alarm */ short precision; /* number of decimal places */ + short RISC_pad; /* RISC alignment */ char units[8]; /* units of value */ float upper_disp_limit; /* upper limit of graph */ float lower_disp_limit; /* lower limit of graph */ @@ -418,6 +417,7 @@ struct dbr_ctrl_char{ unsigned char lower_alarm_limit; unsigned char upper_ctrl_limit; /* upper control limit */ unsigned char lower_ctrl_limit; /* lower control limit */ + char RISC_pad; /* RISC alignment */ unsigned char value; /* current value */ }; @@ -442,6 +442,7 @@ struct dbr_ctrl_double{ short status; /* status of value */ short severity; /* severity of alarm */ short precision; /* number of decimal places */ + short RISC_pad0; /* RISC alignment */ char units[8]; /* units of value */ double upper_disp_limit; /* upper limit of graph */ double lower_disp_limit; /* lower limit of graph */ @@ -455,6 +456,8 @@ struct dbr_ctrl_double{ }; + + /* From $cs/dblib/src/dbiocsubs.c * subroutines diff --git a/src/rsrv/camessage.c b/src/rsrv/camessage.c index 39370c1dd..d24969518 100644 --- a/src/rsrv/camessage.c +++ b/src/rsrv/camessage.c @@ -41,7 +41,6 @@ #include #include #include -#include #include @@ -58,6 +57,7 @@ void event_cancel_reply(); void clear_channel_reply(); void send_err(); void log_header(); +void search_fail_reply(); /* @@ -397,7 +397,7 @@ read_reply(pevext, paddr, hold, pfl) FAST struct event_ext *pevext; FAST struct db_addr *paddr; int hold; /* more on the way if true */ -db_field_log *pfl; +void *pfl; { FAST struct extmsg *mp = pevext->mp; FAST struct client *client = pevext->client; @@ -508,7 +508,6 @@ build_reply(mp, client) struct db_addr tmp_addr; FAST struct channel_in_use *pchannel; - void search_fail_reply(); /* Exit quickly if channel not on this node */ diff --git a/src/rsrv/cast_server.c b/src/rsrv/cast_server.c index 497288cd5..11640e4ef 100644 --- a/src/rsrv/cast_server.c +++ b/src/rsrv/cast_server.c @@ -1,26 +1,46 @@ -/* The IOC connection request server */ -/* -******************************************************************************* -** GTA PROJECT -** Copyright 1988, The Regents of the University of California. -** Los Alamos National Laboratory -** Los Alamos New Mexico 87845 -** cast_server.c - GTA request server main loop -** Sun UNIX 4.2 Release 3.4 -** First Release- Jeff Hill May 88 -** -** -** -** FIXES NEEDED: -** -** Dont send channel found message unless there is memory, a task slot, -** and a TCP socket available. Send a diagnostic instead. -** Or ... make the timeout shorter? This is only a problem if -** they persist in trying to make a connection after getting no -** response. -** -******************************************************************************* -*/ +/* @(#)cast_server.c + * $Id$ + * Author: Jeffrey O. Hill + * hill@luke.lanl.gov + * (505) 665 1831 + * Date: 5-88 + * + * Experimental Physics and Industrial Control System (EPICS) + * + * Copyright 1991, the Regents of the University of California, + * and the University of Chicago Board of Governors. + * + * This software was produced under U.S. Government contracts: + * (W-7405-ENG-36) at the Los Alamos National Laboratory, + * and (W-31-109-ENG-38) at Argonne National Laboratory. + * + * Initial development by: + * The Controls and Automation Group (AT-8) + * Ground Test Accelerator + * Accelerator Technology Division + * Los Alamos National Laboratory + * + * Co-developed with + * The Controls and Computing Group + * Accelerator Systems Division + * Advanced Photon Source + * Argonne National Laboratory + * + * Modification Log: + * ----------------- + * .00 joh 030191 Fixed cast server to not block on TCP + * .01 joh 030891 now reuses old client structure + * .02 joh 032091 allways flushes if the client changes and the old + * client has a TCP connection.(bug introduced by .00) + * + * Improvements + * ------------ + * Dont send channel found message unless there is memory, a task slot, + * and a TCP socket available. Send a diagnostic instead. + * Or ... make the timeout shorter? This is only a problem if + * they persist in trying to make a connection after getting no + * response. + */ #include #include @@ -33,230 +53,288 @@ #include #include - -STATUS + +/* + * CAST_SERVER + * + * service UDP messages + * + */ +void cast_server() { - struct sockaddr_in sin; - FAST int status; - int i; - FAST struct client *client; - FAST struct client *tmpclient = NULL; - struct sockaddr_in recv_addr; - int recv_addr_size = sizeof(recv_addr); - unsigned nchars; - static struct message_buffer udp_msg; -# define TIMEOUT 60 /* sec */ - unsigned long timeout = TIMEOUT * sysClkRateGet(); + struct sockaddr_in sin; + FAST int status; + int count; + FAST struct client *client = NULL; + FAST struct client *true_client = NULL; + FAST struct client *temp_client; + struct sockaddr_in recv_addr; + int recv_addr_size = sizeof(recv_addr); + unsigned nchars; +# define TIMEOUT 60 /* sec */ + unsigned long timeout = TIMEOUT*sysClkRateGet(); + static struct message_buffer udp_msg; - struct client *existing_client(); - struct client *create_udp_client(); - void rsrv_online_notify_task(); + struct client *existing_client(); + struct client *create_udp_client(); + void rsrv_online_notify_task(); - if( IOC_cast_sock!=0 && IOC_cast_sock!=ERROR ) - if( (status = close(IOC_cast_sock)) == ERROR ) - logMsg("Unable to close open master socket\n"); + if( IOC_cast_sock!=0 && IOC_cast_sock!=ERROR ) + if( (status = close(IOC_cast_sock)) == ERROR ) + logMsg("Unable to close open master socket\n"); - /* - * Open the socket. - * Use ARPA Internet address format and datagram socket. - * Format described in . - */ + /* + * Open the socket. + * Use ARPA Internet address format and datagram socket. + * Format described in . + */ - if((IOC_cast_sock = socket (AF_INET, SOCK_DGRAM, 0)) == ERROR){ - logMsg("Socket creation error\n"); - printErrno (errnoGet ()); - taskSuspend(0); - } + if((IOC_cast_sock = socket (AF_INET, SOCK_DGRAM, 0)) == ERROR){ + logMsg("Socket creation error\n"); + printErrno (errnoGet ()); + taskSuspend(0); + } - /* Zero the sock_addr structure */ - bfill(&sin, sizeof(sin), 0); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = INADDR_ANY; - sin.sin_port = CA_SERVER_PORT; + /* Zero the sock_addr structure */ + bfill(&sin, sizeof(sin), 0); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = INADDR_ANY; + sin.sin_port = CA_SERVER_PORT; - /* get server's Internet address */ - if (bind (IOC_cast_sock, &sin, sizeof (sin)) == ERROR){ - logMsg("Bind error\n"); - printErrno (errnoGet ()); - close (IOC_cast_sock); - taskSuspend(0); - } + /* get server's Internet address */ + if( bind(IOC_cast_sock, &sin, sizeof (sin)) == ERROR){ + logMsg("Bind error\n"); + printErrno (errnoGet ()); + close (IOC_cast_sock); + taskSuspend(0); + } - bfill(&udp_msg, sizeof(udp_msg), NULL); + bfill(&udp_msg, sizeof(udp_msg), NULL); - /* tell clients we are on line again */ - status = taskSpawn( - CA_ONLINE_NAME, - CA_ONLINE_PRI, - CA_ONLINE_OPT, - CA_ONLINE_STACK, - rsrv_online_notify_task); - if(status<0){ - logMsg("Cast_server: couldnt start up online notify task\n"); - printErrno(errnoGet ()); - } + /* tell clients we are on line again */ + status = taskSpawn( + CA_ONLINE_NAME, + CA_ONLINE_PRI, + CA_ONLINE_OPT, + CA_ONLINE_STACK, + rsrv_online_notify_task); + if(status<0){ + logMsg("Cast_server: couldnt start up online notify task\n"); + printErrno(errnoGet ()); + } - while(TRUE){ + while(TRUE){ - status = recvfrom( IOC_cast_sock, - &udp_msg.cnt, - sizeof(udp_msg.cnt)+sizeof(udp_msg.buf), + /* + * setup new client structure but reuse old structure if + * possible + * + */ + if(!client){ + client = create_udp_client(IOC_cast_sock); + if(!client){ + taskDelay(sysClkRateGet()*60*5); + continue; + } + } + + status = recvfrom( + IOC_cast_sock, + udp_msg.buf, + sizeof(udp_msg.buf), NULL, &recv_addr, &recv_addr_size); - if(status<0){ - logMsg("Cast_server: UDP recv error\n"); - printErrno(errnoGet ()); - taskSuspend(0); - } + if(status<0){ + logMsg("Cast_server: UDP recv error\n"); + printErrno(errnoGet ()); + taskSuspend(0); + } - if(status != udp_msg.cnt){ - logMsg("Cast_server: Recieved a corrupt broadcast\n"); - continue; - } + udp_msg.cnt = status; + udp_msg.stk = 0; + /* + * If we are talking to a new client flush the old one + * in case it is holding UDP messages for a + * TCP connected client - waiting to see if the + * next message is for this same client. + * (replies to broadcasts are not returned over + * an existing TCP connection to avoid a TCP + * pend which could lock up the cast server). + */ + if( client->valid_addr && + (client->addr.sin_addr.s_addr != + recv_addr.sin_addr.s_addr || + client->addr.sin_port != recv_addr.sin_port)){ + cas_send_msg(client, TRUE); + } + client->addr = recv_addr; + client->valid_addr = TRUE; + if(MPDEBUG==2){ + logMsg( "cast_server(): msg of %d bytes\n", + status); + logMsg( "from addr %x, port %x \n", + recv_addr.sin_addr, + recv_addr.sin_port); + } - if(MPDEBUG==2){ - logMsg( "cast_server(): recieved a broadcast of %d bytes\n", status); - logMsg( "from addr %x, port %x \n", - recv_addr.sin_addr, - recv_addr.sin_port); - } + if(MPDEBUG==3) + count = client->addrq.count; - /* subtract header size */ - udp_msg.cnt -= sizeof(udp_msg.cnt); + /* + * check for existing client occurs after + * message process so that this thread never + * blocks sending TCP + */ + status = camessage(client, &udp_msg); + if(status == OK){ + if(udp_msg.cnt != udp_msg.stk){ + printf( "CA UDP Message OF %d\n", + udp_msg.cnt-udp_msg.stk); + } + } - /* setup new client structure but, reuse old structure if possible */ - LOCK_CLIENTQ; - client = existing_client(&recv_addr); - if(!client){ - if(tmpclient){ - client = tmpclient; - tmpclient = NULL; - } - else - client = create_udp_client(IOC_cast_sock); - if(!client){ - UNLOCK_CLIENTQ; - continue; - } + if(client->addrq.count){ + LOCK_CLIENTQ; - client->addr = recv_addr; - client->ticks_at_creation = tickGet(); - lstAdd(&clientQ, client); - } + true_client = existing_client(&client->addr); + if(true_client == NULL){ + client->ticks_at_creation = tickGet(); + lstAdd(&clientQ, client); + client = NULL; + }else{ + lstConcat( + &true_client->addrq, + &client->addrq); + } - if(MPDEBUG==2) - i = client->addrq.count; + UNLOCK_CLIENTQ; - message_process(client, &udp_msg); + if(MPDEBUG==3){ + logMsg( "Fnd %d name matches (%d tot)\n", + client->addrq.count-count, + client->addrq.count); + } + } - /* remove client data structure from list if channel not found */ - if(client->addrq.count){ - if(MPDEBUG==2) - logMsg( "Found %d new channel name matches (%d cumulative)\n", - client->addrq.count-i, - client->addrq.count); - } - else{ - lstDelete(&clientQ, client); - if(!tmpclient) - tmpclient = client; - else - free(client); - } + /* + * allow message to batch up if more are comming + */ + status = ioctl(IOC_cast_sock, FIONREAD, &nchars); + if(status == ERROR){ + printErrno(errnoGet(0)); + taskSuspend(0); + } - /* - allow message to batch up if more are comming - */ - status = ioctl(IOC_cast_sock, FIONREAD, &nchars); - if(status == ERROR){ - printErrno(errnoGet(0)); - taskSuspend(0); - } - if(nchars == 0){ - client = (struct client *) &clientQ; - while(client = (struct client *) client->node.next) - send_msg(client); + if(nchars == 0){ + if(client) + cas_send_msg(client, TRUE); - clean_clientq(timeout); - } - UNLOCK_CLIENTQ; + /* + * catch any that have not been sent yet + */ + LOCK_CLIENTQ; + temp_client = (struct client *) &clientQ; + while(temp_client = (struct client *) + temp_client->node.next){ + if(temp_client->proto == IPPROTO_UDP) + cas_send_msg(temp_client, TRUE); + } - } + clean_clientq(timeout); + UNLOCK_CLIENTQ; + } + } } - -struct client -*create_udp_client(sock) + +/* + * CREATE_UDP_CLIENT + * + * + */ +struct client *create_udp_client(sock) unsigned sock; { - struct client *client; + struct client *client; - client = (struct client *)malloc(sizeof(struct client)); - if(!client){ - printErrno(errnoGet ()); - return NULL; - } + LOCK_CLIENTQ; + client = (struct client *)lstGet(&rsrv_free_clientQ); + UNLOCK_CLIENTQ; - if(MPDEBUG==2) - logMsg( "cast_server(): Creating data structures for new udp client\n"); + if(!client){ + client = (struct client *)malloc(sizeof(struct client)); + if(!client){ + logMsg("CA: no mem for another client\n"); + printErrno(errnoGet ()); + return NULL; + } + } -/* - The following inits to zero done instead of a bfill since - the send and recv buffers are large and don't need initialization. + if(MPDEBUG==3) + logMsg( "cast_server(): Creating new udp client\n"); - bfill(client, sizeof(*client), NULL); -*/ - lstInit(&client->addrq); - client->tid = 0; - client->send.stk = 0; - client->send.cnt = 0; - client->recv.stk = 0; - client->recv.cnt = 0; - client->evuser = NULL; - client->eventsoff = FALSE; + /* + The following inits to zero done instead of a bfill since + the send and recv buffers are large and don't need initialization. - client->proto = IPPROTO_UDP; - client->send.maxstk = MAX_UDP-sizeof(client->recv.cnt); - FASTLOCKINIT(&client->send.lock); + bfill(client, sizeof(*client), NULL); + */ + lstInit(&client->addrq); + client->tid = 0; + client->send.stk = 0; + client->send.cnt = 0; + client->recv.stk = 0; + client->recv.cnt = 0; + client->evuser = NULL; + client->eventsoff = FALSE; + client->valid_addr = FALSE; + client->disconnect = FALSE; /* for TCP only */ - client->recv.maxstk = MAX_UDP; - FASTLOCKINIT(&client->recv.lock); + client->proto = IPPROTO_UDP; + client->send.maxstk = MAX_UDP-sizeof(client->recv.cnt); + FASTLOCKINIT(&client->send.lock); - client->sock = sock; + client->recv.maxstk = MAX_UDP; + FASTLOCKINIT(&client->recv.lock); - return client; + client->sock = sock; + + return client; } + /* - send lock must be applied - -*/ -udp_to_tcp(client,sock) + * UDP_TO_TCP + * + * send lock must be applied + * + */ +int udp_to_tcp(client,sock) struct client *client; unsigned sock; { - if(MPDEBUG==2) - logMsg("cast_server(): converting udp client to tcp\n"); + if(MPDEBUG==3) + logMsg("cast_server(): converting udp client to tcp\n"); - client->proto = IPPROTO_TCP; - client->send.maxstk = MAX_TCP; - client->recv.maxstk = MAX_TCP; - client->sock = sock; + client->proto = IPPROTO_TCP; + client->send.maxstk = MAX_TCP; + client->recv.maxstk = MAX_TCP; + client->sock = sock; - return OK; + return OK; } diff --git a/src/rsrv/globalsource.c b/src/rsrv/globalsource.c index 808be961c..17bd80df3 100644 --- a/src/rsrv/globalsource.c +++ b/src/rsrv/globalsource.c @@ -1,17 +1,36 @@ -/* -******************************************************************************* -** GTA PROJECT -** Copyright 1988, The Regents of the University of California. -** Los Alamos National Laboratory -** Los Alamos New Mexico 87845 -** inmsgtask0.c - GTA request server message reader task. -** Sun UNIX 4.2 Release 3.4 -** Bob Dingler February 11, 1988 -******************************************************************************* -*/ +/* @(#)globalsource.c + * $Id$ + * Author: Jeffrey O. Hill + * hill@luke.lanl.gov + * (505) 665 1831 + * Date: 5-88 + * + * Experimental Physics and Industrial Control System (EPICS) + * + * Copyright 1991, the Regents of the University of California, + * and the University of Chicago Board of Governors. + * + * This software was produced under U.S. Government contracts: + * (W-7405-ENG-36) at the Los Alamos National Laboratory, + * and (W-31-109-ENG-38) at Argonne National Laboratory. + * + * Initial development by: + * The Controls and Automation Group (AT-8) + * Ground Test Accelerator + * Accelerator Technology Division + * Los Alamos National Laboratory + * + * Co-developed with + * The Controls and Computing Group + * Accelerator Systems Division + * Advanced Photon Source + * Argonne National Laboratory + * + * Modification Log: + * ----------------- + */ #define GLBLSOURCE - #include #include #include diff --git a/src/rsrv/online_notify.c b/src/rsrv/online_notify.c index c96abd9e2..223a38636 100644 --- a/src/rsrv/online_notify.c +++ b/src/rsrv/online_notify.c @@ -1,11 +1,37 @@ /* * O N L I N E _ N O T I F Y . C + * * tell CA clients this a server has joined the network * - * Author: Jeffrey O. Hill + * @(#)online_notify.c + * $Id$ + * Author: Jeffrey O. Hill + * hill@luke.lanl.gov + * (505) 665 1831 + * Date: 103090 * - * Hisory - * .00 103090 joh First release + * Experimental Physics and Industrial Control System (EPICS) + * + * Copyright 1991, the Regents of the University of California, + * and the University of Chicago Board of Governors. + * + * This software was produced under U.S. Government contracts: + * (W-7405-ENG-36) at the Los Alamos National Laboratory, + * and (W-31-109-ENG-38) at Argonne National Laboratory. + * + * Initial development by: + * The Controls and Automation Group (AT-8) + * Ground Test Accelerator + * Accelerator Technology Division + * Los Alamos National Laboratory + * + * Co-developed with + * The Controls and Computing Group + * Accelerator Systems Division + * Advanced Photon Source + * Argonne National Laboratory + * + * History */ /* @@ -17,17 +43,13 @@ #include /* - * LAACS includes + * EPICS includes */ #include #include #define abort taskSuspend -struct complete_msg{ - unsigned length; - struct extmsg extmsg; -}; /* * RSRV_ONLINE_NOTIFY_TASK @@ -45,7 +67,7 @@ void rsrv_online_notify_task() * CA_ONLINE_DELAY [sec] max delay */ unsigned long maxdelay = CA_ONLINE_DELAY * sysClkRateGet(); - struct complete_msg msg; + struct extmsg msg; struct sockaddr_in send_addr; struct sockaddr_in recv_addr; @@ -90,9 +112,8 @@ void rsrv_online_notify_task() abort(0); bfill(&msg, sizeof msg, NULL); - msg.length = htonl(sizeof msg); - msg.extmsg.m_cmmd = htons(IOC_RSRV_IS_UP); - msg.extmsg.m_available = lcl.sin_addr.s_addr; + msg.m_cmmd = htons(IOC_RSRV_IS_UP); + msg.m_available = lcl.sin_addr.s_addr; /* Zero the sock_addr structure */ bfill(&send_addr, sizeof send_addr, 0); @@ -101,8 +122,6 @@ void rsrv_online_notify_task() send_addr.sin_port = htons(CA_CLIENT_PORT); while(TRUE){ - - status = sendto( sock, &msg, @@ -120,38 +139,3 @@ void rsrv_online_notify_task() } - - - - - - - -#ifdef JUNKYARD - client = create_udp_client(sock); - client->addr = send_addr; - client->ticks_at_creation = tickGet(); - - while(TRUE){ - reply = (struct extmsg *) ALLOC_MSG(client, 0); - if(!reply) - abort(0); - - - bfill(reply, sizeof(*reply), NULL); - reply->m_cmmd = IOC_RSRV_IS_UP; - reply->m_available = lcl.sin_addr.s_addr; - reply->m_postsize = 0; - - END_MSG(client); - send_msg(client); - - taskDelay(delay); - delay = delay << 1; - } -/* - Should it need to quit.... - - free_one_client(client); -*/ -#endif diff --git a/src/rsrv/rsrv_init.c b/src/rsrv/rsrv_init.c index 5eae0ffba..9ae5f8bc1 100644 --- a/src/rsrv/rsrv_init.c +++ b/src/rsrv/rsrv_init.c @@ -1,3 +1,34 @@ +/* @(#)rsrv_init.c + * $Id$ + * Author: Jeffrey O. Hill + * hill@luke.lanl.gov + * (505) 665 1831 + * Date: 5-88 + * + * Experimental Physics and Industrial Control System (EPICS) + * + * Copyright 1991, the Regents of the University of California, + * and the University of Chicago Board of Governors. + * + * This software was produced under U.S. Government contracts: + * (W-7405-ENG-36) at the Los Alamos National Laboratory, + * and (W-31-109-ENG-38) at Argonne National Laboratory. + * + * Initial development by: + * The Controls and Automation Group (AT-8) + * Ground Test Accelerator + * Accelerator Technology Division + * Los Alamos National Laboratory + * + * Co-developed with + * The Controls and Computing Group + * Accelerator Systems Division + * Advanced Photon Source + * Argonne National Laboratory + * + * Modification Log: + * ----------------- + */ #include #include #include @@ -11,35 +42,40 @@ #define DELETE_TASK(TID)\ if(errnoOfTaskGet(TID)!=ERROR)td(TID); + +/* + * rsrv_init() + * + * + * + */ rsrv_init() { - FAST struct client *client; - void req_server(); - void cast_server(); + FAST struct client *client; - FASTLOCKINIT(&rsrv_free_addrq_lck); - FASTLOCKINIT(&rsrv_free_eventq_lck); - FASTLOCKINIT(&clientQlock); + FASTLOCKINIT(&rsrv_free_addrq_lck); + FASTLOCKINIT(&rsrv_free_eventq_lck); + FASTLOCKINIT(&clientQlock); - /* - the following is based on the assumtion that external variables - are not reloaded when debugging. - NOTE: NULL below specifies all clients - */ - free_client(NULL); + /* + * the following is based on the assumtion that external variables + * are not reloaded when debugging. NOTE: NULL below specifies all + * clients + */ + free_client(NULL); - DELETE_TASK(taskNameToId(CAST_SRVR_NAME)); - DELETE_TASK(taskNameToId(REQ_SRVR_NAME)); - taskSpawn( REQ_SRVR_NAME, - REQ_SRVR_PRI, - REQ_SRVR_OPT, - REQ_SRVR_STACK, - req_server); + DELETE_TASK(taskNameToId(CAST_SRVR_NAME)); + DELETE_TASK(taskNameToId(REQ_SRVR_NAME)); + taskSpawn(REQ_SRVR_NAME, + REQ_SRVR_PRI, + REQ_SRVR_OPT, + REQ_SRVR_STACK, + req_server); - taskSpawn( CAST_SRVR_NAME, - CAST_SRVR_PRI, - CAST_SRVR_OPT, - CAST_SRVR_STACK, - cast_server); + taskSpawn(CAST_SRVR_NAME, + CAST_SRVR_PRI, + CAST_SRVR_OPT, + CAST_SRVR_STACK, + cast_server); } diff --git a/src/rsrv/server.h b/src/rsrv/server.h index b72b0877b..be08ec20f 100644 --- a/src/rsrv/server.h +++ b/src/rsrv/server.h @@ -1,12 +1,54 @@ +/* @(#)server.h + * $Id$ + * Author: Jeffrey O. Hill + * hill@luke.lanl.gov + * (505) 665 1831 + * Date: 5-88 + * + * Experimental Physics and Industrial Control System (EPICS) + * + * Copyright 1991, the Regents of the University of California, + * and the University of Chicago Board of Governors. + * + * This software was produced under U.S. Government contracts: + * (W-7405-ENG-36) at the Los Alamos National Laboratory, + * and (W-31-109-ENG-38) at Argonne National Laboratory. + * + * Initial development by: + * The Controls and Automation Group (AT-8) + * Ground Test Accelerator + * Accelerator Technology Division + * Los Alamos National Laboratory + * + * Co-developed with + * The Controls and Computing Group + * Accelerator Systems Division + * Advanced Photon Source + * Argonne National Laboratory + * + * Modification Log: + * ----------------- + * .01 joh 060691 removed 4 byte count from the beginning of + * of each message + * .02 joh 060791 moved send_msg stuff into caserverio.c + * + */ #ifndef INCLfast_lockh #include #endif -#include +#ifndef INCLdb_accessh +#include +#endif + +#ifndef INClstLibh +#include +#endif + +#ifndef __IOCMSG__ +#include +#endif -/* buf & cnt must be contiguous */ -/* cnt must be first */ -/* buf must be second */ struct message_buffer{ unsigned stk; @@ -25,9 +67,11 @@ struct client{ struct message_buffer recv; struct sockaddr_in addr; void *evuser; - char eventsoff; unsigned long ticks_at_creation; /* for UDP timeout */ int tid; + char eventsoff; + char valid_addr; + char disconnect; /* disconnect detected */ }; @@ -69,7 +113,8 @@ LOCAL keyed; GLBLTYPE int IOC_sock; GLBLTYPE int IOC_cast_sock; -GLBLTYPE LIST clientQ; +GLBLTYPE LIST clientQ; /* locked by clientQlock */ +GLBLTYPE LIST rsrv_free_clientQ; /* locked by clientQlock */ GLBLTYPE FAST_LOCK clientQlock; GLBLTYPE int MPDEBUG; GLBLTYPE LIST rsrv_free_addrq; @@ -86,43 +131,25 @@ FASTUNLOCK(&(CLIENT)->send.lock); #define EXTMSGPTR(CLIENT)\ ((struct extmsg *) &(CLIENT)->send.buf[(CLIENT)->send.stk]) -#define ALLOC_MSG(CLIENT, EXTSIZE)\ - (struct extmsg *)\ - ((CLIENT)->send.stk + (EXTSIZE) + sizeof(struct extmsg) > \ - (CLIENT)->send.maxstk ? send_msg_nolock(CLIENT): NULL,\ - (CLIENT)->send.stk + (EXTSIZE) + sizeof(struct extmsg) >\ - (CLIENT)->send.maxstk ? NULL : EXTMSGPTR(CLIENT)) +/* + * ALLOC_MSG get a ptr to space in the buffer + * END_MSG push a message onto the buffer stack + * + */ +#define ALLOC_MSG(CLIENT, EXTSIZE) cas_alloc_msg(CLIENT, EXTSIZE) #define END_MSG(CLIENT)\ + EXTMSGPTR(CLIENT)->m_postsize = CA_MESSAGE_ALIGN(EXTMSGPTR(CLIENT)->m_postsize),\ (CLIENT)->send.stk += sizeof(struct extmsg) + EXTMSGPTR(CLIENT)->m_postsize -/* send with lock */ -#define send_msg(CLIENT)\ - {LOCK_SEND(CLIENT); send_msg_nolock(CLIENT); UNLOCK_SEND(CLIENT)}; -/* send with empty test */ -#define send_msg_nolock(CLIENT)\ -!(CLIENT)->send.stk ? FALSE: send_msg_actual(CLIENT) +#define LOCK_CLIENTQ FASTLOCK(&clientQlock) -/* vanilla send */ -#define send_msg_actual(CLIENT)\ -(\ - (CLIENT)->send.cnt = (CLIENT)->send.stk + sizeof((CLIENT)->send.cnt),\ - (CLIENT)->send.stk = 0,\ - MPDEBUG==2?logMsg("Sent a message of %d bytes\n",(CLIENT)->send.cnt):NULL,\ - sendto ( (CLIENT)->sock, \ - &(CLIENT)->send.cnt, \ - (CLIENT)->send.cnt, \ - 0,\ - &(CLIENT)->addr,\ - sizeof((CLIENT)->addr))==ERROR?LOG_SEND_ERROR,FALSE:TRUE\ -) +#define UNLOCK_CLIENTQ FASTUNLOCK(&clientQlock) -#define LOG_SEND_ERROR \ - (logMsg("Send_msg() unable to send, connection broken? %\n")) - -#define LOCK_CLIENTQ \ - FASTLOCK(&clientQlock) - -#define UNLOCK_CLIENTQ \ - FASTUNLOCK(&clientQlock) +struct client *existing_client(); +void camsgtask(); +void req_server(); +void cast_server(); +void cas_send_msg(); +struct extmsg *cas_alloc_msg();