Roxen.git / server / protocols / prot_snmp.pike

version» Context lines:

Roxen.git/server/protocols/prot_snmp.pike:1:   // This is a roxen protocol module.   // Copyright © 2001 - 2009, Roxen IS.      /* -  * $Id: prot_snmp.pike,v 2.20 2011/02/18 15:35:34 wellhard Exp $ +  * $Id$    *    * SNMP protocol support.    *    * Based on the Roxen SNMP agent by Honza Petrous <hop@unibase.cz>.    *    * 2007-08-29 Henrik Grubbström    */      inherit Protocol;   constant supports_ipless = 1;
Roxen.git/server/protocols/prot_snmp.pike:40:    * RFC 2594 Definitions of managed objects for WWW services    *    * TODO:    * * Traps.    * * Module reloading.    * * SNMP v3    * * Security.    */      class SNMP_Port { -  inherit Protocols.SNMP.protocol; +  inherit Protocols.SNMP.protocol : snmp;       protected int udp_errno = 0;       // The following symbols are only for API-compatibility with Stdio.Port.    mixed _accept_callback;    mixed _id;    int bind_unix(string path, mixed|void callback){}    int listen_fd(int fd, mixed|void callback){}    mixed set_id(mixed id){ return _id = id; }    mixed query_id(){ return _id;} -  +  int query_fd(){ return -1; }    Stdio.File accept(){}       int errno()    {    return udp_errno;    }       int bind(int|void port, function got_connection, string|void ip)    {    // NOTE: We know stuff about how Protocols.SNP.protocol is implemented!    udp_errno = 0;    catch { -  if (::bind(port, ip)) { +  if (snmp::bind(port, ip)) {    DWRITE("protocol.bind: success!\n");       DWRITE("protocol.create: local adress:port bound: [%s:%d].\n",    ip||"ANY", port);       if (got_connection) set_nonblocking(got_connection);       return 1;    }    };    //# error ... -  udp_errno = errno(); +  udp_errno = snmp::errno();    DWRITE("protocol.create: can't bind to the socket.\n");    }    -  +  object|mapping snmp_der_decode (string data) +  { +  return Standards.ASN1.Decode.simple_der_decode (data, snmp_type_proc); +  } +  +  mapping get_snmp_errlist() +  { +  return snmp_errlist; +  } +     protected void create() {}   }    - protected SNMP_Port port_obj; + protected SNMP_Port|Stdio.Port port_obj;      ADT.Trie mib = ADT.Trie();      //! cf RFC 1213.   class SystemMIB   {    inherit SNMP.SimpleMIB;       protected void create()    {   #if 0    SNMP.add_oid_path(SNMP.INTERNET_OID + ({ 2, 1, 1 }),    "iso.organizations.dod.internet.mgmt.mib-2.system");   #endif /* 0 */    ::create(SNMP.INTERNET_OID + ({ 2, 1, 1 }), ({}),    ({    UNDEFINED,    // system.sysDescr    SNMP.String("Roxen Webserver SNMP agent v" + -  ("$Revision: 2.20 $"/" ")[1], +  ("$Revision: 2.21 $"/" ")[1],    "sysDescr"),    // system.sysObjectID    SNMP.OID(SNMP.RIS_OID_WEBSERVER,    "sysObjectID"),    // system.sysUpTime    SNMP.Tick(lambda() {    return (time(1) - roxen->start_time)*100;    }, "sysUpTime"),    // system.sysContact    SNMP.String(lambda() {
Roxen.git/server/protocols/prot_snmp.pike:454:    SNMP.Counter(lambda()    { return roxenloader->co_num_runs_5s; },    "coNumRuns5s",    "Number of call outs longer than 5 seconds."),    SNMP.Counter(lambda()    { return roxenloader->co_num_runs_15s; },    "coNumRuns15s",    "Number of call outs longer than 15 seconds."),    }),    }), + #if constant(gethrdtime) +  ({ +  UNDEFINED, +  SNMP.Counter(0, "unithreadQueueSize", +  "Number of threads waiting to run " +  "single threaded."), +  ({ +  UNDEFINED, +  SNMP.Counter(lambda() +  { return gethrdtime()/10000; }, +  "unithreadTime", +  "Single threaded real time in centiseconds."), +  UNDEFINED, // User time.    }),    ({    UNDEFINED, -  +  UNDEFINED, // Num _disable_threads(). +  UNDEFINED, // >= 0.01s +  UNDEFINED, // >= 0.05s +  UNDEFINED, // >= 0.15s +  UNDEFINED, // >= 0.5s +  UNDEFINED, // >= 1s +  UNDEFINED, // >= 5s +  UNDEFINED, // >= 15s +  }), +  }), + #endif +  }),    ({    UNDEFINED, -  +  ({ +  UNDEFINED,    SNMP.Gauge(lambda()    { return update_pike_memusage()->num_arrays; },    "pikeNumArrays",    "Number of pike arrays."),    SNMP.Gauge(lambda()    { return update_pike_memusage()->num_call_outs; },    "pikeNumCallOuts",    "Number of pike call outs."),    SNMP.Gauge(lambda()    { return update_pike_memusage()->num_callables; },    "pikeNumCallables",    "Number of pike callables."),    SNMP.Gauge(lambda()    { return update_pike_memusage()->num_callbacks; },    "pikeNumCallbacks",    "Number of pike callbacks."),    SNMP.Gauge(lambda() -  { return update_pike_memusage()->num_frames; }, +  { return update_pike_memusage()->num_pike_frames; },    "pikeNumFrames",    "Number of pike Frames."),    SNMP.Gauge(lambda()    { return update_pike_memusage()->num_mappings; },    "pikeNumMappings",    "Number of pike mappings."),    SNMP.Gauge(lambda()    { return update_pike_memusage()->num_multisets; },    "pikeNumMultisets",    "Number of pike multisets."),
Roxen.git/server/protocols/prot_snmp.pike:653:    return db_status("Slow_queries");    }, "numSlowQueries"),    }));    }   }      protected void setup_mib()   {    mib->merge(SystemMIB());    mib->merge(SNMPMIB()); -  mib->merge(RoxenGlobalMIB()); -  mib->merge(DBManagerMIB()); +  mib->merge(RoxenGlobalMIB()); // RIS_OID_WEBSERVER + ({ 1 }) +  mib->merge(DBManagerMIB()); // RIS_OID_WEBSERVER + ({ 1, 3 }) +  // Modules (cf configuration) // RIS_OID_WEBSERVER + ({ 2 }) +  mib->merge(cache.mib); // RIS_OID_WEBSERVER + ({ 3 })   }      #define SNMP_OP_GETREQUEST 0   #define SNMP_OP_GETNEXT 1   #define SNMP_OP_GETRESPONSE 2   #define SNMP_OP_SETREQUEST 3   #define SNMP_OP_TRAP 4      #define LOG_EVENT(txt, pkt) log_event(txt, pkt)   
Roxen.git/server/protocols/prot_snmp.pike:716:    if (version < 2) {    // 0: SNMPv1 RFC 1157    // 1: SNMPv2c RCC 1901, RFC 1905    object(Standards.ASN1.Types.Object) pdu = xdec->elements[2];    int errno = pdu->elements[1]->value;    return ([    "msgid": pdu->elements[0]->value,    "ip":rawd->ip,    "port":rawd->port,    "error-status":errno, -  "error-string":port_obj->snmp_errlist[errno], +  "error-string":port_obj->get_snmp_errlist()[errno],    "error-index":pdu->elements[2]->value,    "version":version,    "community":xdec->elements[1]->value,    "op":pdu->get_tag(),    "bindings":map(pdu->elements[3]->elements, Binding),    ]);       } else {    // 3: SNMPv3 RFC 2262, RFC 2272, RFC 2572, RFC 3412   
Roxen.git/server/protocols/prot_snmp.pike:746:   int writemsg(string rem_addr, int rem_port, int version,    Standards.ASN1.Types.Object pdu)   {    //: send SNMP encoded message and return status    //: OK, in most cases :)       object msg;    string rawd;    int msize;    -  msg = Standards.ASN1.Types.asn1_sequence(({ -  Standards.ASN1.Types.asn1_integer(version), -  Standards.ASN1.Types.asn1_octet_string(port_obj->snmp_community), +  msg = Standards.ASN1.Types.Sequence(({ +  Standards.ASN1.Types.Integer(version), +  Standards.ASN1.Types.OctetString(port_obj->snmp_community),    pdu}));       DWRITE("protocol.writemsg: %O\n", msg);       rawd = msg->get_der();       DWRITE("protocol.writemsg: %O:%O <== %O\n", rem_addr, rem_port, rawd);       msize = port_obj->send(rem_addr, rem_port, rawd);    return (msize = sizeof(rawd) ? SNMP_SUCCESS : SNMP_SEND_ERROR);
Roxen.git/server/protocols/prot_snmp.pike:787:    mapping origdata, int|void errcode, int|void erridx)   {    //: GetResponse-PDU low call    object pdu;    int id = origdata->msgid;    int flg;    array vararr = ({});       foreach(bindings, Binding binding) {    vararr += ({ -  Standards.ASN1.Types.asn1_sequence( +  Standards.ASN1.Types.Sequence(    ({ SNMP.OID(binding->oid),    binding->value,    })    )    });    }    -  pdu = Protocols.LDAP.ldap_privates.asn1_context_sequence(2, -  ({Standards.ASN1.Types.asn1_integer(id), // request-id -  Standards.ASN1.Types.asn1_integer(errcode), // error-status -  Standards.ASN1.Types.asn1_integer(erridx), // error-index -  Standards.ASN1.Types.asn1_sequence(vararr)}) +  pdu = SNMP.ContextSequence(2, +  ({Standards.ASN1.Types.Integer(id), // request-id +  Standards.ASN1.Types.Integer(errcode), // error-status +  Standards.ASN1.Types.Integer(erridx), // error-index +  Standards.ASN1.Types.Sequence(vararr)})    );       // now we have PDU ...    flg = writemsg(origdata->ip, origdata->port, origdata->version, pdu);       return id;   }    - protected void got_connection(mapping data) + // Called in a handler thread. + protected void low_got_connection(mapping data)   {    mapping pdata;    array rdata = ({});    int msgid, op, errnum = 0, setflg = 0;    string attrname = "0", comm;       SNMPAGENT_MSG("Got UDP data: %O\n", data);       snmpinpkts->value++;    pdata = decode_asn1_msg(data);
Roxen.git/server/protocols/prot_snmp.pike:932:    rdata = ({ Binding(pdata->bindings[0]->oid,    SNMP.OID(pdata->bindings[0]->oid)) });    }    send_response(rdata, pdata, errnum || 2 /*SNMP_NOSUCHNAME*/);    // future note: v2c, v3 protos want to return "endOfMibView"    } else {    send_response(rdata, pdata);    }   }    + protected void got_connection(mapping data) + { +  // NB: SNMP is UDP, so we don't need to care about +  // sequencing between multiple requests. +  +  // Make sure that we don't block the backend thread +  // by waiting for mutexes and similar... +  roxen.handle(low_got_connection, data); + } +    // NOTE: Code duplication from Protocol!   protected void bind(void|int ignore_eaddrinuse)   {    if (bound) return;    if (!port_obj) port_obj = SNMP_Port();    Privs privs = Privs (sprintf ("Binding %s", get_url()));    if (port_obj->bind(port, got_connection, ip))    {    privs = 0;    bound = 1;    setup_mib();    return;    }    privs = 0;   #if constant(System.EAFNOSUPPORT)    if (port_obj->errno() == System.EAFNOSUPPORT) {    // Fail permanently.    error("Invalid address " + ip);    }   #endif /* System.EAFNOSUPPORT */ - #if constant(System.EADDRINUSE) || constant(system.EADDRINUSE) -  if ( +    #if constant(System.EADDRINUSE) -  (port_obj->errno() == System.EADDRINUSE) - #else /* !constant(System.EADDRINUSE) */ -  (port_obj->errno() == system.EADDRINUSE) - #endif /* constant(System.EADDRINUSE) */ -  ) { -  if (!ignore_eaddrinuse && (retries++ < 10)) { +  if (port_obj->errno() == System.EADDRINUSE) { +  if (ignore_eaddrinuse) { +  // Told to ignore the bind problem. +  bound = -1; +  return; +  } +  if (retries++ < 10) {    // We may get spurious failures on rebinding ports on some OS'es    // (eg Linux, WIN32). See [bug 3031].    report_error(LOC_M(6, "Failed to bind %s (%s)")+"\n",    get_url(), strerror(port_obj->errno()));    report_notice(LOC_M(62, "Attempt %d. Retrying in 1 minute.")+"\n",    retries);    call_out(bind, 60);    }    }    else - #endif /* constant(System.EADDRINUSE) || constant(system.EADDRINUSE) */ + #endif /* constant(System.EADDRINUSE) */    {    report_error(LOC_M(6, "Failed to bind %s (%s)")+"\n",    get_url(), strerror(port_obj->errno()));   #if 0    werror (describe_backtrace (backtrace()));   #endif    }   }      void unref(string url)