Created V0.3.x branch and moved the head into the trunk directory.

git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@246 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
drbob 2007-11-15 03:18:48 +00:00
commit 935745a08e
1318 changed files with 348809 additions and 0 deletions

View file

@ -0,0 +1,26 @@
RS_TOP_DIR = ..
include ../make.opt
OBJ = upnphandler.o upnputil.o
CFLAGS += -I$(UPNPC_DIR) -DMINIUPNP_EXPORTS
all : $(OBJ) librs upnptest
upnptest: $(OBJ) upnptest.o
$(CC) $(CFLAGS) -o upnptest $(OBJ) upnptest.o $(RSLIBS)
librs: $(OBJ)
$(AR) r $(LIBRS) $(OBJ)
$(RANLIB) $(LIBRS)
.cc.o:
$(CC) $(CFLAGS) -c $<
clean:
-/bin/rm $(OBJ) upnptest.o
clobber: clean
-/bin/rm upnptest

View file

@ -0,0 +1,356 @@
#include "dht/dhthandler.h"
/* This stuff is actually C */
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
} /* extern C */
#endif
/* This stuff is actually C */
/* HACK TO SWITCH THIS OFF during testing */
/*define NO_UPNP_RUNNING 1*/
#include "upnp/upnputil.h"
#include "upnp/upnphandler.h"
class uPnPConfigData
{
public:
struct UPNPDev * devlist;
struct UPNPUrls urls;
struct IGDdatas data;
char lanaddr[16]; /* my ip address on the LAN */
};
#include <iostream>
#include <sstream>
void upnphandler::run()
{
/* infinite loop */
while(1)
{
std::cerr << "UPnPHandler::Run()" << std::endl;
int allowedSleep = 30; /* check every 30 seconds */
/* lock it up */
dataMtx.lock(); /* LOCK MUTEX */
bool shutdown = toShutdown;
int state = upnpState;
dataMtx.unlock(); /* UNLOCK MUTEX */
if (shutdown)
{
return;
}
/* do the work! */
checkUPnPState();
/* check new state for sleep period */
dataMtx.lock(); /* LOCK MUTEX */
state = upnpState;
dataMtx.unlock(); /* UNLOCK MUTEX */
/* state machine */
switch(state)
{
case RS_UPNP_S_UNINITIALISED:
case RS_UPNP_S_UNAVAILABLE:
/* failed ... try again in 30 min. */
allowedSleep = 1800;
break;
case RS_UPNP_S_READY:
case RS_UPNP_S_TCP_FAILED:
case RS_UPNP_S_UDP_FAILED:
case RS_UPNP_S_ACTIVE:
/* working ... normal 15 seconds */
allowedSleep = 15;
break;
default:
/* default??? how did it get here? */
break;
}
std::cerr << "UPnPHandler::Run() sleeping for:" << allowedSleep << std::endl;
/********************************** WINDOWS/UNIX SPECIFIC PART ******************/
#ifndef WINDOWS_SYS
sleep(allowedSleep);
#else
Sleep(1000 * allowedSleep);
#endif
/********************************** WINDOWS/UNIX SPECIFIC PART ******************/
}
return;
}
void upnphandler::checkUPnPState()
{
dataMtx.lock(); /* LOCK MUTEX */
int state = upnpState;
dataMtx.unlock(); /* UNLOCK MUTEX */
/* state machine */
switch(state)
{
case RS_UPNP_S_UNINITIALISED:
case RS_UPNP_S_UNAVAILABLE:
initUPnPState();
break;
case RS_UPNP_S_READY:
case RS_UPNP_S_TCP_FAILED:
case RS_UPNP_S_UDP_FAILED:
case RS_UPNP_S_ACTIVE:
printUPnPState();
updateUPnP();
break;
}
return;
}
bool upnphandler::initUPnPState()
{
/* allocate memory */
uPnPConfigData *upcd = new uPnPConfigData;
upcd->devlist = upnpDiscover(2000);
if(upcd->devlist)
{
struct UPNPDev * device;
printf("List of UPNP devices found on the network :\n");
for(device=upcd->devlist;device;device=device->pNext)
{
printf("\n desc: %s\n st: %s\n",
device->descURL, device->st);
}
putchar('\n');
if(UPNP_GetValidIGD(upcd->devlist, &(upcd->urls),
&(upcd->data), upcd->lanaddr,
sizeof(upcd->lanaddr)))
{
printf("Found valid IGD : %s\n",
upcd->urls.controlURL);
printf("Local LAN ip address : %s\n",
upcd->lanaddr);
/* MODIFY STATE */
dataMtx.lock(); /* LOCK MUTEX */
/* convert to ipaddress. */
inet_aton(upcd->lanaddr, &(upnp_iaddr.sin_addr));
upnp_iaddr.sin_port = iaddr.sin_port;
upnpState = RS_UPNP_S_READY;
upnpConfig = upcd; /* */
dataMtx.unlock(); /* UNLOCK MUTEX */
/* done -> READY */
return 1;
}
else
{
fprintf(stderr, "No valid UPNP Internet Gateway Device found.\n");
}
freeUPNPDevlist(upcd->devlist);
upcd->devlist = 0;
}
else
{
fprintf(stderr, "No IGD UPnP Device found on the network !\n");
}
upnpState = RS_UPNP_S_UNAVAILABLE;
delete upcd;
upnpConfig = NULL;
/* done, FAILED -> NOT AVAILABLE */
return 0;
}
bool upnphandler::printUPnPState()
{
std::cerr << "upnphandler::printUPnPState() ... locking";
std::cerr << std::endl;
dataMtx.lock(); /* LOCK MUTEX */
std::cerr << "upnphandler::printUPnPState() ... locked";
std::cerr << std::endl;
uPnPConfigData *config = upnpConfig;
if ((upnpState >= RS_UPNP_S_READY) && (config))
{
DisplayInfos(&(config -> urls), &(config->data));
GetConnectionStatus(&(config -> urls), &(config->data));
ListRedirections(&(config -> urls), &(config->data));
}
else
{
std::cerr << "UPNP not Ready" << std::endl;
}
dataMtx.unlock(); /* UNLOCK MUTEX */
return 1;
}
bool upnphandler::updateUPnP()
{
dataMtx.lock(); /* LOCK MUTEX */
uPnPConfigData *config = upnpConfig;
if (!((upnpState >= RS_UPNP_S_READY) && (config)))
{
return false;
}
char eprot1[] = "TCP";
char eprot2[] = "UDP";
/* if we're to unload -> unload */
if ((toStop) && (eport_curr > 0))
{
toStop = false;
char eport1[256];
char eport2[256];
snprintf(eport1, 256, "%d", eport_curr);
snprintf(eport2, 256, "%d", eport_curr + 1);
std::cerr << "Attempting To Remove Redirection: port: " << eport1;
std::cerr << " Prot: " << eprot1;
std::cerr << std::endl;
RemoveRedirect(&(config -> urls), &(config->data),
eport1, eprot1);
std::cerr << "Attempting To Remove Redirection: port: " << eport2;
std::cerr << " Prot: " << eprot2;
std::cerr << std::endl;
RemoveRedirect(&(config -> urls), &(config->data),
eport2, eprot2);
upnpState = RS_UPNP_S_READY;
}
/* if we're to load -> load */
if (toStart)
{
/* select external ports */
eport_curr = eport;
if (!eport_curr)
{
/* use local port if eport is zero */
eport_curr = ntohs(iaddr.sin_port);
std::cerr << "Using LocalPort for extPort!";
std::cerr << std::endl;
}
if (!eport_curr)
{
std::cerr << "Invalid eport ... ";
std::cerr << std::endl;
return false;
}
toStart = false;
/* our port */
char in_addr[256];
char in_port1[256];
char in_port2[256];
char eport1[256];
char eport2[256];
//struct sockaddr_in localAddr = iaddr;
if (iaddr.sin_addr.s_addr != upnp_iaddr.sin_addr.s_addr)
{
std::cerr << "Warning ... Address Mismatch!";
std::cerr << std::endl;
}
upnp_iaddr.sin_port = iaddr.sin_port;
struct sockaddr_in localAddr = upnp_iaddr;
snprintf(in_port1, 256, "%d", ntohs(localAddr.sin_port));
snprintf(in_port2, 256, "%d", ntohs(localAddr.sin_port) + 1);
snprintf(in_addr, 256, "%d.%d.%d.%d",
((localAddr.sin_addr.s_addr >> 0) & 0xff),
((localAddr.sin_addr.s_addr >> 8) & 0xff),
((localAddr.sin_addr.s_addr >> 16) & 0xff),
((localAddr.sin_addr.s_addr >> 24) & 0xff));
snprintf(eport1, 256, "%d", eport_curr);
snprintf(eport2, 256, "%d", eport_curr + 1);
std::cerr << "Attempting Redirection: InAddr: " << in_addr;
std::cerr << " InPort: " << in_port1;
std::cerr << " ePort: " << eport1;
std::cerr << " eProt: " << eprot1;
std::cerr << std::endl;
if (!SetRedirectAndTest(&(config -> urls), &(config->data),
in_addr, in_port1, eport1, eprot1))
{
upnpState = RS_UPNP_S_TCP_FAILED;
}
else if (!SetRedirectAndTest(&(config -> urls), &(config->data),
in_addr, in_port2, eport2, eprot2))
{
upnpState = RS_UPNP_S_UDP_FAILED;
}
else
{
upnpState = RS_UPNP_S_ACTIVE;
}
}
dataMtx.unlock(); /* UNLOCK MUTEX */
return true;
}

