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