Developing SMUX peers for SNMP agents


When xselect indicates the SMUX file descriptor is ready for reading, the peer program calls the routine smux_wait to return the next event from the SNMP agent.

The event is filled-in from a static area. On the next call to smux_init, smux_close, or smux_wait, the value is overwritten.

On failure, smux_errno will be set to one of parameterMissing, invalidOperation, inProgress, or youLoseBig. See the section ``Error recovery'' for an explanation of these error codes. The peer program takes the appropriate action based on the error code returned.

    struct type_SNMP_SMUX__PDUs *event;

if (smux_wait(&event, NOTOK) == NOTOK) { if (smux_errno == inProgress) return;

LIB_ERROR2("smux_wait: %s [%s]", smux_error(smux_errno), smux_info); smux_fd = NOTOK; return; }

Next, the peer program switches based on the actual event returned:

SMUX__PDUs_registerResponse SMUX__PDUs_get__request SMUX__PDUs_get__next__request SMUX__PDUs_set__request SMUX__PDUs_commitOrRollback SMUX__PDUs_close

The actual code is fairly straightforward:
   switch (event->offset) {
   case SMUX__PDUs_registerResponse:
       if (!tc->t_name)
           goto unexpected;
           struct type_SNMP_RRspPDU *rsp = event->un.registerResponse;

if (rsp->parm == RRspPDU_failure) LIB_ERROR1("SMUX registration of %s failed\n", tc->t_tree); else { if (debug) printf("SMUX register: %s out=%d\n", tc->t_tree, rsp->parm); got_at_least_one = 1; } } for (tc++; tc->t_tree; tc++) if (tc->t_name) { if (smux_register(tc->t_name, -1, tc->t_access) == NOTOK) { LIB_ERROR2("smux_register: %s [%s]\n", smux_error(smux_errno), smux_info); goto losing; } if (debug) printf("SMUX register: %s in=%d\n", tc->t_tree, -1); break; } if (!tc->t_tree) { if (!got_at_least_one) { dont_bother_anymore = 1; (void) smux_close(goingDown); goto losing; } if (smux_trap(trap_coldStart, 0, (struct type_SNMP_VarBindList *) 0) == NOTOK) { LIB_ERROR2("smux_trap: %s [%s]", smux_error(smux_errno), smux_info); goto losing; } } break;

case SMUX__PDUs_get__request: case SMUX__PDUs_get__next__request: case SMUX__PDUs_set__request: do_smux(event->un.get__request, event->offset); break;

   case SMUX__PDUs_commitOrRollback:
           register struct triple *tz;

for (tz = triples; tz->t_tree; tz++) if (tz->t_name) (void) (*tz->t_sync) (event->un.commitOrRollback->parm); } break;

case SMUX__PDUs_close: if (debug) printf("SMUX close: %s\n", smux_error(event->un.close->parm)); goto losing;

case SMUX__PDUs_simple: case SMUX__PDUs_registerRequest: case SMUX__PDUs_get__response: case SMUX__PDUs_trap: unexpected: ; LIB_ERROR1("unexpectedOperation: %d", event->offset); (void) smux_close(protocolError); goto losing;

default: LIB_ERROR1("badOperation: %d", event->offset); (void) smux_close(protocolError); goto losing; }

Note the use of the smux_trap routine to send a coldStart trap once the peer has successfully registered the MIB module it will be managing. The trap codes are:

trap_coldStart trap_warmStart trap_linkDown trap_linkUp trap_authenticationFailure trap_egpNeighborLoss trap_enterpriseSpecific

If this routine fails, smux_errno will be set to one of invalidOperation, congestion, or youLoseBig.

Next topic: Get and set
Previous topic: Main loop

© 2003 Caldera International, Inc. All rights reserved.
SCO OpenServer Release 5.0.7 -- 11 February 2003