// Copyright (c) 2003 David Muse
// See the COPYING file for more information
#include <rudiments/serviceentry.h>
#include <rudiments/charstring.h>
#include <rudiments/rawbuffer.h>
#include <rudiments/error.h>
// for servent, functions
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#define MAXBUFFER (32*1024)
#ifdef RUDIMENTS_NAMESPACE
namespace rudiments {
#endif
class serviceentryprivate {
friend class serviceentry;
private:
servent *_se;
#if defined(RUDIMENTS_HAVE_GETSERVBYNAME_R) || \
defined(RUDIMENTS_HAVE_GETSERVBYPORT_R)
servent _sebuffer;
char *_buffer;
#endif
};
// LAME: not in the class
#if (!defined(RUDIMENTS_HAVE_GETSERVBYNAME_R) || \
!defined(RUDIMENTS_HAVE_GETSERVBYPORT_R))
static mutex *_semutex;
#endif
serviceentry::serviceentry() {
pvt=new serviceentryprivate;
pvt->_se=NULL;
#if defined(RUDIMENTS_HAVE_GETSERVBYNAME_R) && \
defined(RUDIMENTS_HAVE_GETSERVBYPORT_R)
rawbuffer::zero(&pvt->_sebuffer,sizeof(pvt->_sebuffer));
pvt->_buffer=NULL;
#endif
}
serviceentry::serviceentry(const serviceentry &s) {
pvt=new serviceentryprivate;
initialize(s.getName(),s.getProtocol());
}
serviceentry &serviceentry::operator=(const serviceentry &s) {
if (this!=&s) {
initialize(s.getName(),s.getProtocol());
}
return *this;
}
serviceentry::~serviceentry() {
#if defined(RUDIMENTS_HAVE_GETSERVBYNAME_R) && \
defined(RUDIMENTS_HAVE_GETSERVBYPORT_R)
delete[] pvt->_buffer;
#endif
delete pvt;
}
const char *serviceentry::getName() const {
return pvt->_se->s_name;
}
int serviceentry::getPort() const {
return ntohs(pvt->_se->s_port);
}
const char *serviceentry::getProtocol() const {
return pvt->_se->s_proto;
}
const char * const *serviceentry::getAliasList() const {
return pvt->_se->s_aliases;
}
bool serviceentry::needsMutex() {
#if !defined(RUDIMENTS_HAVE_GETSERVBYNAME_R) || \
!defined(RUDIMENTS_HAVE_GETSERVBYPORT_R)
return true;
#else
return false;
#endif
}
void serviceentry::setMutex(mutex *mtx) {
#if !defined(RUDIMENTS_HAVE_GETSERVBYNAME_R) || \
!defined(RUDIMENTS_HAVE_GETSERVBYPORT_R)
_semutex=mtx;
#endif
}
bool serviceentry::initialize(const char *servicename, const char *protocol) {
return initialize(servicename,0,protocol);
}
bool serviceentry::initialize(int port, const char *protocol) {
return initialize(NULL,port,protocol);
}
bool serviceentry::initialize(const char *servicename, int port,
const char *protocol) {
#if defined(RUDIMENTS_HAVE_GETSERVBYNAME_R) && \
defined(RUDIMENTS_HAVE_GETSERVBYPORT_R)
if (pvt->_se) {
pvt->_se=NULL;
delete[] pvt->_buffer;
pvt->_buffer=NULL;
}
// getservbyname_r is goofy.
// It will retrieve an arbitrarily large amount of data, but
// requires that you pass it a pre-allocated buffer. If the
// buffer is too small, it returns an ENOMEM and you have to
// just make the buffer bigger and try again.
for (int size=1024; size<MAXBUFFER; size=size+1024) {
pvt->_buffer=new char[size];
#if defined(RUDIMENTS_HAVE_GETSERVBYNAME_R_6) && \
defined(RUDIMENTS_HAVE_GETSERVBYPORT_R_6)
if (!((servicename)
?(getservbyname_r(servicename,protocol,
&pvt->_sebuffer,
pvt->_buffer,size,
&pvt->_se))
:(getservbyport_r(htons(port),protocol,
&pvt->_sebuffer,
pvt->_buffer,size,
&pvt->_se)))) {
return (pvt->_se!=NULL);
}
#elif defined(RUDIMENTS_HAVE_GETSERVBYNAME_R_5) && \
defined(RUDIMENTS_HAVE_GETSERVBYPORT_R_5)
if ((servicename)
?(pvt->_se=getservbyname_r(servicename,protocol,
&pvt->_sebuffer,
pvt->_buffer,size))
:(pvt->_se=getservbyport_r(htons(port),protocol,
&pvt->_sebuffer,
pvt->_buffer,size))) {
return true;
}
#endif
delete[] pvt->_buffer;
pvt->_buffer=NULL;
pvt->_se=NULL;
if (error::getErrorNumber()!=ENOMEM) {
return false;
}
}
return false;
#else
pvt->_se=NULL;
return (!(_semutex && !_semutex->lock()) &&
((pvt->_se=((servicename)
?getservbyname(servicename,protocol)
:getservbyport(htons(port),protocol)))!=NULL) &&
!(_semutex && !_semutex->unlock()));
#endif
}
bool serviceentry::getAliasList(const char *servicename,
const char *protocol,
char ***aliaslist) {
serviceentry se;
if (se.initialize(servicename,protocol)) {
int counter;
for (counter=0; se.getAliasList()[counter]; counter++);
char **alias=new char *[counter+1];
alias[counter]=NULL;
for (int i=0; i<counter; i++) {
alias[i]=charstring::duplicate(se.getAliasList()[i]);
}
*aliaslist=alias;
return true;
}
return false;
}
bool serviceentry::getPort(const char *servicename, const char *protocol,
int *port) {
serviceentry se;
if (se.initialize(servicename,protocol)) {
*port=se.getPort();
return true;
}
return false;
}
bool serviceentry::getName(int port, const char *protocol, char **name) {
serviceentry se;
if (se.initialize(port,protocol)) {
*name=charstring::duplicate(se.getName());
return true;
}
return false;
}
bool serviceentry::getAliasList(int port, const char *protocol,
char ***aliaslist) {
serviceentry se;
if (se.initialize(port,protocol)) {
int counter;
for (counter=0; se.getAliasList()[counter]; counter++);
char **alias=new char *[counter+1];
alias[counter]=NULL;
for (int i=0; i<counter; i++) {
alias[i]=charstring::duplicate(se.getAliasList()[i]);
}
*aliaslist=alias;
return true;
}
return false;
}
void serviceentry::print() const {
if (!pvt->_se) {
return;
}
printf("Name: %s\n",getName());
printf("Port: %d\n",getPort());
printf("Protocol: %s\n",getProtocol());
printf("Alias list:\n");
for (int i=0; getAliasList()[i]; i++) {
printf(" %s\n",getAliasList()[i]);
}
}
#ifdef RUDIMENTS_NAMESPACE
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1