#ifndef GUESSNET_UTIL_NETWATCHER_H
#define GUESSNET_UTIL_NETWATCHER_H

/*
 * Thread to capture packets from a network
 *
 * Copyright (C) 2003--2007  Enrico Zini <enrico@debian.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 */

#include <wibble/exception.h>
#include <wibble/sys/netbuffer.h>
#include <wibble/sys/mutex.h>
#include <wibble/sys/thread.h>
#include "nettypes.h"
#include "util/starter.h"
#include <string>
#include <list>

struct pcap;
typedef struct pcap pcap_t;

struct libnet_link_int;

namespace wibble {
namespace exception {

class Pcap : public Generic
{
protected:
	std::string _pcap_errmsg;

public:
	Pcap(const std::string& pcap_errmsg, const std::string& context) throw ()
		: Generic(context), _pcap_errmsg(pcap_errmsg) {}
	Pcap(const std::string& context) throw ()
		: Generic(context), _pcap_errmsg() {}
	~Pcap() throw () {}

	virtual const char* type() const throw () { return "pcap"; }

	virtual std::string desc() const throw ()
	{
		if (_pcap_errmsg.size())
			return _pcap_errmsg;
		else
			return "Unknown pcap error";
	}
};

}
}

namespace util {

class PacketListener
{
public:
	virtual ~PacketListener() {}
	virtual void handleARP(const wibble::sys::NetBuffer& pkt) {}
	virtual void handleDHCP(const wibble::sys::NetBuffer& pkt) {}
	virtual void handleICMP(const wibble::sys::NetBuffer& pkt) {}
	virtual void handleEthernet(const wibble::sys::NetBuffer& pkt) {}
};

/*
 * Injects ethernet packets to a given interface.
 *
 * Every method is thread-safe
 */
class NetWatcher : public wibble::sys::Thread, public util::Startable
{
protected:
	static const int captureSize;

	std::string iface;
	pcap_t *pcap_interface;
	bool _canceled;

	wibble::sys::Mutex listenersMutex;

	std::list<PacketListener*> listeners_arp;
	std::list<PacketListener*> listeners_ethernet;
	std::list<PacketListener*> listeners_dhcp;
	std::list<PacketListener*> listeners_icmp;

	struct libnet_link_int* link_interface;

	virtual void* main();
	
	NetWatcher(const std::string& iface);

public:
	~NetWatcher();

	void shutdown();

	struct ether_addr* getMACAddress();

	void addARPListener(PacketListener* pl);
	void addDHCPListener(PacketListener* pl);
	void addICMPListener(PacketListener* pl);
	void addEthernetListener(PacketListener* pl);

	void startableStart();
	void startableStop() { shutdown(); }

	static void configure(const std::string& iface);
	static NetWatcher& get();
};

}

// vim:set ts=4 sw=4:
#endif
