/************************************************************************/ /* SISCO SOFTWARE MODULE HEADER *****************************************/ /************************************************************************/ /* (c) Copyright Systems Integration Specialists Company, Inc., */ /* 1994 - 1996, All Rights Reserved */ /* */ /* MODULE NAME : s_write.c */ /* PRODUCT(S) : MMSEASE-LITE */ /* */ /* MODULE DESCRIPTION : */ /* */ /* GLOBAL FUNCTIONS DEFINED IN THIS MODULE : */ /* NONE */ /* */ /* MODIFICATION LOG : */ /* Date Who Rev Comments */ /* -------- --- ------ ------------------------------------------- */ /* 02/02/09 JRB 32 Chk va_to_free before ...free_va. */ /* 01/23/09 MDE 31 Use 0x%X for hex values in log msgs. */ /* 01/13/09 MDE 30 Free VA (and temp type) in case of errors */ /* 05/01/08 JRB 29 Chk ms_asn1_to_local return & set */ /* WRITE_RESULT "failure" appropriately. */ /* 04/09/07 MDE 28 Enhanced filtered logging */ /* 10/30/06 JRB 27 Use new mvl_vmd_* object handling functions. */ /* Add args on call to _mvl_objname_to_va. */ /* Elim use of global "_mvl_curr_net_info". */ /* Elim use of global "_mvl_curr_usr_ind_ctrl". */ /* 08/09/06 JRB 26 ALWAYS set resp_tag & failure in wr_rslt */ /* same as in vaCtrl. In put_asn1_data, set */ /* vaCtrl->failure to appropriate value. */ /* 01/30/06 GLB 25 Integrated porting changes for VMS */ /* 05/16/05 JRB 24 Send appropriate failure codes in write resp.*/ /* Move statistics code so it is always executed*/ /* 03/13/03 JRB 23 Use mvl_type_ctrl_find. */ /* 07/24/02 JRB 22 Use mvl_send_resp_i like ALL responses. */ /* 07/09/02 MDE 21 Add maxpend_ind support */ /* 09/21/01 JRB 20 Alloc global bufs only once at startup. */ /* 05/25/01 MDE 19 Moved where the old data is saved */ /* 03/30/01 MDE 18 Changed MSMEM_ENC_INFO to MSMEM_ENC_OS_INFO */ /* 10/25/00 JRB 17 Del u_mvl funct ptrs. Call functs directly. */ /* Control with #ifdefs. */ /* 10/06/00 MDE 16 Now restore old data for write failure */ /* 05/15/00 MDE 15 Added MMS statistics */ /* 01/21/00 MDE 14 Now use MEM_SMEM for dynamic memory */ /* 11/22/99 JRB 13 mvlas_write_resp: del indCtrl from link list */ /* 09/13/99 MDE 12 Added SD_CONST modifiers */ /* 04/07/99 MDE 11 Logging improvements */ /* 12/11/98 MDE 10 Removed scope references from VA */ /* 12/08/98 MDE 09 Fixed write handling for alternate access */ /* 11/16/98 MDE 08 Renamed internal functions (prefix '_') */ /* 09/21/98 MDE 07 Minor lint cleanup */ /* 06/15/98 MDE 06 Changes to allow compile under C++ */ /* 05/15/98 JRB 05 Chg mvl_process.. arg to (MVL_IND_PEND *). */ /* 05/15/98 JRB 04 Call u_mvl_write_ind direct (no funct ptr). */ /* 02/20/98 MDE 03 Fixed usrVa set problem */ /* 02/10/98 MDE 02 Removed NEST_RT_TYPES, always support AA, */ /* added 'u_mvl_wr_ind_start' and */ /* 'u_mvl_wr_resp_sent', other */ /* 09/10/97 MDE 01 MMS-LITE V4.0 Release */ /************************************************************************/ #include "glbtypes.h" #include "sysincs.h" #include "mmsdefs.h" #include "mms_pvar.h" #include "mms_vvar.h" #include "mvl_defs.h" #include "mvl_log.h" /************************************************************************/ /* For debug version, use a static pointer to avoid duplication of */ /* __FILE__ strings. */ /************************************************************************/ #ifdef DEBUG_SISCO SD_CONST static ST_CHAR *SD_CONST thisFileName = __FILE__; #endif /************************************************************************/ ST_RET (*u_mvl_wr_ind_start) (MVL_IND_PEND *indCtrl); ST_VOID (*u_mvl_wr_resp_sent) (MVL_IND_PEND *indCtrl); /************************************************************************/ /* Internal functions */ static ST_VOID put_asn1_data (MVL_IND_PEND *indCtrl, VARIABLE_LIST *vl, ST_UCHAR *asn1_buffer, ST_INT asn1_len, MVLAS_WR_VA_CTRL *vaCtrl); /************************************************************************/ /************************************************************************/ /* _mvl_process_write_ind */ /* A write indication has been received, process it and respond */ /************************************************************************/ ST_VOID _mvl_process_write_ind (MVL_IND_PEND *indCtrl) { MVLAS_WRITE_CTRL *wrCtrl; MVLAS_WR_VA_CTRL *vaCtrl; WRITE_REQ_INFO *write_info; ST_INT num_var; VARIABLE_LIST *vl_ptr; VAR_ACC_DATA *va_ptr; ST_INT i; ST_RET rc; write_info = (WRITE_REQ_INFO *) indCtrl->event->u.mms.dec_rslt.data_ptr; num_var = write_info->va_spec.num_of_variables; /* verify that this is a list of variables */ if (write_info->va_spec.var_acc_tag != VAR_ACC_VARLIST) { _mplas_err_resp (indCtrl,7,2); /* access, non-existent */ return; } if (u_mvl_wr_ind_start) { /* This might set optional user pointer "indCtrl->usr_ind_ctrl". */ rc = (*u_mvl_wr_ind_start) (indCtrl); if (rc != SD_SUCCESS) { _mplas_err_resp (indCtrl,7,2); /* access, non-existent */ return; } } wrCtrl = &indCtrl->u.wr; wrCtrl->vaCtrlTbl = (MVLAS_WR_VA_CTRL *) M_CALLOC (MSMEM_GEN, num_var, sizeof(MVLAS_WR_VA_CTRL)); vaCtrl = wrCtrl->vaCtrlTbl; wrCtrl->numVar = num_var; /* Looks OK, prepare to process each variable in the list */ vl_ptr = (VARIABLE_LIST *) (write_info+1); va_ptr = write_info->va_data; for (i = 0; i < num_var; ++i, ++vl_ptr, ++va_ptr, ++vaCtrl) put_asn1_data (indCtrl, vl_ptr, va_ptr->data, va_ptr->len, vaCtrl); u_mvl_write_ind (indCtrl); } /************************************************************************/ /* mvlas_write_resp */ /************************************************************************/ ST_VOID mvlas_write_resp (MVL_IND_PEND *indCtrl) { MVLAS_WRITE_CTRL *wrCtrl; MVLAS_WR_VA_CTRL *vaCtrl; MVL_COMM_EVENT *event; MVL_NET_INFO *net_info; ST_RET rc; ST_CHAR *resp_buf; ST_INT num_var; ST_INT va_data_size; WRITE_RESP_INFO *resp_info; WRITE_RESULT *wr_rslt; ST_INT i; MVL_TYPE_CTRL *type_ctrl; net_info = indCtrl->event->net_info; event = indCtrl->event; wrCtrl = &indCtrl->u.wr; vaCtrl = wrCtrl->vaCtrlTbl; num_var = wrCtrl->numVar; resp_buf = (ST_CHAR *) M_CALLOC (MSMEM_ENC_OS_INFO, 1, sizeof(WRITE_RESP_INFO) + (num_var * sizeof (WRITE_RESULT))); /* Create a write response info struct */ resp_info = (WRITE_RESP_INFO *) resp_buf; resp_info->num_of_result = num_var; wr_rslt = (WRITE_RESULT *) (resp_info +1); for (i = 0; i < num_var; ++i, ++wr_rslt, ++vaCtrl) { wr_rslt->resp_tag = vaCtrl->resp_tag; wr_rslt->failure = vaCtrl->failure; if (vaCtrl->va != NULL) { if (wr_rslt->resp_tag == WR_RSLT_FAILURE) { /* On a failure, restore the previous data */ type_ctrl = mvl_type_ctrl_find (vaCtrl->va->type_id); va_data_size = type_ctrl->data_size; memcpy (vaCtrl->va->data, vaCtrl->oldData, va_data_size); } M_FREE (MSMEM_GEN, vaCtrl->oldData); #if defined(MVL_UCA) || defined(USE_MANUFACTURED_OBJS) if (vaCtrl->va->va_to_free != NULL) u_mvl_free_va (MMSOP_WRITE, vaCtrl->va, event->net_info); #endif /* defined(MVL_UCA) || defined(USE_MANUFACTURED_OBJS) */ } if (wr_rslt->resp_tag == WR_RSLT_SUCCESS) ++mvl_mms_statistics.serverVarWrOk; else ++mvl_mms_statistics.serverVarWrErr; } /* end loop */ /* Build a write response */ rc = mpl_write_resp (event->u.mms.dec_rslt.id, resp_info); if (rc == SD_SUCCESS) mpl_resp_log (indCtrl, resp_info); if (u_mvl_wr_resp_sent) (*u_mvl_wr_resp_sent) (indCtrl); M_FREE (MSMEM_ENC_OS_INFO, resp_buf); M_FREE (MSMEM_GEN, wrCtrl->vaCtrlTbl); /* NOTE: This funct frees indCtrl. DO NOT use after this. */ /* NOTE: if rc != SD_SUCCESS, this funct sends error resp. */ _mvl_send_resp_i (indCtrl, rc); } /************************************************************************/ /* put_asn1_data */ /* This function is to provide ASN.1 encoded data, given the variable */ /* list element. */ /************************************************************************/ static ST_VOID put_asn1_data (MVL_IND_PEND *indCtrl, VARIABLE_LIST *vl, ST_UCHAR *asn1_buffer, ST_INT asn1_len, MVLAS_WR_VA_CTRL *vaCtrl) { MVL_VAR_ASSOC *va; RUNTIME_TYPE *rt; ST_INT num_rt; ST_RET rc; ST_CHAR *temp_data_buf; ST_CHAR *va_data; ST_INT va_data_size; ST_INT aa_mode; ALT_ACCESS alt_acc; /* Alternate Access specification */ ST_BOOLEAN alt_access_pres; ST_BOOLEAN alt_access_done; MVL_TYPE_CTRL *type_ctrl; /* There are more ways to fail than to succeed! */ /* Assume failure=ARE_TYPE_INCONSISTENT, but may be changed in some cases.*/ vaCtrl->resp_tag = WR_RSLT_FAILURE; vaCtrl->failure = ARE_TYPE_INCONSISTENT; alt_access_pres = vl->alt_access_pres; if (alt_access_pres) /* no alternate access support now */ { #if !defined(MVL_AA_SUPP) MVL_LOG_NERR0 ("Put ASN1 Data : Alternate Access not supported"); return; #else /* now create the AA, given the ASN.1 spec */ if (ms_asn1_to_aa (vl->alt_access.data, vl->alt_access.len, &alt_acc)) { MVL_LOG_NERR0 ("Write Indication : ASN.1 -> AA failure"); return; } #endif } switch (vl->var_spec.var_spec_tag) { case VA_SPEC_NAMED : va = _mvl_objname_to_va (&mvl_vmd, indCtrl->event->net_info, MMSOP_WRITE, &vl->var_spec.vs.name, &vaCtrl->va_scope, alt_access_pres, &alt_acc, &alt_access_done); if (alt_access_pres && alt_access_done) { M_FREE (MSMEM_GEN, alt_acc.aa); alt_access_pres = SD_FALSE; } if (!va) /* could not find variable association */ { MVL_LOG_NERR1 ("Write ind : Variable Association '%s' not found", vl->var_spec.vs.name.obj_name.vmd_spec); vaCtrl->failure = ARE_OBJ_NONEXISTENT; return; } vaCtrl->va = va; va->usr_ind_ctrl = indCtrl->usr_ind_ctrl; /* save optional user pointer in va*/ /* Save the current data in case the user rejects the write */ type_ctrl = mvl_type_ctrl_find (va->type_id); /* find type */ va_data_size = type_ctrl->data_size; vaCtrl->oldData = (ST_UCHAR *) M_MALLOC (MSMEM_GEN, va_data_size); memcpy (vaCtrl->oldData, va->data, va_data_size); /* We have obtained a variable association */ /* Now do the alternate access preprocess function if appropriate */ #if defined(MVL_AA_SUPP) aa_mode = MVL_USE_UNPACKED_AA; if (alt_access_pres && va->proc && va->proc->proc_write_aa) { rc = (*va->proc->proc_write_aa)(&va, &alt_acc, indCtrl->event->net_info, &aa_mode); if (rc != SD_SUCCESS) { MVL_LOG_NERR1 ("Write : proc_write_aa returned %d", rc); return; } } #endif /* Now take care of the data conversion (asn1 to local) */ rc = mvl_get_runtime (va->type_id, &rt, &num_rt); if (rc != SD_SUCCESS) { M_FREE (MSMEM_GEN, vaCtrl->oldData); MVL_LOG_NERR1 ("Could not get type_id %d", va->type_id); vaCtrl->va = NULL; return; } /* Sanity check, because foundry can generate configured vars w/o */ /* the data pointer initialized. */ if (va->data == NULL) { M_FREE (MSMEM_GEN, vaCtrl->oldData); MVL_LOG_NERR1 ("Write Indication : va '%s' data is NULL", va->name); vaCtrl->va = NULL; return; } va_data = (ST_CHAR *) va->data; /* "va_data_size" already set above */ break; case VA_SPEC_DESCRIBED : default : MVL_LOG_NERR0 ("Put ASN1 Data : Invalid Variable Specification Tag"); vaCtrl->failure = ARE_OBJ_ACC_UNSUPPORTED; return; break; } /* If we got here, we have a valid runtime and have resolved local */ /* data pointer and size. Go ahead and convert the ASN.1 data element to*/ /* local data format */ temp_data_buf = (ST_CHAR *) M_MALLOC (MSMEM_WR_DATA_DEC_BUF, va_data_size); #if defined(MVL_AA_SUPP) if (alt_access_pres == SD_FALSE || aa_mode == MVL_USE_NO_AA) rc = ms_asn1_to_local (rt, num_rt, asn1_buffer, asn1_len, temp_data_buf); else { /* This is an alternate access write, we must first copy the data */ /* contents to to the temp buffer, then only the selected elements */ /* will be written by the data conversion. */ memcpy (temp_data_buf, va_data, va_data_size); if (aa_mode == MVL_USE_PACKED_AA) m_alt_acc_packed = SD_TRUE; else m_alt_acc_packed = SD_FALSE; rc = ms_asn1_to_local_aa (rt, num_rt, &alt_acc, asn1_buffer, asn1_len, temp_data_buf); } #else rc = ms_asn1_to_local (rt, num_rt, asn1_buffer, asn1_len, temp_data_buf); #endif if (rc != SD_SUCCESS) { MVL_LOG_NERR1 ("Put ASN1 Data : ms_asn1_to_local failed, rc = 0x%X", rc); M_FREE (MSMEM_GEN, vaCtrl->oldData); M_FREE (MSMEM_WR_DATA_DEC_BUF, temp_data_buf); #if defined(MVL_UCA) || defined(USE_MANUFACTURED_OBJS) /* Need to free VA (caller will not if vaCtrl->va == NULL) */ if (vaCtrl->va->va_to_free != NULL) u_mvl_free_va (MMSOP_WRITE, vaCtrl->va, NULL); #endif vaCtrl->va = NULL; if (rc == ASN1E_UNEXPECTED_TAG) /* Tag mismatch in this context indicates MMS type mismatch. */ vaCtrl->failure = ARE_TYPE_INCONSISTENT; else vaCtrl->failure = ARE_OBJ_VALUE_INVALID; return; } /* Call the preprocessing function for this variable, if it exists */ if (va->proc && va->proc->pre_write_aa) { rc = (*va->proc->pre_write_aa)(va, alt_access_pres, &alt_acc, indCtrl->event->net_info, temp_data_buf, va_data_size); if (rc != SD_SUCCESS) { MVL_LOG_NERR1 ("Put ASN1 Data : call to Write pre-processor failed, rc = 0x%X", rc); M_FREE (MSMEM_GEN, vaCtrl->oldData); #if defined(MVL_UCA) || defined(USE_MANUFACTURED_OBJS) /* Need to free VA (caller will not if vaCtrl->va == NULL) */ if (vaCtrl->va->va_to_free != NULL) u_mvl_free_va (MMSOP_WRITE, vaCtrl->va, NULL); #endif vaCtrl->va = NULL; } } /* OK, almost done. The data has been converted OK and the user has had */ /* a chance to look at it. If rc == SD_SUCCESS, we are OK. */ if (rc == SD_SUCCESS) { vaCtrl->resp_tag = WR_RSLT_SUCCESS; memcpy (va_data, temp_data_buf, va_data_size); /* Call the postprocessing function for this variable, if it exists */ if (va->proc && va->proc->post_write_aa) (*va->proc->post_write_aa)(va, alt_access_pres, &alt_acc, indCtrl->event->net_info); } #if defined(MVL_AA_SUPP) if (alt_access_pres) /* if we calloc'd this AA, free it */ M_FREE (MSMEM_GEN, alt_acc.aa); #endif M_FREE (MSMEM_WR_DATA_DEC_BUF, temp_data_buf); }