View file

@ -0,0 +1,230 @@
#ifndef _RS_UPNP_IFACE_H
#define _RS_UPNP_IFACE_H
#include <string.h>
#include "util/rsthreads.h"
#include <string>
#include <map>
/* platform independent networking... */
#include "pqi/pqinetwork.h"
#include "pqi/pqiaddrstore.h"
class upnpentry
{
public:
std::string name;
std::string id;
struct sockaddr_in addr;
unsigned int flags;
int status;
int lastTs;
};
class upnpforward
{
public:
std::string name;
unsigned int flags;
struct sockaddr_in iaddr;
struct sockaddr_in eaddr;
int status;
int lastTs;
};
#define RS_UPNP_S_UNINITIALISED 0
#define RS_UPNP_S_UNAVAILABLE 1
#define RS_UPNP_S_READY 2
#define RS_UPNP_S_TCP_FAILED 3
#define RS_UPNP_S_UDP_FAILED 4
#define RS_UPNP_S_ACTIVE 5
class uPnPConfigData;
class upnphandler: public RsThread
{
public:
upnphandler()
:toShutdown(false), toEnable(false),
toStart(false), toStop(false),
eport(0), eport_curr(0),
upnpState(RS_UPNP_S_UNINITIALISED),
upnpConfig(NULL)
{
return;
}
~upnphandler()
{
return;
}
/* RsIface */
void enableUPnP(bool active)
{
dataMtx.lock(); /*** LOCK MUTEX ***/
toEnable = active;
dataMtx.unlock(); /*** UNLOCK MUTEX ***/
}
/* RsIface */
void shutdownUPnP()
{
dataMtx.lock(); /*** LOCK MUTEX ***/
toShutdown = true;
dataMtx.unlock(); /*** UNLOCK MUTEX ***/
}
void setupUPnPForwarding()
{
dataMtx.lock(); /*** LOCK MUTEX ***/
toStart = true;
dataMtx.unlock(); /*** UNLOCK MUTEX ***/
}
void shutdownUPnPForwarding()
{
dataMtx.lock(); /*** LOCK MUTEX ***/
toStop = true;
dataMtx.unlock(); /*** UNLOCK MUTEX ***/
}
/* the address that the listening port is on */
void setInternalAddress(struct sockaddr_in iaddr_in)
{
// std::cerr << "UPnPHandler::setInternalAddress() pre Lock!" << std::endl;
dataMtx.lock(); /*** LOCK MUTEX ***/
// std::cerr << "UPnPHandler::setInternalAddress() postLock!" << std::endl;
if ((iaddr.sin_addr.s_addr != iaddr_in.sin_addr.s_addr) ||
(iaddr.sin_port != iaddr_in.sin_port))
{
iaddr = iaddr_in;
if (toEnable)
{
toStop = true;
toStart = true;
}
}
dataMtx.unlock(); /*** UNLOCK MUTEX ***/
}
void setExternalPort(unsigned short eport_in)
{
// std::cerr << "UPnPHandler::getExternalPort() pre Lock!" << std::endl;
dataMtx.lock(); /*** LOCK MUTEX ***/
// std::cerr << "UPnPHandler::getExternalPort() postLock!" << std::endl;
/* flag both shutdown/start -> for restart */
if (eport != eport_in)
{
eport = eport_in;
if (toEnable)
{
toStop = true;
toStart = true;
}
}
dataMtx.unlock(); /*** UNLOCK MUTEX ***/
}
/* as determined by uPnP */
bool getInternalAddress(struct sockaddr_in &addr)
{
// std::cerr << "UPnPHandler::getInternalAddress() pre Lock!" << std::endl;
dataMtx.lock(); /*** LOCK MUTEX ***/
// std::cerr << "UPnPHandler::getInternalAddress() postLock!" << std::endl;
addr = upnp_iaddr;
bool valid = (upnpState >= RS_UPNP_S_READY);
dataMtx.unlock(); /*** UNLOCK MUTEX ***/
return valid;
}
bool getExternalAddress(struct sockaddr_in &addr)
{
// std::cerr << "UPnPHandler::getExternalAddress() pre Lock!" << std::endl;
dataMtx.lock(); /*** LOCK MUTEX ***/
// std::cerr << "UPnPHandler::getExternalAddress() postLock!" << std::endl;
addr = upnp_eaddr;
bool valid = (upnpState >= RS_UPNP_S_READY);
dataMtx.unlock(); /*** UNLOCK MUTEX ***/
return valid;
}
int getUPnPStatus(upnpentry &ent)
{
// std::cerr << "UPnPHandler::getUPnPStatus() pre Lock!" << std::endl;
dataMtx.lock(); /*** LOCK MUTEX ***/
// std::cerr << "UPnPHandler::getUPnPStatus() postLock!" << std::endl;
/* TODO - define data structure first */
int state = upnpState;
dataMtx.unlock(); /*** UNLOCK MUTEX ***/
return state;
}
int init();
int shutdown();
int print();
/* must run thread */
virtual void run();
private:
bool initUPnPState();
void checkUPnPState();
bool printUPnPState();
bool updateUPnP();
/* Mutex for data below */
RsMutex dataMtx;
/* requested from rs */
bool toShutdown; /* if set shuts down the thread. */
bool toEnable; /* overall on/off switch */
bool toStart; /* if set start forwarding */
bool toStop; /* if set stop forwarding */
struct sockaddr_in iaddr;
unsigned short eport; /* config */
unsigned short eport_curr; /* current forwarded */
/* info from upnp */
unsigned int upnpState;
uPnPConfigData *upnpConfig;
struct sockaddr_in upnp_iaddr;
struct sockaddr_in upnp_eaddr;
/* active port forwarding */
std::list<upnpforward> activeForwards;
};
#endif /* _RS_UPNP_IFACE_H */

