/*
 * This file implements the COVALENT-APACHE-APACHE-STATUS-MIB module.
 * $Id: apache-status-mib.c 8676 2008-01-17 23:11:17Z ispringer $
 * harrie@covalent.net
 */
 
#include <httpd.h>
#include "http_config.h"
#include <http_conf_globals.h>
#include <scoreboard.h>

/* SNMP includes */
#include "ucd-snmp-config.h"
#include "asn1.h"
#include "snmp.h"
#include "snmp_api.h"
#include "snmp_impl.h"
#include "snmp_debug.h"
#include "snmp_vars.h"
#include "var_struct.h"

/* Conductor includes */
#include "ietf-mibs/snmp-generic.h"
#include "covalent-snmp-config.h"
#include "covalent-snmp-logging.h"
#include "covalent-snmp-sconfig.h"
#include "covalent-snmp.h"
#include "apache-status-mib.h"

/* global objects of the server status */
#define SERVERSTATUSGENERATION         1

/* columnar objects of the csServerStatusTable */
#define SERVERSTATUSPROCESSID          2
#define SERVERSTATUSSTATUS             3
#define SERVERSTATUSACCESSCOUNT        4
#define SERVERSTATUSBYTESSERVED        5
#define SERVERSTATUSPROCESSACCESSCOUNT 6
#define SERVERSTATUSPROCESSBYTESSERVED 7
#define SERVERSTATUSCONNECTIONBYTES    8
#define SERVERSTATUSCONNECTIONCOUNT    9
#define SERVERSTATUSSTARTTIME          10
#define SERVERSTATUSSTOPTIME           11
#define SERVERSTATUSCLIENT             12
#define SERVERSTATUSREQUEST            13
#define SERVERSTATUSVIRTUALHOST        14

#ifdef COVALENT_APACHE_STATUS_MIB

global_score *globalscore_ptr =  NULL;
parent_score *parent_score_array_ptr = NULL;
short_score  *short_score_array_ptr = NULL;

unsigned char *
read_csServerStatusGlobals(
    struct variable *vp,
    oid     *name,
    size_t  *length,
    int     exact,
    size_t  *var_len,
    WriteMethod **write_method)
{
int result;

    DEBUGMSGTL(("sever-status-mib", "read_csServerStatusGlobals: "));
    DEBUGMSGOID(("sever-status-mib", name, *length));
    DEBUGMSG(("sever-status-mib"," %s\n", (exact ? "exact" : "next")));

    result = snmp_oid_compare(name, *length, vp->name, vp->namelen);
    if ((exact && (result != 0)) || (!exact && (result >= 0)))
        return(NULL);
    memcpy((char *)name,(char *)vp->name, vp->namelen * sizeof(oid));
    *length = vp->namelen;
    *write_method = NULL;
    *var_len = sizeof(long_return);

    switch (vp->magic) {
        case SERVERSTATUSGENERATION:
            if (globalscore_ptr) {
                *var_len = sizeof(long);
		long_return = globalscore_ptr->running_generation;
                return (unsigned char *) &long_return;
            }
            return(NULL);
    }
    return NULL;
}

int
create_ServerStatus_Index(struct variable *vp,
        oid *name, size_t *namelength,
        oid *newname, size_t *newname_length,
        int exact)
{
oid *ptr;
int result;
int i;

    DEBUGMSGTL(("create_ServerStatus_Index", "Index creation"));
    DEBUGMSGOID(("create_ServerStatus_Index", name, *namelength));
    DEBUGMSG(("create_ServerStatus_Index"," exact=%d\n", exact));

    *newname_length = vp->namelen;
    ptr = &(newname[ (*newname_length)++ ]);
    memcpy((char *)newname, (char *)vp->name, *newname_length * sizeof(oid));
    for ( i=0 ; i < derived_hard_server_limit; i++) {
	if (parent_score_array_ptr[ i ].pid || ap_scoreboard_image->servers[ i ].access_count) {
	    *ptr = i + 1;
            result = snmp_oid_compare(name, *namelength, newname, *newname_length);
	    if ((exact && (result == 0)) || (!exact && (result < 0))) {
		return(i);
	    }
	}
    }
    return(-1);
}	

