net-snmp 5.7
|
00001 #include <net-snmp/net-snmp-config.h> 00002 #include <net-snmp/net-snmp-features.h> 00003 00004 #include <net-snmp/net-snmp-includes.h> 00005 #include <net-snmp/agent/net-snmp-agent-includes.h> 00006 00007 #include <net-snmp/agent/row_merge.h> 00008 00009 #if HAVE_STRING_H 00010 #include <string.h> 00011 #else 00012 #include <strings.h> 00013 #endif 00014 00015 netsnmp_feature_provide(row_merge) 00016 netsnmp_feature_child_of(row_merge, row_merge_all) 00017 netsnmp_feature_child_of(row_merge_all, mib_helpers) 00018 00019 00020 #ifndef NETSNMP_FEATURE_REMOVE_ROW_MERGE 00021 00034 netsnmp_mib_handler * 00035 netsnmp_get_row_merge_handler(int prefix_len) 00036 { 00037 netsnmp_mib_handler *ret = NULL; 00038 ret = netsnmp_create_handler("row_merge", 00039 netsnmp_row_merge_helper_handler); 00040 if (ret) { 00041 ret->myvoid = (void *)(intptr_t)prefix_len; 00042 } 00043 return ret; 00044 } 00045 00048 netsnmp_feature_child_of(register_row_merge, row_merge_all) 00049 #ifndef NETSNMP_FEATURE_REMOVE_REGISTER_ROW_MERGE 00050 int 00051 netsnmp_register_row_merge(netsnmp_handler_registration *reginfo) 00052 { 00053 netsnmp_inject_handler(reginfo, 00054 netsnmp_get_row_merge_handler(reginfo->rootoid_len+1)); 00055 return netsnmp_register_handler(reginfo); 00056 } 00057 #endif /* NETSNMP_FEATURE_REMOVE_REGISTER_ROW_MERGE */ 00058 00059 static void 00060 _rm_status_free(void *mem) 00061 { 00062 netsnmp_row_merge_status *rm_status = (netsnmp_row_merge_status*)mem; 00063 00064 if (NULL != rm_status->saved_requests) 00065 free(rm_status->saved_requests); 00066 00067 if (NULL != rm_status->saved_status) 00068 free(rm_status->saved_status); 00069 00070 free(mem); 00071 } 00072 00073 00076 netsnmp_row_merge_status * 00077 netsnmp_row_merge_status_get(netsnmp_handler_registration *reginfo, 00078 netsnmp_agent_request_info *reqinfo, 00079 int create_missing) 00080 { 00081 netsnmp_row_merge_status *rm_status; 00082 char buf[64]; 00083 int rc; 00084 00085 /* 00086 * see if we've already been here 00087 */ 00088 rc = snprintf(buf, sizeof(buf), "row_merge:%p", reginfo); 00089 if ((-1 == rc) || ((size_t)rc >= sizeof(buf))) { 00090 snmp_log(LOG_ERR,"error creating key\n"); 00091 return NULL; 00092 } 00093 00094 rm_status = (netsnmp_row_merge_status*)netsnmp_agent_get_list_data(reqinfo, buf); 00095 if ((NULL == rm_status) && create_missing) { 00096 netsnmp_data_list *data_list; 00097 00098 rm_status = SNMP_MALLOC_TYPEDEF(netsnmp_row_merge_status); 00099 if (NULL == rm_status) { 00100 snmp_log(LOG_ERR,"error allocating memory\n"); 00101 return NULL; 00102 } 00103 data_list = netsnmp_create_data_list(buf, rm_status, 00104 _rm_status_free); 00105 if (NULL == data_list) { 00106 free(rm_status); 00107 return NULL; 00108 } 00109 netsnmp_agent_add_list_data(reqinfo, data_list); 00110 } 00111 00112 return rm_status; 00113 } 00114 00119 int 00120 netsnmp_row_merge_status_first(netsnmp_handler_registration *reginfo, 00121 netsnmp_agent_request_info *reqinfo) 00122 { 00123 netsnmp_row_merge_status *rm_status; 00124 00125 /* 00126 * find status 00127 */ 00128 rm_status = netsnmp_row_merge_status_get(reginfo, reqinfo, 0); 00129 if (NULL == rm_status) 00130 return 0; 00131 00132 return (rm_status->count == 1) ? 1 : (rm_status->current == 1); 00133 } 00134 00139 int 00140 netsnmp_row_merge_status_last(netsnmp_handler_registration *reginfo, 00141 netsnmp_agent_request_info *reqinfo) 00142 { 00143 netsnmp_row_merge_status *rm_status; 00144 00145 /* 00146 * find status 00147 */ 00148 rm_status = netsnmp_row_merge_status_get(reginfo, reqinfo, 0); 00149 if (NULL == rm_status) 00150 return 0; 00151 00152 return (rm_status->count == 1) ? 1 : 00153 (rm_status->current == rm_status->rows); 00154 } 00155 00156 00157 #define ROW_MERGE_WAITING 0 00158 #define ROW_MERGE_ACTIVE 1 00159 #define ROW_MERGE_DONE 2 00160 #define ROW_MERGE_HEAD 3 00161 00163 int 00164 netsnmp_row_merge_helper_handler(netsnmp_mib_handler *handler, 00165 netsnmp_handler_registration *reginfo, 00166 netsnmp_agent_request_info *reqinfo, 00167 netsnmp_request_info *requests) 00168 { 00169 netsnmp_request_info *request, **saved_requests; 00170 char *saved_status; 00171 netsnmp_row_merge_status *rm_status; 00172 int i, j, ret, tail, count, final_rc = SNMP_ERR_NOERROR; 00173 00174 /* 00175 * Use the prefix length as supplied during registration, rather 00176 * than trying to second-guess what the MIB implementer wanted. 00177 */ 00178 int SKIP_OID = (int)(intptr_t)handler->myvoid; 00179 00180 DEBUGMSGTL(("helper:row_merge", "Got request (%d): ", SKIP_OID)); 00181 DEBUGMSGOID(("helper:row_merge", reginfo->rootoid, reginfo->rootoid_len)); 00182 DEBUGMSG(("helper:row_merge", "\n")); 00183 00184 /* 00185 * find or create status 00186 */ 00187 rm_status = netsnmp_row_merge_status_get(reginfo, reqinfo, 1); 00188 00189 /* 00190 * Count the requests, and set up an array to keep 00191 * track of the original order. 00192 */ 00193 for (count = 0, request = requests; request; request = request->next) { 00194 DEBUGIF("helper:row_merge") { 00195 DEBUGMSGTL(("helper:row_merge", " got varbind: ")); 00196 DEBUGMSGOID(("helper:row_merge", request->requestvb->name, 00197 request->requestvb->name_length)); 00198 DEBUGMSG(("helper:row_merge", "\n")); 00199 } 00200 count++; 00201 } 00202 00203 /* 00204 * Optimization: skip all this if there is just one request 00205 */ 00206 if(count == 1) { 00207 rm_status->count = count; 00208 if (requests->processed) 00209 return SNMP_ERR_NOERROR; 00210 return netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); 00211 } 00212 00213 /* 00214 * we really should only have to do this once, instead of every pass. 00215 * as a precaution, we'll do it every time, but put in some asserts 00216 * to see if we have to. 00217 */ 00218 /* 00219 * if the count changed, re-do everything 00220 */ 00221 if ((0 != rm_status->count) && (rm_status->count != count)) { 00222 /* 00223 * ok, i know next/bulk can cause this condition. Probably 00224 * GET, too. need to rethink this mode counting. maybe 00225 * add the mode to the rm_status structure? xxx-rks 00226 */ 00227 if ((reqinfo->mode != MODE_GET) && 00228 (reqinfo->mode != MODE_GETNEXT) && 00229 (reqinfo->mode != MODE_GETBULK)) { 00230 netsnmp_assert((NULL != rm_status->saved_requests) && 00231 (NULL != rm_status->saved_status)); 00232 } 00233 DEBUGMSGTL(("helper:row_merge", "count changed! do over...\n")); 00234 00235 SNMP_FREE(rm_status->saved_requests); 00236 SNMP_FREE(rm_status->saved_status); 00237 00238 rm_status->count = 0; 00239 rm_status->rows = 0; 00240 } 00241 00242 if (0 == rm_status->count) { 00243 /* 00244 * allocate memory for saved structure 00245 */ 00246 rm_status->saved_requests = 00247 (netsnmp_request_info**)calloc(count+1, 00248 sizeof(netsnmp_request_info*)); 00249 rm_status->saved_status = (char*)calloc(count,sizeof(char)); 00250 } 00251 00252 saved_status = rm_status->saved_status; 00253 saved_requests = rm_status->saved_requests; 00254 00255 /* 00256 * set up saved requests, and set any processed requests to done 00257 */ 00258 i = 0; 00259 for (request = requests; request; request = request->next, i++) { 00260 if (request->processed) { 00261 saved_status[i] = ROW_MERGE_DONE; 00262 DEBUGMSGTL(("helper:row_merge", " skipping processed oid: ")); 00263 DEBUGMSGOID(("helper:row_merge", request->requestvb->name, 00264 request->requestvb->name_length)); 00265 DEBUGMSG(("helper:row_merge", "\n")); 00266 } 00267 else 00268 saved_status[i] = ROW_MERGE_WAITING; 00269 if (0 != rm_status->count) 00270 netsnmp_assert(saved_requests[i] == request); 00271 saved_requests[i] = request; 00272 saved_requests[i]->prev = NULL; 00273 } 00274 saved_requests[i] = NULL; 00275 00276 /* 00277 * Note that saved_requests[count] is valid 00278 * (because of the 'count+1' in the calloc above), 00279 * but NULL (since it's past the end of the list). 00280 * This simplifies the re-linking later. 00281 */ 00282 00283 /* 00284 * Work through the (unprocessed) requests in order. 00285 * For each of these, search the rest of the list for any 00286 * matching indexes, and link them into a new list. 00287 */ 00288 for (i=0; i<count; i++) { 00289 if (saved_status[i] != ROW_MERGE_WAITING) 00290 continue; 00291 00292 if (0 == rm_status->count) 00293 rm_status->rows++; 00294 DEBUGMSGTL(("helper:row_merge", " row %d oid[%d]: ", rm_status->rows, i)); 00295 DEBUGMSGOID(("helper:row_merge", saved_requests[i]->requestvb->name, 00296 saved_requests[i]->requestvb->name_length)); 00297 DEBUGMSG(("helper:row_merge", "\n")); 00298 00299 saved_requests[i]->next = NULL; 00300 saved_status[i] = ROW_MERGE_HEAD; 00301 tail = i; 00302 for (j=i+1; j<count; j++) { 00303 if (saved_status[j] != ROW_MERGE_WAITING) 00304 continue; 00305 00306 DEBUGMSGTL(("helper:row_merge", "? oid[%d]: ", j)); 00307 DEBUGMSGOID(("helper:row_merge", 00308 saved_requests[j]->requestvb->name, 00309 saved_requests[j]->requestvb->name_length)); 00310 if (!snmp_oid_compare( 00311 saved_requests[i]->requestvb->name+SKIP_OID, 00312 saved_requests[i]->requestvb->name_length-SKIP_OID, 00313 saved_requests[j]->requestvb->name+SKIP_OID, 00314 saved_requests[j]->requestvb->name_length-SKIP_OID)) { 00315 DEBUGMSG(("helper:row_merge", " match\n")); 00316 saved_requests[tail]->next = saved_requests[j]; 00317 saved_requests[j]->next = NULL; 00318 saved_requests[j]->prev = saved_requests[tail]; 00319 saved_status[j] = ROW_MERGE_ACTIVE; 00320 tail = j; 00321 } 00322 else 00323 DEBUGMSG(("helper:row_merge", " no match\n")); 00324 } 00325 } 00326 00327 /* 00328 * not that we have a list for each row, call next handler... 00329 */ 00330 if (0 == rm_status->count) 00331 rm_status->count = count; 00332 rm_status->current = 0; 00333 for (i=0; i<count; i++) { 00334 if (saved_status[i] != ROW_MERGE_HEAD) 00335 continue; 00336 00337 /* 00338 * found the head of a new row, 00339 * call the next handler with this list 00340 */ 00341 rm_status->current++; 00342 ret = netsnmp_call_next_handler(handler, reginfo, reqinfo, 00343 saved_requests[i]); 00344 if (ret != SNMP_ERR_NOERROR) { 00345 snmp_log(LOG_WARNING, 00346 "bad rc (%d) from next handler in row_merge\n", ret); 00347 if (SNMP_ERR_NOERROR == final_rc) 00348 final_rc = ret; 00349 } 00350 } 00351 00352 /* 00353 * restore original linked list 00354 */ 00355 for (i=0; i<count; i++) { 00356 saved_requests[i]->next = saved_requests[i+1]; 00357 if (i>0) 00358 saved_requests[i]->prev = saved_requests[i-1]; 00359 } 00360 00361 return final_rc; 00362 } 00363 00369 void 00370 netsnmp_init_row_merge(void) 00371 { 00372 netsnmp_register_handler_by_name("row_merge", 00373 netsnmp_get_row_merge_handler(-1)); 00374 } 00375 #else /* NETSNMP_FEATURE_REMOVE_ROW_MERGE */ 00376 netsnmp_feature_unused(row_merge); 00377 #endif /* NETSNMP_FEATURE_REMOVE_ROW_MERGE */ 00378 00379