net-snmp/net-snmp-5.5-agentx-disconn...

271 lines
9.6 KiB
Diff

955511 - net-snmpd crash on time out
969061 - net-snmpd crash on time out
1038011 - net-snmp: snmpd crashes/hangs when AgentX subagent times-out
Based on usptream commit 793d596838ff7cb48a73b675d62897c56c9e62df,
heavily backported to net-snmp-5.5
diff -up net-snmp-5.7.2/agent/mibgroup/agentx/master_admin.c.disconnect-crash net-snmp-5.7.2/agent/mibgroup/agentx/master_admin.c
--- net-snmp-5.7.2/agent/mibgroup/agentx/master_admin.c.disconnect-crash 2013-07-03 15:26:35.884813210 +0200
+++ net-snmp-5.7.2/agent/mibgroup/agentx/master_admin.c 2013-07-03 15:26:35.908813135 +0200
@@ -158,6 +158,7 @@ close_agentx_session(netsnmp_session * s
for (sp = session->subsession; sp != NULL; sp = sp->next) {
if (sp->sessid == sessid) {
+ netsnmp_remove_delegated_requests_for_session(sp);
unregister_mibs_by_session(sp);
unregister_index_by_session(sp);
unregister_sysORTable_by_session(sp);
diff -up net-snmp-5.7.2/agent/mibgroup/agentx/master.c.disconnect-crash net-snmp-5.7.2/agent/mibgroup/agentx/master.c
--- net-snmp-5.7.2/agent/mibgroup/agentx/master.c.disconnect-crash 2013-07-03 15:26:35.000000000 +0200
+++ net-snmp-5.7.2/agent/mibgroup/agentx/master.c 2013-07-03 15:29:00.644362208 +0200
@@ -222,7 +222,7 @@ agentx_got_response(int operation,
/* response is too late, free the cache */
if (magic)
netsnmp_free_delegated_cache((netsnmp_delegated_cache*) magic);
- return 0;
+ return 1;
}
requests = cache->requests;
diff -up net-snmp-5.7.2/agent/snmp_agent.c.disconnect-crash net-snmp-5.7.2/agent/snmp_agent.c
--- net-snmp-5.7.2/agent/snmp_agent.c.disconnect-crash 2013-07-03 15:26:35.893813182 +0200
+++ net-snmp-5.7.2/agent/snmp_agent.c 2013-07-03 15:28:28.979460861 +0200
@@ -1446,6 +1446,7 @@ free_agent_snmp_session(netsnmp_agent_se
netsnmp_free_cachemap(asp->cache_store);
asp->cache_store = NULL;
}
+ agent_snmp_session_release_cancelled(asp);
SNMP_FREE(asp);
}
@@ -1457,6 +1458,11 @@ netsnmp_check_for_delegated(netsnmp_agen
if (NULL == asp->treecache)
return 0;
+
+ if (agent_snmp_session_is_cancelled(asp)) {
+ printf("request %p cancelled\n", asp);
+ return 0;
+ }
for (i = 0; i <= asp->treecache_num; i++) {
for (request = asp->treecache[i].requests_begin; request;
@@ -1535,39 +1541,48 @@ int
netsnmp_remove_delegated_requests_for_session(netsnmp_session *sess)
{
netsnmp_agent_session *asp;
- int count = 0;
+ int total_count = 0;
for (asp = agent_delegated_list; asp; asp = asp->next) {
/*
* check each request
*/
+ int i;
+ int count = 0;
netsnmp_request_info *request;
- for(request = asp->requests; request; request = request->next) {
- /*
- * check session
- */
- netsnmp_assert(NULL!=request->subtree);
- if(request->subtree->session != sess)
- continue;
+ for (i = 0; i <= asp->treecache_num; i++) {
+ for (request = asp->treecache[i].requests_begin; request;
+ request = request->next) {
+ /*
+ * check session
+ */
+ netsnmp_assert(NULL!=request->subtree);
+ if(request->subtree->session != sess)
+ continue;
- /*
- * matched! mark request as done
- */
- netsnmp_request_set_error(request, SNMP_ERR_GENERR);
- ++count;
+ /*
+ * matched! mark request as done
+ */
+ netsnmp_request_set_error(request, SNMP_ERR_GENERR);
+ ++count;
+ }
+ }
+ if (count) {
+ agent_snmp_session_mark_cancelled(asp);
+ total_count += count;
}
}
/*
* if we found any, that request may be finished now
*/
- if(count) {
+ if(total_count) {
DEBUGMSGTL(("snmp_agent", "removed %d delegated request(s) for session "
- "%8p\n", count, sess));
- netsnmp_check_outstanding_agent_requests();
+ "%8p\n", total_count, sess));
+ netsnmp_check_delegated_requests();
}
- return count;
+ return total_count;
}
int
@@ -2739,19 +2754,11 @@ handle_var_requests(netsnmp_agent_sessio
return final_status;
}
-/*
- * loop through our sessions known delegated sessions and check to see
- * if they've completed yet. If there are no more delegated sessions,
- * check for and process any queued requests
- */
void
-netsnmp_check_outstanding_agent_requests(void)
+netsnmp_check_delegated_requests(void)
{
netsnmp_agent_session *asp, *prev_asp = NULL, *next_asp = NULL;
- /*
- * deal with delegated requests
- */
for (asp = agent_delegated_list; asp; asp = next_asp) {
next_asp = asp->next; /* save in case we clean up asp */
if (!netsnmp_check_for_delegated(asp)) {
@@ -2790,6 +2797,22 @@ netsnmp_check_outstanding_agent_requests
prev_asp = asp;
}
}
+}
+
+/*
+ * loop through our sessions known delegated sessions and check to see
+ * if they've completed yet. If there are no more delegated sessions,
+ * check for and process any queued requests
+ */
+void
+netsnmp_check_outstanding_agent_requests(void)
+{
+ netsnmp_agent_session *asp;
+
+ /*
+ * deal with delegated requests
+ */
+ netsnmp_check_delegated_requests();
/*
* if we are processing a set and there are more delegated
@@ -2819,7 +2842,8 @@ netsnmp_check_outstanding_agent_requests
netsnmp_processing_set = netsnmp_agent_queued_list;
DEBUGMSGTL(("snmp_agent", "SET request remains queued while "
- "delegated requests finish, asp = %8p\n", asp));
+ "delegated requests finish, asp = %8p\n",
+ agent_delegated_list));
break;
}
#endif /* NETSNMP_NO_WRITE_SUPPORT */
@@ -2880,6 +2904,11 @@ check_delayed_request(netsnmp_agent_sess
case SNMP_MSG_GETBULK:
case SNMP_MSG_GETNEXT:
netsnmp_check_all_requests_status(asp, 0);
+ if (agent_snmp_session_is_cancelled(asp)) {
+ printf("request %p is cancelled\n", asp);
+ DEBUGMSGTL(("snmp_agent","canceling next walk for asp %p\n", asp));
+ break;
+ }
handle_getnext_loop(asp);
if (netsnmp_check_for_delegated(asp) &&
netsnmp_check_transaction_id(asp->pdu->transid) !=
@@ -3838,4 +3867,73 @@ netsnmp_set_all_requests_error(netsnmp_a
return error_value;
}
#endif /* NETSNMP_FEATURE_REMOVE_SET_ALL_REQUESTS_ERROR */
+
+/*
+ * Ugly hack to fix bug #950602 and preserve ABI
+ * (the official patch adds netsnmp_agent_session->flags).
+ * We must create parallel database of netsnmp_agent_sessions
+ * and put cancelled requests there instead of marking
+ * netsnmp_agent_session->flags.
+ */
+static netsnmp_agent_session **cancelled_agent_snmp_sessions;
+static int cancelled_agent_snmp_sessions_count;
+static int cancelled_agent_snmp_sessions_max;
+
+int
+agent_snmp_session_mark_cancelled(netsnmp_agent_session *session)
+{
+ DEBUGMSGTL(("agent:cancelled", "Cancelling session %p\n", session));
+ if (!session)
+ return 0;
+ if (cancelled_agent_snmp_sessions_count + 1 > cancelled_agent_snmp_sessions_max) {
+ netsnmp_agent_session **aux;
+ int max = cancelled_agent_snmp_sessions_max + 10;
+ aux = realloc(cancelled_agent_snmp_sessions, sizeof(netsnmp_agent_session*) * max);
+ if (!aux)
+ return SNMP_ERR_GENERR;
+ cancelled_agent_snmp_sessions = aux;
+ cancelled_agent_snmp_sessions_max = max;
+ }
+ cancelled_agent_snmp_sessions[cancelled_agent_snmp_sessions_count] = session;
+ cancelled_agent_snmp_sessions_count++;
+ return 0;
+}
+
+int
+agent_snmp_session_is_cancelled(netsnmp_agent_session *session)
+{
+ int i;
+ for (i=0; i<cancelled_agent_snmp_sessions_count; i++)
+ if (cancelled_agent_snmp_sessions[i] == session) {
+ DEBUGMSGTL(("agent:cancelled", "session %p is cancelled\n", session));
+ return TRUE;
+ }
+ return FALSE;
+}
+
+int
+agent_snmp_session_release_cancelled(netsnmp_agent_session *session)
+{
+ int i, j;
+
+ if (!session)
+ return 0;
+
+ DEBUGMSGTL(("agent:cancelled", "Removing session %p\n", session));
+
+ /* delete the session from cancelled_agent_snmp_sessions */
+ for (i=0, j=0; j<cancelled_agent_snmp_sessions_count; i++, j++)
+ if (cancelled_agent_snmp_sessions[j] == session)
+ i--; /* don't increase i in this loop iteration */
+ else
+ cancelled_agent_snmp_sessions[i] = cancelled_agent_snmp_sessions[j];
+
+ cancelled_agent_snmp_sessions_count = i;
+
+ for (; i< cancelled_agent_snmp_sessions_max; i++)
+ cancelled_agent_snmp_sessions[i] = NULL;
+ return 0;
+}
+
/** @} */
+
diff -up net-snmp-5.7.2/include/net-snmp/agent/snmp_agent.h.disconnect-crash net-snmp-5.7.2/include/net-snmp/agent/snmp_agent.h
--- net-snmp-5.7.2/include/net-snmp/agent/snmp_agent.h.disconnect-crash 2012-10-10 00:28:58.000000000 +0200
+++ net-snmp-5.7.2/include/net-snmp/agent/snmp_agent.h 2013-07-03 15:26:35.909813132 +0200
@@ -240,6 +240,7 @@ extern "C" {
int init_master_agent(void);
void shutdown_master_agent(void);
int agent_check_and_process(int block);
+ void netsnmp_check_delegated_requests(void);
void netsnmp_check_outstanding_agent_requests(void);
int netsnmp_request_set_error(netsnmp_request_info *request,