unsigned char *
read_csServerStatusEntry(
    struct variable *vp,
    oid     *name,
    size_t  *length,
    int     exact,
    size_t  *var_len,
    WriteMethod **write_method)
{
oid newname[ MAX_OID_LEN ];
size_t newname_length;
int		slot_index;
server_rec	*vh;

    ap_sync_scoreboard_image();
    slot_index = create_ServerStatus_Index(vp, name, length,
					newname, &newname_length, exact);
    if (slot_index < 0) {
	return(NULL);
    }
    *length = newname_length;
    memcpy( (char *)name,(char *)newname, *length * sizeof(oid));
    *write_method = 0;
    switch (vp->magic) {
	case SERVERSTATUSPROCESSID:
	    *var_len = sizeof(pid_t);
	    return (unsigned char *) &(parent_score_array_ptr[ slot_index ].pid);
	case SERVERSTATUSSTATUS:
	    *var_len = sizeof(long_return);
	    long_return = ap_scoreboard_image->servers[ slot_index ].status + 1;
	    return (unsigned char *) &(long_return);
	case SERVERSTATUSACCESSCOUNT:
	    *var_len = sizeof(long_return);
            long_return = ap_scoreboard_image->servers[ slot_index ].access_count;
            return (unsigned char *) &(long_return);
	case SERVERSTATUSBYTESSERVED:
	    *var_len = sizeof(long_return);
            long_return = ap_scoreboard_image->servers[ slot_index ].bytes_served;
            return (unsigned char *) &(long_return);
	case SERVERSTATUSPROCESSACCESSCOUNT:
	    *var_len = sizeof(long_return);
            long_return = ap_scoreboard_image->servers[ slot_index ].my_access_count;
            return (unsigned char *) &(long_return);
	case SERVERSTATUSPROCESSBYTESSERVED:
	    *var_len = sizeof(long_return);
            long_return = ap_scoreboard_image->servers[ slot_index ].my_bytes_served;
            return (unsigned char *) &(long_return);
	case SERVERSTATUSCONNECTIONBYTES:
	    *var_len = sizeof(long_return);
            long_return = ap_scoreboard_image->servers[ slot_index ].conn_bytes;
            return (unsigned char *) &(long_return);
	case SERVERSTATUSCONNECTIONCOUNT:
	    *var_len = sizeof(long_return);
            long_return = ap_scoreboard_image->servers[ slot_index ].conn_count;
            return (unsigned char *) &(long_return);
/* Currently not implemented correctly!!
	case SERVERSTATUSSTARTTIME:
	    *var_len = sizeof(long_return);
            long_return = ap_scoreboard_image->servers[ slot_index ].start_time;
            return (unsigned char *) &(long_return);
	case SERVERSTATUSSTOPTIME:
	    *var_len = sizeof(long_return);
            long_return = ap_scoreboard_image->servers[ slot_index ].stop_time;
            return (unsigned char *) &(long_return);
*/
	case SERVERSTATUSCLIENT:
	    *var_len = strlen(ap_scoreboard_image->servers[ slot_index ].client);
	    return (unsigned char *) ap_scoreboard_image->servers[ slot_index ].client;
	case SERVERSTATUSREQUEST:
	    *var_len = strlen(ap_scoreboard_image->servers[ slot_index ].request);
	    return (unsigned char *) ap_scoreboard_image->servers[ slot_index ].request;
	case SERVERSTATUSVIRTUALHOST:
	    long_return = 0;
            if (parent_score_array_ptr[ slot_index ].generation
			 == ap_my_generation) {
	        vh = ap_scoreboard_image->servers[ slot_index ].vhostrec;
		if (vh != NULL) {
		    long_return = get_sconfig_wwwServiceIndex(vh);
		}
	    }
	    *var_len = sizeof(long_return);
	    return (unsigned char *) &long_return;
        default:
            return NULL;
    }
}

