From e87bbef75c0ac0f281842d3a7efd043fb21c9014 Mon Sep 17 00:00:00 2001 From: Michael Abbott Date: Wed, 11 Aug 2010 16:38:49 -0500 Subject: [PATCH] Update rsrv to support V4.13 protocol extension. The rsrv server is updated in this commit to deliver variable sized waveforms in response to a zero length request, implementing an extension to the v4 EPICS protocol tied to minor version 13. The core of the changes are in read_reply, rsrv/camessage.c, which first reserves packet space for the largest possible response, but then resizes the packet according to how much data is actually returned from the database. --- src/ca/db_access.h | 6 +- src/db/db_access.c | 347 +++++++++--------------------------- src/db/db_access_routines.h | 3 + src/rsrv/camessage.c | 85 ++++----- src/rsrv/caserverio.c | 14 ++ src/rsrv/server.h | 3 +- 6 files changed, 153 insertions(+), 305 deletions(-) diff --git a/src/ca/db_access.h b/src/ca/db_access.h index e88a929d0..92aa5d011 100644 --- a/src/ca/db_access.h +++ b/src/ca/db_access.h @@ -524,16 +524,16 @@ struct dbr_ctrl_double{ dbr_double_t value; /* current value */ }; -#ifndef db_accessHFORdb_accessC #define dbr_size_n(TYPE,COUNT)\ ((unsigned)((COUNT)<=0?dbr_size[TYPE]:dbr_size[TYPE]+((COUNT)-1)*dbr_value_size[TYPE])) /* size for each type - array indexed by the DBR_ type code */ -epicsShareExtern const unsigned short dbr_size[LAST_BUFFER_TYPE+1]; +epicsShareExtern const unsigned short dbr_size[]; /* size for each type's value - array indexed by the DBR_ type code */ -epicsShareExtern const unsigned short dbr_value_size[LAST_BUFFER_TYPE+1]; +epicsShareExtern const unsigned short dbr_value_size[]; +#ifndef db_accessHFORdb_accessC /* class for each type's value */ enum dbr_value_class { dbr_class_int, diff --git a/src/db/db_access.c b/src/db/db_access.c index 6f389257f..98ff26361 100644 --- a/src/db/db_access.c +++ b/src/db/db_access.c @@ -148,95 +148,58 @@ int epicsShareAPI db_name_to_addr(const char *pname, struct dbAddr *paddr) int epicsShareAPI db_get_field(struct dbAddr *paddr, int buffer_type, void *pbuffer, int no_elements, void *pfl) +{ + long nRequest = no_elements; + int result = db_get_field_and_count( + paddr, buffer_type, pbuffer, &nRequest, pfl); + if (nRequest < no_elements) + /* If the database request returned fewer elements than requested then + * fill out the remainder of the array with zeros. */ + memset( + (char *)pbuffer + dbr_size_n(buffer_type, nRequest), 0, + (no_elements - nRequest) * dbr_value_size[buffer_type]); + return result; +} + +/* Performs the work of the public db_get_field API, but also returns the number + * of elements actually copied to the buffer. The caller is responsible for + * zeroing the remaining part of the buffer. */ +int epicsShareAPI db_get_field_and_count( + struct dbAddr *paddr, int buffer_type, + void *pbuffer, long *nRequest, void *pfl) { long status; long options; - long nRequest; long i; + long zero = 0; - /* The order of the DBR* elements in the "new" structures below is + /* The order of the DBR* elements in the "newSt" structures below is * very important and must correspond to the order of processing * in the dbAccess.c dbGet() and getOptions() routines. */ switch(buffer_type) { case(oldDBR_STRING): - { - DBSTRING *pvalue = (DBSTRING *)pbuffer; - - options = 0; - nRequest = no_elements; - status = dbGetField(paddr, DBR_STRING, pbuffer, &options, &nRequest, - pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i][0] = 0; - } + status = dbGetField(paddr, DBR_STRING, pbuffer, &zero, nRequest, pfl); break; /* case(oldDBR_INT): */ case(oldDBR_SHORT): - { - dbr_short_t *pvalue = (dbr_short_t *)pbuffer; - - options = 0; - nRequest = no_elements; - status = dbGetField(paddr, DBR_SHORT, pbuffer, &options, &nRequest, - pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i] = 0; - } + status = dbGetField(paddr, DBR_SHORT, pbuffer, &zero, nRequest, pfl); break; case(oldDBR_FLOAT): - { - dbr_float_t *pvalue = (dbr_float_t *)pbuffer; - - options = 0; - nRequest = no_elements; - status = dbGetField(paddr, DBR_FLOAT, pbuffer, &options, &nRequest, - pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i] = 0; - } + status = dbGetField(paddr, DBR_FLOAT, pbuffer, &zero, nRequest, pfl); break; case(oldDBR_ENUM): - { - dbr_enum_t *pvalue = (dbr_enum_t *)pbuffer; - - options = 0; - nRequest = no_elements; - status = dbGetField(paddr, DBR_ENUM, pbuffer, &options, &nRequest, - pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i] = 0; - } + status = dbGetField(paddr, DBR_ENUM, pbuffer, &zero, nRequest, pfl); break; case(oldDBR_CHAR): - { - dbr_char_t *pvalue = (dbr_char_t *)pbuffer; - - options = 0; - nRequest = no_elements; - status = dbGetField(paddr, DBR_CHAR, pbuffer, &options, &nRequest, - pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i] = 0; - } + status = dbGetField(paddr, DBR_CHAR, pbuffer, &zero, nRequest, pfl); break; case(oldDBR_LONG): - { - dbr_long_t *pvalue = (dbr_long_t *)pbuffer; - - options = 0; - nRequest = no_elements; - status = dbGetField(paddr, DBR_LONG, pbuffer, &options, &nRequest, - pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i] = 0; - } + status = dbGetField(paddr, DBR_LONG, pbuffer, &zero, nRequest, pfl); break; case(oldDBR_DOUBLE): - { - dbr_double_t *pvalue = (dbr_double_t *)pbuffer; - - options = 0; - nRequest = no_elements; - status = dbGetField(paddr, DBR_DOUBLE, pbuffer, &options, &nRequest, - pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i] = 0; - } + status = dbGetField(paddr, DBR_DOUBLE, pbuffer, &zero, nRequest, pfl); break; case(oldDBR_STS_STRING): @@ -247,19 +210,13 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, struct { DBRstatus } newSt; - DBSTRING *pvalue = (DBSTRING *)pold->value; options = DBR_STATUS; - nRequest = 0; - status = dbGetField(paddr, DBR_STRING, &newSt, &options, &nRequest, - pfl); + status = dbGetField(paddr, DBR_STRING, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; - options = 0; - nRequest = no_elements; - status = dbGetField(paddr, DBR_STRING, pold->value, &options, - &nRequest, pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i][0] = 0; + status = dbGetField(paddr, DBR_STRING, pold->value, &zero, + nRequest, pfl); } break; /* case(oldDBR_STS_INT): */ @@ -269,19 +226,13 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, struct { DBRstatus } newSt; - dbr_short_t *pvalue = &pold->value; options = DBR_STATUS; - nRequest = 0; - status = dbGetField(paddr, DBR_SHORT, &newSt, &options, &nRequest, - pfl); + status = dbGetField(paddr, DBR_SHORT, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; - options = 0; - nRequest = no_elements; - status = dbGetField(paddr, DBR_SHORT, &pold->value, &options, - &nRequest, pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i] = 0; + status = dbGetField(paddr, DBR_SHORT, &pold->value, &zero, + nRequest, pfl); } break; case(oldDBR_STS_FLOAT): @@ -290,19 +241,13 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, struct { DBRstatus } newSt; - dbr_float_t *pvalue = &pold->value; options = DBR_STATUS; - nRequest = 0; - status = dbGetField(paddr, DBR_FLOAT, &newSt, &options, &nRequest, - pfl); + status = dbGetField(paddr, DBR_FLOAT, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; - options = 0; - nRequest = no_elements; - status = dbGetField(paddr, DBR_FLOAT, &pold->value, &options, - &nRequest, pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i] = 0; + status = dbGetField(paddr, DBR_FLOAT, &pold->value, &zero, + nRequest, pfl); } break; case(oldDBR_STS_ENUM): @@ -311,19 +256,13 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, struct { DBRstatus } newSt; - dbr_enum_t *pvalue = &pold->value; options = DBR_STATUS; - nRequest = 0; - status = dbGetField(paddr, DBR_ENUM, &newSt, &options, &nRequest, - pfl); + status = dbGetField(paddr, DBR_ENUM, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; - options = 0; - nRequest = no_elements; - status = dbGetField(paddr, DBR_ENUM, &pold->value, &options, - &nRequest, pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i] = 0; + status = dbGetField(paddr, DBR_ENUM, &pold->value, &zero, + nRequest, pfl); } break; case(oldDBR_STS_CHAR): @@ -332,19 +271,13 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, struct { DBRstatus } newSt; - dbr_char_t *pvalue = &pold->value; options = DBR_STATUS; - nRequest = 0; - status = dbGetField(paddr, DBR_UCHAR, &newSt, &options, &nRequest, - pfl); + status = dbGetField(paddr, DBR_UCHAR, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; - options = 0; - nRequest = no_elements; - status = dbGetField(paddr, DBR_UCHAR, &pold->value, &options, - &nRequest, pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i] = 0; + status = dbGetField(paddr, DBR_UCHAR, &pold->value, &zero, + nRequest, pfl); } break; case(oldDBR_STS_LONG): @@ -353,19 +286,13 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, struct { DBRstatus } newSt; - dbr_long_t *pvalue = &pold->value; options = DBR_STATUS; - nRequest = 0; - status = dbGetField(paddr, DBR_LONG, &newSt, &options, &nRequest, - pfl); + status = dbGetField(paddr, DBR_LONG, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; - options = 0; - nRequest = no_elements; - status = dbGetField(paddr, DBR_LONG, &pold->value, &options, - &nRequest, pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i] = 0; + status = dbGetField(paddr, DBR_LONG, &pold->value, &zero, + nRequest, pfl); } break; case(oldDBR_STS_DOUBLE): @@ -374,19 +301,14 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, struct { DBRstatus } newSt; - dbr_double_t *pvalue = &pold->value; options = DBR_STATUS; - nRequest = 0; - status = dbGetField(paddr, DBR_DOUBLE, &newSt, &options, &nRequest, - pfl); + status = dbGetField(paddr, DBR_DOUBLE, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; options = 0; - nRequest = no_elements; status = dbGetField(paddr, DBR_DOUBLE, &pold->value, &options, - &nRequest, pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i] = 0; + nRequest, pfl); } break; @@ -397,20 +319,15 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, DBRstatus DBRtime } newSt; - DBSTRING *pvalue = (DBSTRING *)(pold->value); options = DBR_STATUS | DBR_TIME; - nRequest = 0; - status = dbGetField(paddr, DBR_STRING, &newSt, &options, &nRequest, - pfl); + status = dbGetField(paddr, DBR_STRING, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; pold->stamp = newSt.time; /* structure copy */ options = 0; - nRequest = no_elements; - status = dbGetField(paddr, DBR_STRING, pold->value, &options, - &nRequest, pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i][0] = 0; + status = dbGetField(paddr, DBR_STRING, pold->value, &options, + nRequest, pfl); } break; /* case(oldDBR_TIME_INT): */ @@ -421,20 +338,15 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, DBRstatus DBRtime } newSt; - dbr_short_t *pvalue = &pold->value; options = DBR_STATUS | DBR_TIME; - nRequest = 0; - status = dbGetField(paddr, DBR_SHORT, &newSt, &options, &nRequest, - pfl); + status = dbGetField(paddr, DBR_SHORT, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; pold->stamp = newSt.time; /* structure copy */ options = 0; - nRequest = no_elements; status = dbGetField(paddr, DBR_SHORT, &pold->value, &options, - &nRequest, pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i] = 0; + nRequest, pfl); } break; case(oldDBR_TIME_FLOAT): @@ -444,20 +356,15 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, DBRstatus DBRtime } newSt; - dbr_float_t *pvalue = &pold->value; options = DBR_STATUS | DBR_TIME; - nRequest = 0; - status = dbGetField(paddr, DBR_FLOAT, &newSt, &options, &nRequest, - pfl); + status = dbGetField(paddr, DBR_FLOAT, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; pold->stamp = newSt.time; /* structure copy */ options = 0; - nRequest = no_elements; status = dbGetField(paddr, DBR_FLOAT, &pold->value, &options, - &nRequest, pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i] = 0; + nRequest, pfl); } break; case(oldDBR_TIME_ENUM): @@ -467,20 +374,15 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, DBRstatus DBRtime } newSt; - dbr_enum_t *pvalue = &pold->value; options = DBR_STATUS | DBR_TIME; - nRequest = 0; - status = dbGetField(paddr, DBR_ENUM, &newSt, &options, &nRequest, - pfl); + status = dbGetField(paddr, DBR_ENUM, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; pold->stamp = newSt.time; /* structure copy */ options = 0; - nRequest = no_elements; status = dbGetField(paddr, DBR_ENUM, &pold->value, &options, - &nRequest, pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i] = 0; + nRequest, pfl); } break; case(oldDBR_TIME_CHAR): @@ -490,20 +392,15 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, DBRstatus DBRtime } newSt; - dbr_char_t *pvalue = &pold->value; options = DBR_STATUS | DBR_TIME; - nRequest = 0; - status = dbGetField(paddr, DBR_CHAR, &newSt, &options, &nRequest, - pfl); + status = dbGetField(paddr, DBR_CHAR, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; pold->stamp = newSt.time; /* structure copy */ options = 0; - nRequest = no_elements; status = dbGetField(paddr, DBR_CHAR, &pold->value, &options, - &nRequest, pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i] = 0; + nRequest, pfl); } break; case(oldDBR_TIME_LONG): @@ -513,20 +410,15 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, DBRstatus DBRtime } newSt; - dbr_long_t *pvalue = &pold->value; options = DBR_STATUS | DBR_TIME; - nRequest = 0; - status = dbGetField(paddr, DBR_LONG, &newSt, &options, &nRequest, - pfl); + status = dbGetField(paddr, DBR_LONG, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; pold->stamp = newSt.time; /* structure copy */ options = 0; - nRequest = no_elements; status = dbGetField(paddr, DBR_LONG, &pold->value, &options, - &nRequest, pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i] = 0; + nRequest, pfl); } break; case(oldDBR_TIME_DOUBLE): @@ -536,20 +428,15 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, DBRstatus DBRtime } newSt; - dbr_double_t *pvalue = &pold->value; options = DBR_STATUS | DBR_TIME; - nRequest = 0; - status = dbGetField(paddr, DBR_DOUBLE, &newSt, &options, &nRequest, - pfl); + status = dbGetField(paddr, DBR_DOUBLE, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; pold->stamp = newSt.time; /* structure copy */ options = 0; - nRequest = no_elements; status = dbGetField(paddr, DBR_DOUBLE, &pold->value, &options, - &nRequest, pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i] = 0; + nRequest, pfl); } break; @@ -564,12 +451,9 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, DBRgrLong DBRalLong } newSt; - dbr_short_t *pvalue = &pold->value; options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_AL_LONG; - nRequest = 0; - status = dbGetField(paddr, DBR_SHORT, &newSt, &options, &nRequest, - pfl); + status = dbGetField(paddr, DBR_SHORT, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; strncpy(pold->units, newSt.units, MAX_UNITS_SIZE); @@ -581,10 +465,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, pold->lower_warning_limit = newSt.lower_warning_limit; pold->lower_alarm_limit = newSt.lower_alarm_limit; options = 0; - nRequest = no_elements; status = dbGetField(paddr, DBR_SHORT, &pold->value, &options, - &nRequest, pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i] = 0; + nRequest, pfl); } break; case(oldDBR_GR_FLOAT): @@ -597,13 +479,10 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, DBRgrDouble DBRalDouble } newSt; - dbr_float_t *pvalue = &pold->value; options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE | DBR_AL_DOUBLE; - nRequest = 0; - status = dbGetField(paddr, DBR_FLOAT, &newSt, &options, &nRequest, - pfl); + status = dbGetField(paddr, DBR_FLOAT, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; pold->precision = newSt.precision.dp; @@ -616,10 +495,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, pold->upper_warning_limit = epicsConvertDoubleToFloat(newSt.upper_warning_limit); pold->lower_warning_limit = epicsConvertDoubleToFloat(newSt.lower_warning_limit); options = 0; - nRequest = no_elements; status = dbGetField(paddr, DBR_FLOAT, &pold->value, &options, - &nRequest, pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i] = 0; + nRequest, pfl); } break; /* case(oldDBR_GR_ENUM): see oldDBR_CTRL_ENUM */ @@ -632,12 +509,9 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, DBRgrLong DBRalLong } newSt; - dbr_char_t *pvalue = &pold->value; options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_AL_LONG; - nRequest = 0; - status = dbGetField(paddr, DBR_UCHAR, &newSt, &options, &nRequest, - pfl); + status = dbGetField(paddr, DBR_UCHAR, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; strncpy(pold->units, newSt.units, MAX_UNITS_SIZE); @@ -649,10 +523,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, pold->lower_warning_limit = newSt.lower_warning_limit; pold->lower_alarm_limit = newSt.lower_alarm_limit; options = 0; - nRequest = no_elements; status = dbGetField(paddr, DBR_UCHAR, &pold->value, &options, - &nRequest, pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i] = 0; + nRequest, pfl); } break; case(oldDBR_GR_LONG): @@ -664,12 +536,9 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, DBRgrLong DBRalLong } newSt; - dbr_long_t *pvalue = &pold->value; options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_AL_LONG; - nRequest = 0; - status = dbGetField(paddr, DBR_LONG, &newSt, &options, &nRequest, - pfl); + status = dbGetField(paddr, DBR_LONG, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; strncpy(pold->units, newSt.units, MAX_UNITS_SIZE); @@ -681,10 +550,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, pold->lower_warning_limit = newSt.lower_warning_limit; pold->lower_alarm_limit = newSt.lower_alarm_limit; options = 0; - nRequest = no_elements; status = dbGetField(paddr, DBR_LONG, &pold->value, &options, - &nRequest, pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i] = 0; + nRequest, pfl); } break; case(oldDBR_GR_DOUBLE): @@ -697,13 +564,10 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, DBRgrDouble DBRalDouble } newSt; - dbr_double_t *pvalue = &pold->value; options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE | DBR_AL_DOUBLE; - nRequest = 0; - status = dbGetField(paddr, DBR_DOUBLE, &newSt, &options, &nRequest, - pfl); + status = dbGetField(paddr, DBR_DOUBLE, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; pold->precision = newSt.precision.dp; @@ -716,10 +580,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, pold->lower_warning_limit = newSt.lower_warning_limit; pold->lower_alarm_limit = newSt.lower_alarm_limit; options = 0; - nRequest = no_elements; status = dbGetField(paddr, DBR_DOUBLE, &pold->value, &options, - &nRequest, pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i] = 0; + nRequest, pfl); } break; @@ -734,13 +596,10 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, DBRctrlLong DBRalLong } newSt; - dbr_short_t *pvalue = &pold->value; options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_CTRL_LONG | DBR_AL_LONG; - nRequest = 0; - status = dbGetField(paddr, DBR_SHORT, &newSt, &options, &nRequest, - pfl); + status = dbGetField(paddr, DBR_SHORT, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; strncpy(pold->units, newSt.units, MAX_UNITS_SIZE); @@ -754,10 +613,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, pold->upper_ctrl_limit = newSt.upper_ctrl_limit; pold->lower_ctrl_limit = newSt.lower_ctrl_limit; options = 0; - nRequest = no_elements; status = dbGetField(paddr, DBR_SHORT, &pold->value, &options, - &nRequest, pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i] = 0; + nRequest, pfl); } break; case(oldDBR_CTRL_FLOAT): @@ -771,13 +628,10 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, DBRctrlDouble DBRalDouble } newSt; - dbr_float_t *pvalue = &pold->value; options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE | DBR_CTRL_DOUBLE | DBR_AL_DOUBLE; - nRequest = 0; - status = dbGetField(paddr, DBR_FLOAT, &newSt, &options, &nRequest, - pfl); + status = dbGetField(paddr, DBR_FLOAT, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; pold->precision = newSt.precision.dp; @@ -792,10 +646,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, pold->upper_ctrl_limit = epicsConvertDoubleToFloat(newSt.upper_ctrl_limit); pold->lower_ctrl_limit = epicsConvertDoubleToFloat(newSt.lower_ctrl_limit); options = 0; - nRequest = no_elements; status = dbGetField(paddr, DBR_FLOAT, &pold->value, &options, - &nRequest, pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i] = 0; + nRequest, pfl); } break; case(oldDBR_GR_ENUM): @@ -807,14 +659,11 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, DBRenumStrs } newSt; short no_str; - dbr_enum_t *pvalue = &pold->value; memset(pold, '\0', sizeof(struct dbr_ctrl_enum)); /* first get status and severity */ options = DBR_STATUS | DBR_ENUM_STRS; - nRequest = 0; - status = dbGetField(paddr, DBR_ENUM, &newSt, &options, &nRequest, - pfl); + status = dbGetField(paddr, DBR_ENUM, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; no_str = newSt.no_str; @@ -824,10 +673,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, strncpy(pold->strs[i], newSt.strs[i], sizeof(pold->strs[i])); /*now get values*/ options = 0; - nRequest = no_elements; status = dbGetField(paddr, DBR_ENUM, &pold->value, &options, - &nRequest, pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i] = 0; + nRequest, pfl); } break; case(oldDBR_CTRL_CHAR): @@ -840,13 +687,10 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, DBRctrlLong DBRalLong } newSt; - dbr_char_t *pvalue = &pold->value; options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_CTRL_LONG | DBR_AL_LONG; - nRequest = 0; - status = dbGetField(paddr, DBR_UCHAR, &newSt, &options, &nRequest, - pfl); + status = dbGetField(paddr, DBR_UCHAR, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; strncpy(pold->units, newSt.units, MAX_UNITS_SIZE); @@ -860,10 +704,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, pold->upper_ctrl_limit = newSt.upper_ctrl_limit; pold->lower_ctrl_limit = newSt.lower_ctrl_limit; options = 0; - nRequest = no_elements; status = dbGetField(paddr, DBR_UCHAR, &pold->value, &options, - &nRequest, pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i] = 0; + nRequest, pfl); } break; case(oldDBR_CTRL_LONG): @@ -876,13 +718,10 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, DBRctrlLong DBRalLong } newSt; - dbr_long_t *pvalue = &pold->value; options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_CTRL_LONG | DBR_AL_LONG; - nRequest = 0; - status = dbGetField(paddr, DBR_LONG, &newSt, &options, &nRequest, - pfl); + status = dbGetField(paddr, DBR_LONG, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; strncpy(pold->units, newSt.units, MAX_UNITS_SIZE); @@ -896,10 +735,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, pold->upper_ctrl_limit = newSt.upper_ctrl_limit; pold->lower_ctrl_limit = newSt.lower_ctrl_limit; options = 0; - nRequest = no_elements; status = dbGetField(paddr, DBR_LONG, &pold->value, &options, - &nRequest, pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i] = 0; + nRequest, pfl); } break; case(oldDBR_CTRL_DOUBLE): @@ -913,13 +750,10 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, DBRctrlDouble DBRalDouble } newSt; - dbr_double_t *pvalue = &pold->value; options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE | DBR_CTRL_DOUBLE | DBR_AL_DOUBLE; - nRequest = 0; - status = dbGetField(paddr, DBR_DOUBLE, &newSt, &options, &nRequest, - pfl); + status = dbGetField(paddr, DBR_DOUBLE, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; pold->precision = newSt.precision.dp; @@ -934,10 +768,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, pold->upper_ctrl_limit = newSt.upper_ctrl_limit; pold->lower_ctrl_limit = newSt.lower_ctrl_limit; options = 0; - nRequest = no_elements; status = dbGetField(paddr, DBR_DOUBLE, &pold->value, &options, - &nRequest, pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i] = 0; + nRequest, pfl); } break; @@ -947,21 +779,16 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr, struct { DBRstatus } newSt; - DBSTRING *pvalue = (DBSTRING *)(pold->value); options = DBR_STATUS; - nRequest = 0; - status = dbGetField(paddr, DBR_STRING, &newSt, &options, &nRequest, - pfl); + status = dbGetField(paddr, DBR_STRING, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; pold->ackt = newSt.ackt; pold->acks = newSt.acks; options = 0; - nRequest = no_elements; status = dbGetField(paddr, DBR_STRING, pold->value, - &options, &nRequest, pfl); - for (i = nRequest; i < no_elements; i++) pvalue[i][0] = 0; + &options, nRequest, pfl); } break; diff --git a/src/db/db_access_routines.h b/src/db/db_access_routines.h index 4dde58fb7..a45c24e29 100644 --- a/src/db/db_access_routines.h +++ b/src/db/db_access_routines.h @@ -39,6 +39,9 @@ epicsShareFunc int epicsShareAPI db_put_field( DBADDR *paddr, int src_type,const void *psrc, int no_elements); epicsShareFunc int epicsShareAPI db_get_field( DBADDR *paddr, int dest_type,void *pdest, int no_elements, void *pfl); +epicsShareFunc int db_get_field_and_count( + struct dbAddr *paddr, int buffer_type, + void *pbuffer, long *nRequest, void *pfl); #ifdef __cplusplus diff --git a/src/rsrv/camessage.c b/src/rsrv/camessage.c index 984d04cfb..8542becb8 100644 --- a/src/rsrv/camessage.c +++ b/src/rsrv/camessage.c @@ -528,12 +528,21 @@ static void read_reply ( void *pArg, struct dbAddr *paddr, cid = pciu->cid; } - status = cas_copy_in_header ( pClient, pevext->msg.m_cmmd, pevext->size, - pevext->msg.m_dataType, pevext->msg.m_count, cid, pevext->msg.m_available, + /* If the client has requested a zero element count we interpret this as a + * request for all avaiable elements. In this case we initialise the + * header with the maximum element size specified by the database. */ + int autosize = pevext->msg.m_count == 0; + long item_count = + autosize ? paddr->no_elements : pevext->msg.m_count; + ca_uint32_t payload_size = dbr_size_n(pevext->msg.m_dataType, item_count); + status = cas_copy_in_header( + pClient, pevext->msg.m_cmmd, payload_size, + pevext->msg.m_dataType, item_count, cid, pevext->msg.m_available, &pPayload ); if ( status != ECA_NORMAL ) { send_err ( &pevext->msg, status, pClient, - "server unable to load read (or subscription update) response into protocol buffer PV=\"%s\" max bytes=%u", + "server unable to load read (or subscription update) response " + "into protocol buffer PV=\"%s\" max bytes=%u", RECORD_NAME ( paddr ), rsrvSizeofLargeBufTCP ); if ( ! eventsRemaining ) cas_send_bs_msg ( pClient, FALSE ); @@ -552,8 +561,8 @@ static void read_reply ( void *pArg, struct dbAddr *paddr, return; } - status = db_get_field ( paddr, pevext->msg.m_dataType, - pPayload, pevext->msg.m_count, pfl); + status = db_get_field_and_count( + paddr, pevext->msg.m_dataType, pPayload, &item_count, pfl); if ( status < 0 ) { /* * I cant wait to redesign this protocol from scratch! @@ -567,58 +576,52 @@ static void read_reply ( void *pArg, struct dbAddr *paddr, send_err ( &pevext->msg, ECA_GETFAIL, pClient, RECORD_NAME ( paddr ) ); } else { - /* - * New clients recv the status of the - * operation directly to the + /* New clients recv the status of the operation directly to the * event/put/get callback. * - * Fetched value is set to zero in case they - * use it even when the status indicates - * failure. + * Fetched value is set to zero in case they use it even when the + * status indicates failure -- unless the client selected autosizing + * data, in which case they'd better know what they're doing! * - * The m_cid field in the protocol - * header is abused to carry the status - */ - memset ( pPayload, 0, pevext->size ); + * The m_cid field in the protocol header is abused to carry the + * status */ + if (autosize) { + payload_size = dbr_size_n(pevext->msg.m_dataType, 0); + cas_set_header_count(pClient, 0); + } + memset ( pPayload, 0, payload_size ); cas_set_header_cid ( pClient, ECA_GETFAIL ); - cas_commit_msg ( pClient, pevext->size ); + cas_commit_msg ( pClient, payload_size ); } } else { - ca_uint32_t payloadSize = pevext->size; int cacStatus = caNetConvert ( pevext->msg.m_dataType, pPayload, pPayload, - TRUE /* host -> net format */, pevext->msg.m_count ); - if ( cacStatus == ECA_NORMAL ) { - /* - * force string message size to be the true size rounded to even - * boundary - */ - if ( pevext->msg.m_dataType == DBR_STRING - && pevext->msg.m_count == 1 ) { - char * pStr = (char *) pPayload; - size_t strcnt = strlen ( pStr ); - if ( strcnt < payloadSize ) { - payloadSize = ( ca_uint32_t ) ( strcnt + 1u ); - } - else { - pStr[payloadSize-1] = '\0'; - errlogPrintf ( - "caserver: read_reply: detected DBR_STRING w/o nill termination " - "in response from db_get_field, pPayload = \"%s\"\n", - pStr ); - } + TRUE /* host -> net format */, item_count ); + if ( cacStatus == ECA_NORMAL ) { + ca_uint32_t data_size = + dbr_size_n(pevext->msg.m_dataType, item_count); + if (autosize) { + payload_size = data_size; + cas_set_header_count(pClient, item_count); } + else + memset( + (char *) pPayload + data_size, 0, payload_size - data_size); } else { - memset ( pPayload, 0, payloadSize ); + if (autosize) { + payload_size = dbr_size_n(pevext->msg.m_dataType, 0); + cas_set_header_count(pClient, 0); + } + memset ( pPayload, 0, payload_size ); cas_set_header_cid ( pClient, cacStatus ); - } - cas_commit_msg ( pClient, payloadSize ); + } + cas_commit_msg ( pClient, payload_size ); } /* - * Ensures timely response for events, but does que + * Ensures timely response for events, but does queue * them up like db requests when the OPI does not keep up. */ if ( ! eventsRemaining ) diff --git a/src/rsrv/caserverio.c b/src/rsrv/caserverio.c index 34ead95e1..4d8b77385 100644 --- a/src/rsrv/caserverio.c +++ b/src/rsrv/caserverio.c @@ -336,6 +336,20 @@ void cas_set_header_cid ( struct client *pClient, ca_uint32_t cid ) pMsg->m_cid = htonl ( cid ); } +void cas_set_header_count (struct client *pClient, ca_uint32_t count) +{ + caHdr *pMsg = (caHdr *) &pClient->send.buf[pClient->send.stk]; + if (pMsg->m_postsize == htons(0xffff)) { + assert(pMsg->m_count == 0); + ca_uint32_t *pLW = (ca_uint32_t *) (pMsg + 1); + pLW[1] = htonl(count); + } + else { + assert(count < 65536); + pMsg->m_count = htons((ca_uint16_t) count); + } +} + void cas_commit_msg ( struct client *pClient, ca_uint32_t size ) { caHdr * pMsg = ( caHdr * ) &pClient->send.buf[pClient->send.stk]; diff --git a/src/rsrv/server.h b/src/rsrv/server.h index 5fe69c638..6d1dfc38f 100644 --- a/src/rsrv/server.h +++ b/src/rsrv/server.h @@ -27,7 +27,7 @@ #include "asLib.h" #include "dbAddr.h" #include "dbNotify.h" -#define CA_MINOR_PROTOCOL_REVISION 12 +#define CA_MINOR_PROTOCOL_REVISION 13 #include "caProto.h" #include "ellLib.h" #include "epicsTime.h" @@ -226,6 +226,7 @@ int cas_copy_in_header ( ca_uint16_t dataType, ca_uint32_t nElem, ca_uint32_t cid, ca_uint32_t responseSpecific, void **pPayload ); void cas_set_header_cid ( struct client *pClient, ca_uint32_t ); +void cas_set_header_count (struct client *pClient, ca_uint32_t count); void cas_commit_msg ( struct client *pClient, ca_uint32_t size ); #endif /*INCLserverh*/