/*
 * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 Yokogawa Electric Corporation,
 * YDC Corporation, IPA (Information-technology Promotion Agency, Japan).
 * All rights reserved.
 * 
 * Redistribution and use of this software in source and binary forms, with 
 * or without modification, are permitted provided that the following 
 * conditions and disclaimer are agreed and accepted by the user:
 * 
 * 1. Redistributions of source code must retain the above copyright 
 * notice, this list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the following disclaimer in the 
 * documentation and/or other materials provided with the distribution.
 * 
 * 3. Neither the names of the copyrighters, the name of the project which 
 * is related to this software (hereinafter referred to as "project") nor 
 * the names of the contributors may be used to endorse or promote products 
 * derived from this software without specific prior written permission.
 * 
 * 4. No merchantable use may be permitted without prior written 
 * notification to the copyrighters. However, using this software for the 
 * purpose of testing or evaluating any products including merchantable 
 * products may be permitted without any notification to the copyrighters.
 * 
 * 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHTERS, THE PROJECT AND 
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING 
 * BUT NOT LIMITED THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 * FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.  IN NO EVENT SHALL THE 
 * COPYRIGHTERS, THE PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT,STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
 * THE POSSIBILITY OF SUCH DAMAGE.
 *
 * $TAHI: v6eval/lib/pkt/PktServer.cc,v 1.19 2003/10/23 04:37:31 akisada Exp $
 */
#include <stdio.h>
#include <time.h>
#include "PktServer.h"
#include <sys/types.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <net/bpf.h>
#include <unistd.h>
#include "CmDispatch.h"
#include "CmMain.h"
#include "timeval.h"

PktAccept::PktAccept(PktBuf *p):PktAgent(),accepts_(new PktAgentSet(defaultPktClient)), bpf_(p){}
PktAccept::~PktAccept() {}

void PktAccept::addAgent(PktAgent* a) {
	accepts_->add(a);}

void PktAccept::removeAgent(PktAgent* a) {
	accepts_->remove(a);}

//======================================================================
// STARTING SERVICE
int PktAccept::listen(){
	CmSocket* s=socket();
	int rc=s->listen();
	if(rc<0) return rc;
	s->setReuseAddrOpt();
	if(DBGFLAGS('c')) {printf("PktAccept::listen"); s->print();}
	readAction((agentFunc)&PktAccept::accept);
	return rc;}

//======================================================================
// ESTABLISH THE CONNECTION
int PktAccept::accept() {
	CmSocket* sock=socket()->accept();
	if(sock!=0) {
		PktServer* agent=new PktServer(sock,this,bpf_);
		addAgent(agent);
		agent->receiver();}
	return 0;}

int PktAccept::terminate() {
	int rc=PktAgent::terminate();
	return rc;}

//======================================================================
PktServer::PktServer(CmSocket* s,PktAccept* a,PktBuf *bpf):PktReceiver(s),accepter_(a),bpfbuf_(bpf),pktbuf_(bpf) {
        timerAction((timerFunc)&PktServer::timeout);}

PktServer::~PktServer() {
	if(pktbuf_->readwait_==this)
		pktbuf_->readwait(0);
	dispatch()->stopTimer(this);
	accepter_->removeAgent(this);}

int PktServer::terminate() {
	accepter_->removeAgent(this);
	int rc=PktReceiver::terminate();
	delete this;
	return rc;}
	
//======================================================================
// Connect Request
int PktServer::connectRequest() {
	return response(0,0,NULL);}
//======================================================================
// Write Request
int PktServer::writeRequest() {
	timeval sendtime;
	bpfbuf_->write(buffer(0),header().length());
	gettimeofday(&sendtime,NULL);
	sendtime.tv_sec=htonl(sendtime.tv_sec);
	sendtime.tv_usec=htonl(sendtime.tv_usec);
	return (response(0,sizeof(sendtime),(STR)&sendtime));}
//======================================================================
// Read Request
int PktServer::readRequest() {
	// get timeout time */
	timeval tv;
	if(header().length()!=0){
		timeval &tvreq = *(timeval*)buffer(0);
		tv.tv_sec = ntohl(tvreq.tv_sec);
		tv.tv_usec = ntohl(tvreq.tv_usec);}
	// get recieve time of oldest data.
	timeval *tvdata =bpfbuf_->ReceiveTimeOfOldestData();
	if(tvdata==0){  // Buffer is Empty.
		pktbuf_->readwait(this);
		if(header().length()!=0){
			// set timeout time
			dispatch()->startTimerByAbsoluteTime(tv,this);}
		return 0;}

	if(header().length()!=0 && *tvdata > tv){
		// timeout
		return(response(2,0,0));}

	char tmp[bpfbuf_->maxdatasize()];
	int len=bpfbuf_->read(tmp,sizeof(tmp));
	if(len==0) { abort(); }
	return(readResponse(tmp,len));}

int PktServer::readResponse(char *p, int32_t size) {
	struct bpf_hdr* hdr=(bpf_hdr*)p;
	const struct bpf_hdr hdrorg=*hdr;
	hdr->bh_tstamp.tv_sec=htonl(hdrorg.bh_tstamp.tv_sec);
	hdr->bh_tstamp.tv_usec=htonl(hdrorg.bh_tstamp.tv_usec);
	hdr->bh_caplen=htonl(hdrorg.bh_caplen);
	hdr->bh_datalen=htonl(hdrorg.bh_datalen);
	hdr->bh_hdrlen=htons(hdrorg.bh_hdrlen);
	dispatch()->stopTimer(this);
	return(response(0,size,p));}

int PktServer::timeout(time_t ,uint32_t) {
	pktbuf_->readwait(0);
	return(response(2,0,0));}

//======================================================================
// Status Request
int PktServer::statusRequest() {
	struct bufStat stat = bpfbuf_->stat();
	return(response(0,sizeof(stat),(char *)(&stat)));}
// Wrap Request
int PktServer::wrapRequest() {
	bpfbuf_->setWrapMode();
	return(response(0,0,0));}

// noWrap Request
int PktServer::nowrapRequest() {
	bpfbuf_->setNowrapMode();
	return(response(0,0,0));}

// clear Request
int PktServer::clearRequest() {
	bpfbuf_->clear();
	return(response(0,0,0));}

// capture Request
int PktServer::captureRequest() {
	bpfbuf_->capture();
	return(response(0,0,0));}

// stop Request
int PktServer::stopRequest() {
	bpfbuf_->stop();
	return(response(0,0,0));}

// dump Request
int PktServer::dumpRequest() {
	uint32_t dp=ntohl(*(uint32_t *)buffer(0));
	uint32_t datanum = (bpfbuf_->stat()).datanum();
	char tmp[bpfbuf_->maxdatasize()];
	int size=bpfbuf_->readn(tmp,dp);
	if(size!=0){
		// convert network byte order
		struct bpf_hdr* hdr=(bpf_hdr*)tmp;
		const struct bpf_hdr hdrorg=*hdr;
		hdr->bh_tstamp.tv_sec=htonl(hdrorg.bh_tstamp.tv_sec);
		hdr->bh_tstamp.tv_usec=htonl(hdrorg.bh_tstamp.tv_usec);
		hdr->bh_caplen=htonl(hdrorg.bh_caplen);
		hdr->bh_datalen=htonl(hdrorg.bh_datalen);
		hdr->bh_hdrlen=htons(hdrorg.bh_hdrlen);
	}
	if(size==0||++dp >= datanum) dp=0; // buffer has more data
	return(response(dp,size,tmp));}


syntax highlighted by Code2HTML, v. 0.9.1