static oid covalentServerStatusMIB_oid[] = { 1, 3, 6, 1, 4, 1, 6100, 4 };
static oid csServerStatusGlobals_oid[] = {1, 3, 6, 1, 4, 1, 6100, 4, 1, 1};
struct variable2 csServerStatusGlobals_variables[] = {
    { SERVERSTATUSGENERATION, ASN_UNSIGNED, RONLY, read_csServerStatusGlobals, 2, {1, 0} }
};
static oid csServerStatusEntry_oid[] = { 1, 3, 6, 1, 4, 1, 6100, 4, 1, 2, 1 };
static struct variable2 csServerStatusEntry_variables[] = {
    { SERVERSTATUSPROCESSID, ASN_UNSIGNED, RONLY, read_csServerStatusEntry, 1, {2} },
    { SERVERSTATUSSTATUS, ASN_INTEGER, RONLY, read_csServerStatusEntry, 1, {3} },
    { SERVERSTATUSACCESSCOUNT, ASN_COUNTER, RONLY, read_csServerStatusEntry, 1, {4} },
    { SERVERSTATUSBYTESSERVED, ASN_COUNTER, RONLY, read_csServerStatusEntry, 1, {5} },
    { SERVERSTATUSPROCESSACCESSCOUNT, ASN_COUNTER, RONLY, read_csServerStatusEntry, 1, {6} },
    { SERVERSTATUSPROCESSBYTESSERVED, ASN_COUNTER, RONLY, read_csServerStatusEntry, 1, {7} },
    { SERVERSTATUSCONNECTIONBYTES, ASN_COUNTER, RONLY, read_csServerStatusEntry, 1, {8} },
    { SERVERSTATUSCONNECTIONCOUNT, ASN_COUNTER, RONLY, read_csServerStatusEntry, 1, {9} },
    { SERVERSTATUSSTARTTIME, ASN_TIMETICKS, RONLY, read_csServerStatusEntry, 1, {10} },
    { SERVERSTATUSSTOPTIME, ASN_TIMETICKS, RONLY, read_csServerStatusEntry, 1, {11} },
    { SERVERSTATUSCLIENT, ASN_OCTET_STR, RONLY, read_csServerStatusEntry, 1, {12} },
    { SERVERSTATUSREQUEST, ASN_OCTET_STR, RONLY, read_csServerStatusEntry, 1, {13} },
    { SERVERSTATUSVIRTUALHOST, ASN_UNSIGNED, RONLY, read_csServerStatusEntry, 1, {14} }
};

void
init_covalent_apache_status_mib()
{
unsigned long offset_parentscore;
unsigned long offset_globalscore;

    DEBUGMSGTL(("covalent/serverstatus-mib", "init_apache_serverstatus-mib"));
    offset_parentscore = (sizeof(short_score) * derived_hard_server_limit);
    offset_globalscore = ((sizeof(short_score) + sizeof(parent_score)) * derived_hard_server_limit);
    globalscore_ptr = (global_score *) ((long) ap_scoreboard_image + (long) offset_globalscore);
    parent_score_array_ptr = (parent_score *) ((long) ap_scoreboard_image + (long) offset_parentscore);
    REGISTER_MIB("covalent-serverstatus-mib/csServerStatusGlobals",
		csServerStatusGlobals_variables, variable2,
		csServerStatusGlobals_oid);
    REGISTER_MIB("covalent-serverstatus-mib/csServerStatusTable",
		csServerStatusEntry_variables, variable2,
		csServerStatusEntry_oid);
#ifdef USING_MIBII_SYSORTABLE_MODULE
    register_sysORTable(covalentServerStatusMIB_oid, 8,
		"The Covalent Apache Server Status MIB module");
#endif /* USING_MIBII_SYSORTABLE_MODULE */
}

#endif /* COVALENT_APACHE_STATUS_MIB */

