#!/usr/bin/php
<?php
/*
   +-------------------------------------------------------------------------+
   | Copyright (C) 2004-2018 The Cacti Group                                 |
   |                                                                         |
   | This program is free software; you can redistribute it and/or           |
   | modify it under the terms of the GNU General Public License             |
   | as published by the Free Software Foundation; either version 2          |
   | of the License, or (at your option) any later version.                  |
   |                                                                         |
   | This program is snmpagent in the hope that it will be useful,           |
   | but WITHOUT ANY WARRANTY; without even the implied warranty of          |
   | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           |
   | GNU General Public License for more details.                            |
   +-------------------------------------------------------------------------+
   | Cacti: The Complete RRDtool-based Graphing Solution                     |
   +-------------------------------------------------------------------------+
   | This code is designed, written, and maintained by the Cacti Group. See  |
   | about.php and/or the AUTHORS file for specific developer information.   |
   +-------------------------------------------------------------------------+
   | http://www.cacti.net/                                                   |
   +-------------------------------------------------------------------------+
*/

/* do NOT run this script through a web browser */
if (!isset($_SERVER['argv'][0]) || isset($_SERVER['REQUEST_METHOD'])  || isset($_SERVER['REMOTE_ADDR'])) {
	die('<br><strong>This script is only meant to run at the command line.</strong>');
}

/* we are not talking to the browser */
$no_http_headers = true;

/* let's report all errors */
error_reporting(E_ALL);

/* allow the script to hang around waiting for connections. */
set_time_limit(0);
chdir(dirname(__FILE__));
include_once('./include/global.php');

/* translate well-known textual conventions and SNMP base types to net-snmp */
$smi_base_datatypes = array(
	'integer' 			=> 'INTEGER',
	'integer32'			=> 'Integer32',
	'unsigned32' 		=> 'Unsigned32',
	'gauge' 			=> 'Gauge',
	'gauge32' 			=> 'Gauge32',
	'counter' 			=> 'Counter',
	'counter32' 		=> 'Counter32',
	'counter64' 		=> 'Counter64',
	'timeticks' 		=> 'TimeTicks',
	'octect string' 	=> 'OCTET STRING',
	'opaque'			=> 'Opaque',
	'object identifier' => 'OBJECT IDENTIFIER',
	'ipaddress' 		=> 'IpAddress',
	'networkaddress' 	=> 'IpAddress',
	'bits' 				=> 'OCTET STRING',
	'displaystring' 	=> 'STRING',
	'physaddress' 		=> 'OCTET STRING',
	'macaddress' 		=> 'OCTET STRING',
	'truthvalue' 		=> 'INTEGER',
	'testandincr' 		=> 'Integer32',
	'autonomoustype' 	=> 'OBJECT IDENTIFIER',
	'variablepointer' 	=> 'OBJECT IDENTIFIER',
	'rowpointer' 		=> 'OBJECT IDENTIFIER',
	'rowstatus' 		=> 'INTEGER',
	'timestamp' 		=> 'TimeTicks',
	'timeinterval' 		=> 'Integer32',
	'dateandtime' 		=> 'STRING',
	'storagetype' 		=> 'INTEGER',
	'tdomain' 			=> 'OBJECT IDENTIFIER',
	'taddress' 			=> 'OCTET STRING'
);

$data				= false;
$eol				= "\n";
$cache  			= array();
$cache_last_refresh = false;



/* start background caching process if not running */
$php = read_config_option('path_php_binary');
$extra_args     = '-q "./snmpagent_mibcache.php"';

if(strstr(PHP_OS, 'WIN')) {
	/* windows part missing */
	pclose(popen("start \"CactiSNMPCache\" /I /B \"" . $php . "\" " . $extra_args, "r"));
} else {
	exec('ps -ef | grep -v grep | grep -v "sh -c" | grep snmpagent_mibcache.php', $output);
	if(!sizeof($output)) {
		exec($php . " " . $extra_args . " > /dev/null &");
	}
}


/* activate circular reference collector */
gc_enable();


while(1) {

	$input = trim(fgets(STDIN));
	switch($input) {
		case '':
			exit(0);
		case 'PING':
			fwrite(STDOUT, 'PONG' . $eol);
			cache_refresh();
			break;
		case 'get':
			$oid = trim(fgets(STDIN));
			if($data = cache_read($oid)) {
				fwrite(STDOUT, $oid . $eol . (isset($smi_base_datatypes[$data['type']]) ? $smi_base_datatypes[$data['type']] : 'INTEGER') . $eol . $data['value'] . $eol);
			}else {
				fwrite(STDOUT, 'NONE' . $eol);
			}
			break;
		case 'getnext':
			$oid = trim(fgets(STDIN));
			if( $next_oid = cache_get_next($oid)) {
				if($data = cache_read($next_oid)) {
					fwrite(STDOUT, $next_oid . $eol . (isset($smi_base_datatypes[$data['type']]) ? $smi_base_datatypes[$data['type']] : 'INTEGER') . $eol . $data['value'] . $eol);
			}else {
					 fwrite(STDOUT, 'NONE' . $eol);
				}
			}else {
				fwrite(STDOUT, 'NONE' . $eol);
				
			}
			break;
		case 'debug':
			fwrite(STDOUT, print_r($cache, true));
			break;
		case 'shutdown':
			fwrite(STDOUT, 'BYE' . $eol);
			exit(0);
	}
}

function cache_read($oid) {
	global $cache;
	return (isset($cache[$oid]) && $cache[$oid]) ? $cache[$oid] : false;
}

function cache_get_next($oid) {
	global $cache;
	return (isset($cache[$oid]['next'])) ? $cache[$oid]['next'] : false;
}

function cache_refresh() {
	global $config, $cache, $cache_last_refresh;

	$path_mibcache = $config['base_path'] . '/cache/mibcache/mibcache.tmp';
	$path_mibcache_lock = $config['base_path'] . '/cache/mibcache/mibcache.lock';

	/* check temporary cache file */
	clearstatcache();
	$cache_refresh_time = @filemtime( $path_mibcache );
	
	if($cache_refresh_time !== false) {
		/* initial phase */
		if( $cache_last_refresh === false || $cache_refresh_time > $cache_last_refresh ) {
			while( is_file( $path_mibcache_lock ) !== false ) {
				sleep(1);
				clearstatcache();
			}
			$cache = NULL;
			gc_collect_cycles();
			$cache_last_refresh = $cache_refresh_time;
			include( $path_mibcache );
		}
	}
	return;
}