View file

@ -0,0 +1,110 @@
#include "upnp/upnphandler.h"
int main(int argc, char **argv)
{
int id = argc % 3;
/*********
char *fhash1 = "3509426505463458576487";
char *hash2 = "1549879882341985914515";
char *hash3 = "8743598543269526505434";
int port1 = 8754;
int port2 = 2355;
int port3 = 6621;
**********/
std::cerr << "Starting dhttest Id: " << id << std::endl;
/******************************** WINDOWS/UNIX SPECIFIC PART ******************/
#ifndef WINDOWS_SYS
/********************************** WINDOWS/UNIX SPECIFIC PART ******************/
#else
// Windows Networking Init.
WORD wVerReq = MAKEWORD(2,2);
WSADATA wsaData;
if (0 != WSAStartup(wVerReq, &wsaData))
{
std::cerr << "Failed to Startup Windows Networking";
std::cerr << std::endl;
}
else
{
std::cerr << "Started Windows Networking";
std::cerr << std::endl;
}
#endif
/********************************** WINDOWS/UNIX SPECIFIC PART ******************/
#ifdef PTW32_STATIC_LIB
pthread_win32_process_attach_np();
#endif
upnphandler upnp;
upnp.start();
#ifdef NOTEVER
if (id == 0)
{
dht.setOwnPort(port1);
dht.setOwnHash(hash1);
dht.addFriend(hash2);
dht.addFriend(hash3);
}
else if (id == 1)
{
dht.setOwnPort(port2);
dht.setOwnHash(hash2);
dht.addFriend(hash1);
dht.addFriend(hash3);
}
else
{
dht.setOwnPort(port3);
dht.setOwnHash(hash3);
dht.addFriend(hash1);
dht.addFriend(hash2);
}
#endif /* NOTEVER */
for(int i = 0; 1; i++)
{
/********************************** WINDOWS/UNIX SPECIFIC PART ******************/
#ifndef WINDOWS_SYS
sleep(1);
#else
Sleep(1000);
#endif
/********************************** WINDOWS/UNIX SPECIFIC PART ******************/
if (i % 300 == 10)
{
/* start up a forward */
upnp.setupUPnPForwarding();
}
if (i % 300 == 20)
{
/* shutdown a forward */
upnp.shutdownUPnPForwarding();
}
}
}

