#include "protoApp.h"
#include "protoCap.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
class ProtoCapExample : public ProtoApp
{
public:
ProtoCapExample();
~ProtoCapExample();
bool OnStartup(int argc, const char*const* argv);
bool ProcessCommands(int argc, const char*const* argv);
void OnShutdown();
private:
enum CmdType {CMD_INVALID, CMD_ARG, CMD_NOARG};
static const char* const CMD_LIST[];
static CmdType GetCmdType(const char* string);
bool OnCommand(const char* cmd, const char* val);
void Usage();
void OnReceive(ProtoChannel& theChannel,
ProtoChannel::Notification notifyType);
bool OnStatTimeout(ProtoTimer& theTimer);
char rcvr_interface[64];
char sndr_interface[64];
ProtoCap* cap_rcvr; ProtoCap* cap_sndr; ProtoCap* cap_fwdr; bool forward;
unsigned int recv_count;
unsigned int send_count;
unsigned int serr_count;
ProtoTimer stat_timer;
};
PROTO_INSTANTIATE_APP(ProtoCapExample)
ProtoCapExample::ProtoCapExample()
: cap_rcvr(NULL), cap_sndr(NULL), cap_fwdr(NULL),
forward(false), recv_count(0), send_count(0), serr_count(0)
{
stat_timer.SetListener(this, &ProtoCapExample::OnStatTimeout);
stat_timer.SetInterval(1.0);
stat_timer.SetRepeat(-1);
}
ProtoCapExample::~ProtoCapExample()
{
}
void ProtoCapExample::Usage()
{
#ifdef WIN32
fprintf(stderr, "protoCapExample [listen <interfaceName> [{forward | bridge} <interfaceName>]][background]\n");
#else
fprintf(stderr, "protoCapExample [listen <interfaceName> [{forward | bridge} <interfaceName>]]\n");
#endif }
const char* const ProtoCapExample::CMD_LIST[] =
{
"+listen", "+forward", "+bridge", NULL
};
ProtoCapExample::CmdType ProtoCapExample::GetCmdType(const char* cmd)
{
if (!cmd) return CMD_INVALID;
unsigned int len = strlen(cmd);
bool matched = false;
CmdType type = CMD_INVALID;
const char* const* nextCmd = CMD_LIST;
while (*nextCmd)
{
if (!strncmp(cmd, *nextCmd+1, len))
{
if (matched)
{
return CMD_INVALID;
}
else
{
matched = true;
if ('+' == *nextCmd[0])
type = CMD_ARG;
else
type = CMD_NOARG;
}
}
nextCmd++;
}
return type;
}
bool ProtoCapExample::OnStartup(int argc, const char*const* argv)
{
#ifdef _WIN32_WCE
Sleep(1000); #endif
char ifName[256];
ProtoAddress localAddress;
if (localAddress.ResolveLocalAddress())
{
ProtoSocket dummySocket(ProtoSocket::UDP);
unsigned int index = dummySocket.GetInterfaceIndex(localAddress.GetHostString());
TRACE("protoCapExample: got interface index:%d for interface: %s\n",
index, localAddress.GetHostString());
ifName[255] = '\0';
if (dummySocket.GetInterfaceName(index, ifName, 255))
{
TRACE(" (real interface name: \"%s\")\n", ifName);
}
ProtoAddress ethAddr;
if (dummySocket.GetInterfaceAddress(ifName, ProtoAddress::ETH, ethAddr))
{
TRACE(" (interface MAC addr: \"%s\")\n", ethAddr.GetHostString());
}
}
if (!(cap_rcvr = ProtoCap::Create()))
{
PLOG(PL_ERROR, "protoCapExample::OnStartup() new ProtoCap cap_rcvr error: %s\n", GetErrorString());
return false;
}
cap_rcvr->SetListener(this, &ProtoCapExample::OnReceive);
cap_rcvr->SetNotifier(static_cast<ProtoChannel::Notifier*>(&dispatcher));
if (!(cap_sndr = ProtoCap::Create()))
{
PLOG(PL_ERROR, "protoCapExample::OnStartup() new ProtoCap cap_sndr error: %s\n", GetErrorString());
return false;
}
if (!ProcessCommands(argc, argv))
{
PLOG(PL_ERROR, "protoCapExample: Error! bad command line\n");
return false;
}
#ifdef HAVE_SCHED
struct sched_param schp;
memset(&schp, 0, sizeof(schp));
schp.sched_priority = sched_get_priority_max(SCHED_FIFO);
if (sched_setscheduler(0, SCHED_FIFO, &schp))
{
schp.sched_priority = sched_get_priority_max(SCHED_OTHER);
if (sched_setscheduler(0, SCHED_OTHER, &schp))
PLOG(PL_ERROR, "protoCapExample: Warning! Couldn't set any real-time priority: %s\n", GetErrorString());
}
#endif
#ifdef WIN32
#ifndef _WIN32_WCE
if (!SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS))
PLOG(PL_ERROR, "protoCapExample: Warning! SetPriorityClass() error: %s\n", GetErrorString());
#endif if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL))
PLOG(PL_ERROR, "protoCapExample: Warning! SetThreadPriority() error: %s\n", GetErrorString());
#endif
return true;
}
void ProtoCapExample::OnShutdown()
{
if (NULL != cap_rcvr)
{
cap_rcvr->Close();
delete cap_rcvr;
cap_rcvr = NULL;
}
if (NULL != cap_sndr)
{
cap_sndr->Close();
delete cap_sndr;
cap_sndr = NULL;
}
PLOG(PL_ERROR, "protoCapExample: Done.\n");
CloseDebugLog();
}
bool ProtoCapExample::ProcessCommands(int argc, const char*const* argv)
{
int i = 1;
while ( i < argc)
{
switch (GetCmdType(argv[i]))
{
case CMD_INVALID:
{
PLOG(PL_ERROR, "ProtoCapExample::ProcessCommands() Invalid command:%s\n",
argv[i]);
return false;
}
case CMD_NOARG:
if (!OnCommand(argv[i], NULL))
{
PLOG(PL_ERROR, "ProtoCapExample::ProcessCommands() ProcessCommand(%s) error\n",
argv[i]);
return false;
}
i++;
break;
case CMD_ARG:
if (!OnCommand(argv[i], argv[i+1]))
{
PLOG(PL_ERROR, "ProtoCapExample::ProcessCommands() ProcessCommand(%s, %s) error\n",
argv[i], argv[i+1]);
return false;
}
i += 2;
break;
}
}
return true;
}
bool ProtoCapExample::OnCommand(const char* cmd, const char* val)
{
CmdType type = GetCmdType(cmd);
ASSERT(CMD_INVALID != type);
unsigned int len = strlen(cmd);
if ((CMD_ARG == type) && !val)
{
PLOG(PL_ERROR, "ProtoCapExample::ProcessCommand(%s) missing argument\n", cmd);
return false;
}
else if (!strncmp("listen", cmd, len))
{
int ifIndex = ProtoSocket::GetInterfaceIndex(val);
char ifName[256];
ifName[255] = '\0';
if (!ProtoSocket::GetInterfaceName(ifIndex, ifName, 255))
{
PLOG(PL_ERROR, "protoCapExample: invalid <interfaceName>\n");
return false;
}
if (!cap_rcvr->Open(ifName))
{
PLOG(PL_ERROR, "protoCapExample: ProtoCap::Open() error.\n");
return false;
}
strncpy(rcvr_interface, ifName, 64);
rcvr_interface[62] = '\0';
TRACE("protoCapExample: listening to interface: %s...\n", ifName);
if (!stat_timer.IsActive()) ActivateTimer(stat_timer);
}
else if (!strncmp("forward", cmd, len))
{
if (!cap_rcvr->IsOpen())
{
PLOG(PL_ERROR, "protoCapExample: command line error: must specify \"listen\" first\n");
Usage();
return false;
}
int ifIndex = ProtoSocket::GetInterfaceIndex(val);
char ifName[256];
ifName[255] = '\0';
if (!ProtoSocket::GetInterfaceName(ifIndex, ifName, 255))
{
PLOG(PL_ERROR, "protoCapExample: invalid <interfaceName>\n");
return false;
}
if (!strncmp(ifName, rcvr_interface, 64))
{
cap_fwdr = cap_rcvr;
}
else
{
if (!cap_sndr->Open(ifName))
{
PLOG(PL_ERROR, "protoCapExample: ProtoCap::Open() error.\n");
return false;
}
cap_fwdr = cap_sndr;
}
strncpy(sndr_interface, ifName, 64);
sndr_interface[62] = '\0';
forward = true;
TRACE("protoCapExample: forwarding to interface: %s...\n", ifName);
}
else if (!strncmp("bridge", cmd, len))
{
if (!cap_rcvr->IsOpen())
{
PLOG(PL_ERROR, "protoCapExample: command line error: must specify \"listen\" first\n");
Usage();
return false;
}
int ifIndex = ProtoSocket::GetInterfaceIndex(val);
char ifName[256];
ifName[255] = '\0';
if (!ProtoSocket::GetInterfaceName(ifIndex, ifName, 255))
{
PLOG(PL_ERROR, "protoCapExample: invalid <interfaceName>\n");
return false;
}
if (!strncmp(ifName, rcvr_interface, 64))
{
cap_fwdr = cap_rcvr;
}
else
{
if (!cap_sndr->Open(ifName))
{
PLOG(PL_ERROR, "protoCapExample: ProtoCap::Open() error.\n");
return false;
}
cap_fwdr = cap_sndr;
}
strncpy(sndr_interface, ifName, 64);
sndr_interface[62] = '\0';
forward = false;
TRACE("protoCapExample: bridging to interface: %s...\n", ifName);
}
else
{
PLOG(PL_ERROR, "protoCapExample:: invalid command\n");
return false;
}
return true;
}
void ProtoCapExample::OnReceive(ProtoChannel& theChannel,
ProtoChannel::Notification notifyType)
{
if (ProtoChannel::NOTIFY_INPUT == notifyType)
{
char buffer[4096];
unsigned int numBytes;
do
{
numBytes = 4096;
ProtoCap::Direction direction;
if (!cap_rcvr->Recv(buffer, numBytes, &direction))
{
PLOG(PL_ERROR, "protoCapExample::OnReceive() ProtoCap::Recv() error\n");
break;
}
else if (0 != numBytes)
{
recv_count++;
if (cap_fwdr)
{
UINT16 type;
memcpy(&type, buffer+12, 2);
type = ntohs(type);
if ((ProtoCap::INBOUND == direction) && (0 != numBytes) && (type > 0x05dc))
{
if (forward)
{
if (cap_fwdr->Forward(buffer, numBytes))
send_count++;
else
serr_count++;
}
else {
if (cap_fwdr->Send(buffer, numBytes))
send_count++;
else
serr_count++;
}
}
}
}
} while (0 != numBytes);
}
else
{
TRACE("ProtoCapExample::OnReceive() unhandled notifyType: %d\n", notifyType);
}
}
bool ProtoCapExample::OnStatTimeout(ProtoTimer& )
{
TRACE("stats: rcvd>%lu sent>%lu serr>%lu\n", recv_count, send_count, serr_count);
return true;
}