#!/usr/local/bin/perl
#
# Program: LDAP Ping <ldap-ping.pl>
#
# Author: Clay McClure <clay@daemons.net> && Ryan Matteson <matty@daemons.net>
#
# Current Version: 1.1
# 
# Revision History:
#
# Version 1.1
#     Added checks for arguments
#
# Version 1.0
#     Original release
#
# Last Updated: 10-20-2004
#
# Purpose:
#  Reports latency between a directory server and a given host
#
# License:
#   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, or (at your option) any
#   later version.
#
#   This program is distributed 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.
#
#   You should have received a copy of the GNU General Public License
#   along with this program; if not, write to the Free Software
#   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# Installation:
#   Install Net::LDAP, and copy the shell script to a suitable location
#
# Usage:
#   Usage: ldap-ping.pl [ -s server ] [ -p port ] [ -d delay ] [ -h ]
#
# Example:
#   ping.pl -s ldap.daemons.net -p 389 -d 10
#   Mon May 24 18:10:07 2004: new=0.008s, = bind=0.002s, search=0.017s, unbind=0.000s [local port=43080] [Normal Delay]
#   Mon May 24 18:10:17 2004: new=0.005s, = bind=0.000s, search=0.006s, unbind=0.000s [local port=43081] [Normal Delay]
#   Mon May 24 18:10:27 2004: new=0.005s, = bind=0.000s, search=0.006s, unbind=0.000s [local port=43082] [Normal Delay]
#

use Net::LDAP;
use Time::HiRes qw (time);
use Getopt::Std;

# Define the excessive_delay to use
my $excessive_delay = 1;

# Define the default time to wait if "-d" wasn't used
my $delay = 60;

# Pfiles and lsof binaries to get local port info
my $pfiles_binary = "/usr/in/pfiles";

# Define the host and port
my $host = 0, $port = 0;

%options=();
getopts("d:hp:s:",\%options);

if ( defined $options{d} ) {
        $delay  = $options{d};
}

if ( defined $options{p} ) {
        $port = $options{p};
}

if ( defined $options{s} ) {
        $server = $options{s};
}

if (defined $options{h} ) {
        printf("Usage: ldap-ping.pl [ -s server ] [ -p port ] [ -d delay ] [ -h ]\n");
        exit(1);
}

if ( ( ! $server ) || (! $port ) || ( ! $delay)) {
       printf("Usage: ldap-ping.pl [ -s server ] [ -p port ] [ -d delay ] [ -h ]\n");
        exit(1);
}

my $ldap = 0, $start = 0, $localport = 0;
my $new = 0, $bind = 0, $search = 0, $unbind = 0;

my @weekday = ("Sun", "Mon", "Tue", "Wed", "Thu" , "Fri", "Sat");
my @month   = ("Jan", "Feb", "Mar", "Apr", "May", "Jun",
               "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");

printf("Querying LDAP server $server:$port every $delay seconds (Ctrl-C to stop):\n");

while (1) {
        $start = time();
        $ldap = new Net::LDAP($server, port=> $port) or die($@);
        $new = time() - $start;

        $start = time();
        $ldap->bind(
                "base"     => "",
                "version"  => 3
        ) or die($@);
        $bind = time() - $start;

        $start = time();
        $ldap->search(
                "base"   => "",
                "filter" => "(objectclass=*)",
                "attrs"  => "cn",
                "scope"  => "base"
        ) or die($@);
        $search = time() - $start;

        $start = time();
        $ldap->unbind() or die($@);
        $unbind = time() - $start;

        # This bit gets out local TCP port number. lsof would also work.
        # sockname: AF_INET 192.168.1.1  port: 12345
        if ( -e $pfiles_binary ) {
		open(PFILES, "$pfiles_binary $$|");
        	while (<PFILES>) {
                	$localport = (split)[4] if /sockname/;
		}
		close(PFILES);
        }

        if (($new > $excessive_delay) || ($bind > $excessive_delay) || 
            ($search > $excessive_delay) || ($unbind > $excessive_delay)) {
           my ($ss, $mm, $hr, $md, $mo, $yr, $wd, $yd, $isdst) = localtime(time());
           my $dt = sprintf "%3s %3s %2.2d %2.2d:%2.2d:%2.2d %4.4d", $weekday[$wd], $month[$mo], $md, $hr, $mm, $ss, $yr+1900;
           printf("%s: new=%.3fs, = bind=%.3fs, search=%.3fs, unbind=%.3fs [local port=%d] [Excessive Delay]\n", $dt, $new, $bind, $search, $unbind, $localport);
        } else {
            my ($ss, $mm, $hr, $md, $mo, $yr, $wd, $yd, $isdst) = localtime(time());
            my $dt = sprintf "%3s %3s %2.2d %2.2d:%2.2d:%2.2d %4.4d", $weekday[$wd], $month[$mo], $md, $hr, $mm, $ss, $yr+1900;
            printf "%s: new=%.3fs, = bind=%.3fs, search=%.3fs, unbind=%.3fs [local port=%d] [Normal Delay]\n", $dt, $new, $bind, $search, $unbind, $localport;
        }

        sleep($delay);
}