View file

@ -0,0 +1,201 @@
#include "upnp/upnputil.h"
/* protofix() checks if protocol is "UDP" or "TCP"
* returns NULL if not */
const char * protofix(const char * proto)
{
static const char proto_tcp[4] = { 'T', 'C', 'P', 0};
static const char proto_udp[4] = { 'U', 'D', 'P', 0};
int i, b;
for(i=0, b=1; i<4; i++)
b = b && ( (proto[i] == proto_tcp[i])
|| (proto[i] == (proto_tcp[i] | 32)) );
if(b)
return proto_tcp;
for(i=0, b=1; i<4; i++)
b = b && ( (proto[i] == proto_udp[i])
|| (proto[i] == (proto_udp[i] | 32)) );
if(b)
return proto_udp;
return 0;
}
void DisplayInfos(struct UPNPUrls * urls,
struct IGDdatas * data)
{
char externalIPAddress[16];
char connectionType[64];
char status[64];
unsigned int uptime;
unsigned int brUp, brDown;
UPNP_GetConnectionTypeInfo(urls->controlURL,
data->servicetype,
connectionType);
if(connectionType[0])
printf("Connection Type : %s\n", connectionType);
else
printf("GetConnectionTypeInfo failed.\n");
UPNP_GetStatusInfo(urls->controlURL, data->servicetype, status, &uptime);
printf("Status : %s, uptime=%u\n", status, uptime);
UPNP_GetLinkLayerMaxBitRates(urls->controlURL_CIF, data->servicetype_CIF,
&brDown, &brUp);
printf("MaxBitRateDown : %u bps MaxBitRateUp %u bps\n", brDown, brUp);
UPNP_GetExternalIPAddress(urls->controlURL,
data->servicetype,
externalIPAddress);
if(externalIPAddress[0])
printf("ExternalIPAddress = %s\n", externalIPAddress);
else
printf("GetExternalIPAddress failed.\n");
}
void GetConnectionStatus(struct UPNPUrls * urls,
struct IGDdatas * data)
{
unsigned int bytessent, bytesreceived, packetsreceived, packetssent;
DisplayInfos(urls, data);
bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->servicetype_CIF);
bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->servicetype_CIF);
packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->servicetype_CIF);
packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->servicetype_CIF);
printf("Bytes: Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived);
printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived);
}
void ListRedirections(struct UPNPUrls * urls,
struct IGDdatas * data)
{
int r;
int i = 0;
char index[6];
char intClient[16];
char intPort[6];
char extPort[6];
char protocol[4];
char desc[80];
char enabled[6];
char rHost[64];
char duration[16];
/*unsigned int num=0;
UPNP_GetPortMappingNumberOfEntries(urls->controlURL, data->servicetype, &num);
printf("PortMappingNumberOfEntries : %u\n", num);*/
do {
snprintf(index, 6, "%d", i);
rHost[0] = '\0'; enabled[0] = '\0';
duration[0] = '\0'; desc[0] = '\0';
extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0';
r = UPNP_GetGenericPortMappingEntry(urls->controlURL, data->servicetype,
index,
extPort, intClient, intPort,
protocol, desc, enabled,
rHost, duration);
if(r==0)
printf("%02d - %s %s->%s:%s\tenabled=%s leaseDuration=%s\n"
" desc='%s' rHost='%s'\n",
i, protocol, extPort, intClient, intPort,
enabled, duration,
desc, rHost);
i++;
} while(r==0);
}
/* Test function
* 1 - get connection type
* 2 - get extenal ip address
* 3 - Add port mapping
* 4 - get this port mapping from the IGD */
bool SetRedirectAndTest(struct UPNPUrls * urls,
struct IGDdatas * data,
const char * iaddr,
const char * iport,
const char * eport,
const char * proto)
{
char externalIPAddress[16];
char intClient[16];
char intPort[6];
int r;
int ok = 1;
if(!iaddr || !iport || !eport || !proto)
{
fprintf(stderr, "Wrong arguments\n");
return 0;
}
proto = protofix(proto);
if(!proto)
{
fprintf(stderr, "invalid protocol\n");
return 0;
}
UPNP_GetExternalIPAddress(urls->controlURL,
data->servicetype,
externalIPAddress);
if(externalIPAddress[0])
printf("ExternalIPAddress = %s\n", externalIPAddress);
else
printf("GetExternalIPAddress failed.\n");
r = UPNP_AddPortMapping(urls->controlURL, data->servicetype,
eport, iport, iaddr, 0, proto);
if(r==0)
{
printf("AddPortMapping(%s, %s, %s) failed\n", eport, iport, iaddr);
ok = 0;
}
UPNP_GetSpecificPortMappingEntry(urls->controlURL,
data->servicetype,
eport, proto,
intClient, intPort);
if(intClient[0])
printf("InternalIP:Port = %s:%s\n", intClient, intPort);
else
{
printf("GetSpecificPortMappingEntry failed.\n");
ok = 0;
}
printf("external %s:%s is redirected to internal %s:%s\n",
externalIPAddress, eport, intClient, intPort);
if (ok)
{
printf("uPnP Forward/Mapping Succeeded\n");
}
else
{
printf("uPnP Forward/Mapping Failed\n");
}
return ok;
}
bool
RemoveRedirect(struct UPNPUrls * urls,
struct IGDdatas * data,
const char * eport,
const char * proto)
{
if(!proto || !eport)
{
fprintf(stderr, "invalid arguments\n");
return 0;
}
proto = protofix(proto);
if(!proto)
{
fprintf(stderr, "protocol invalid\n");
return 0;
}
UPNP_DeletePortMapping(urls->controlURL, data->servicetype, eport, proto);
return 1;
}
/* EOF */

View file

@ -0,0 +1,48 @@
#ifndef MINIUPNP_UTIL_H_
#define MINIUPNP_UTIL_H_
/* $Id: upnpc.c,v 1.50 2007/04/26 19:00:10 nanard Exp $ */
/* Project : miniupnp
* Author : Thomas Bernard
* Copyright (c) 2005 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution.
* */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef WIN32
#include <winsock2.h>
#define snprintf _snprintf
#endif
#include "miniwget.h"
#include "miniupnpc.h"
#include "upnpcommands.h"
/* protofix() checks if protocol is "UDP" or "TCP"
* returns NULL if not */
const char * protofix(const char * proto);
void DisplayInfos(struct UPNPUrls * urls,
struct IGDdatas * data);
void GetConnectionStatus(struct UPNPUrls * urls,
struct IGDdatas * data);
void ListRedirections(struct UPNPUrls * urls,
struct IGDdatas * data);
bool SetRedirectAndTest(struct UPNPUrls * urls,
struct IGDdatas * data,
const char * iaddr,
const char * iport,
const char * eport,
const char * proto);
bool RemoveRedirect(struct UPNPUrls * urls,
struct IGDdatas * data,
const char * eport,
const char * proto);
/* EOF */
#endif