|
/***************************************************************************
|
|
$RCSfile$
|
|
-------------------
|
|
cvs : $Id$
|
|
begin : Tue Oct 02 2002
|
|
copyright : (C) 2002 by Martin Preuss
|
|
email : martin@libchipcard.de
|
|
|
|
***************************************************************************
|
|
* *
|
|
* 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 *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#include "inetaddr_p.h"
|
|
#include <gwenhywfar/misc.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <netdb.h>
|
|
#include <string.h>
|
|
#include <sys/un.h>
|
|
#include <arpa/inet.h>
|
|
|
|
#include "gwenhywfar/debug.h"
|
|
|
|
/* #define MEMTRACE */
|
|
|
|
/* needed for Solaris */
|
|
#ifndef SUN_LEN
|
|
# define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
|
|
+ strlen ((ptr)->sun_path))
|
|
#endif
|
|
|
|
|
|
#ifdef MEMTRACE
|
|
static int GWEN_INETADDR__Counter=0;
|
|
#endif
|
|
|
|
|
|
uint32_t GWEN_InetAddr_GetCapabilities(void)
|
|
{
|
|
return
|
|
GWEN_INETADDR_CAPS_AF_TCP |
|
|
GWEN_INETADDR_CAPS_AF_UNIX;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_InetAddr_ModuleInit(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_InetAddr_ModuleFini(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
GWEN_INETADDRESS *GWEN_InetAddr_new(GWEN_AddressFamily af)
|
|
{
|
|
GWEN_INETADDRESS *ia;
|
|
|
|
GWEN_NEW_OBJECT(GWEN_INETADDRESS, ia);
|
|
|
|
ia->af=af;
|
|
switch (ia->af) {
|
|
case GWEN_AddressFamilyIP: {
|
|
struct sockaddr_in *aptr;
|
|
|
|
ia->address=(struct sockaddr *)malloc(sizeof(struct sockaddr_in));
|
|
assert(ia->address);
|
|
aptr=(struct sockaddr_in *)(ia->address);
|
|
ia->size=sizeof(struct sockaddr_in);
|
|
memset(ia->address, 0, ia->size);
|
|
#ifdef PF_INET
|
|
aptr->sin_family=PF_INET;
|
|
#else
|
|
aptr->sin_family=AF_INET;
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
case GWEN_AddressFamilyUnix: {
|
|
struct sockaddr_un *aptr;
|
|
|
|
ia->address=(struct sockaddr *)malloc(sizeof(struct sockaddr_un));
|
|
assert(ia->address);
|
|
aptr=(struct sockaddr_un *)(ia->address);
|
|
#if defined(PF_UNIX)
|
|
aptr->sun_family=PF_UNIX;
|
|
#elif defined (AF_UNIX)
|
|
aptr->sun_family=AF_UNIX;
|
|
#else
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "No unix domain sockets available for this system");
|
|
GWEN_InetAddr_free(ia);
|
|
return 0;
|
|
#endif
|
|
aptr->sun_path[0]=0;
|
|
ia->size=sizeof(struct sockaddr_un);
|
|
memset(ia->address, 0, ia->size);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
DBG_INFO(GWEN_LOGDOMAIN, "Unknown address family (%d)", af);
|
|
assert(0);
|
|
} /* switch */
|
|
#ifdef MEMTRACE
|
|
GWEN_INETADDR__Counter++;
|
|
DBG_INFO(GWEN_LOGDOMAIN, "InetAddr created, now %d", GWEN_INETADDR__Counter);
|
|
#endif
|
|
return ia;
|
|
}
|
|
|
|
|
|
|
|
GWEN_INETADDRESS *GWEN_InetAddr_dup(const GWEN_INETADDRESS *oa)
|
|
{
|
|
GWEN_INETADDRESS *ia;
|
|
|
|
GWEN_NEW_OBJECT(GWEN_INETADDRESS, ia);
|
|
ia->af=oa->af;
|
|
ia->size=oa->size;
|
|
//ia->address=(struct sockaddr *)malloc(sizeof(struct sockaddr));
|
|
if (oa->size) {
|
|
ia->address=(struct sockaddr *)malloc(oa->size);
|
|
assert(ia->address);
|
|
memmove(ia->address, oa->address, oa->size);
|
|
}
|
|
return ia;
|
|
}
|
|
|
|
|
|
|
|
void GWEN_InetAddr_free(GWEN_INETADDRESS *ia)
|
|
{
|
|
if (ia) {
|
|
#ifdef MEMTRACE
|
|
GWEN_INETADDR__Counter--;
|
|
DBG_INFO(GWEN_LOGDOMAIN, "Free InetAddr, makes %d", GWEN_INETADDR__Counter);
|
|
#endif
|
|
free(ia->address);
|
|
GWEN_FREE_OBJECT(ia);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int GWEN_InetAddr_SetAddress(GWEN_INETADDRESS *ia,
|
|
const char *addr)
|
|
{
|
|
assert(ia);
|
|
|
|
switch (ia->af) {
|
|
case GWEN_AddressFamilyIP: {
|
|
struct sockaddr_in *aptr;
|
|
|
|
aptr=(struct sockaddr_in *)(ia->address);
|
|
/* reset */
|
|
#ifdef PF_INET
|
|
aptr->sin_family=PF_INET;
|
|
#elif defined (AF_INET)
|
|
aptr->sun_family=AF_INET;
|
|
#else
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "No TCP sockets available for this system");
|
|
return GWEN_ERROR_BAD_ADDRESS_FAMILY;
|
|
#endif
|
|
aptr->sin_addr.s_addr=0;
|
|
|
|
if (addr) {
|
|
/* ok, address to be set */
|
|
if (!inet_aton(addr, &aptr->sin_addr))
|
|
/* bad address, so maybe it rather is a name */
|
|
return GWEN_ERROR_BAD_ADDRESS;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case GWEN_AddressFamilyUnix: {
|
|
struct sockaddr_un *aptr;
|
|
|
|
aptr=(struct sockaddr_un *)(ia->address);
|
|
#ifdef PF_UNIX
|
|
aptr->sun_family=PF_UNIX;
|
|
#elif defined (AF_UNIX)
|
|
aptr->sun_family=AF_UNIX;
|
|
#else
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "No unix domain sockets available for this system");
|
|
return GWEN_ERROR_BAD_ADDRESS_FAMILY;
|
|
#endif
|
|
memset(aptr->sun_path, 0, sizeof(aptr->sun_path));
|
|
if (addr) {
|
|
/* ok, address to be set */
|
|
if ((strlen(addr)+1)>sizeof(aptr->sun_path)) {
|
|
/* bad address */
|
|
DBG_INFO(GWEN_LOGDOMAIN, "Path too long (%d>%d)",
|
|
(int)(strlen(addr)+1), (int)(sizeof(aptr->sun_path)));
|
|
return GWEN_ERROR_BAD_ADDRESS;
|
|
}
|
|
strcpy(aptr->sun_path, addr);
|
|
ia->size=SUN_LEN(aptr);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
return GWEN_ERROR_BAD_ADDRESS_FAMILY;
|
|
} /* switch */
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/* internal function */
|
|
int GWEN_InetAddr_TranslateHError(int herr)
|
|
{
|
|
int rv;
|
|
|
|
switch (herr) {
|
|
case HOST_NOT_FOUND:
|
|
rv=GWEN_ERROR_HOST_NOT_FOUND;
|
|
break;
|
|
#ifdef NO_ADDRESS
|
|
case NO_ADDRESS:
|
|
rv=GWEN_ERROR_NO_ADDRESS;
|
|
break;
|
|
#endif
|
|
case NO_RECOVERY:
|
|
rv=GWEN_ERROR_NO_RECOVERY;
|
|
break;
|
|
case TRY_AGAIN:
|
|
rv=GWEN_ERROR_TRY_AGAIN;
|
|
break;
|
|
default:
|
|
rv=GWEN_ERROR_UNKNOWN_DNS_ERROR;
|
|
break;
|
|
} /* switch */
|
|
return rv;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_InetAddr_SetName(GWEN_INETADDRESS *ia, const char *name)
|
|
{
|
|
struct hostent *he;
|
|
|
|
assert(ia);
|
|
|
|
switch (ia->af) {
|
|
case GWEN_AddressFamilyIP: {
|
|
struct sockaddr_in *aptr;
|
|
|
|
aptr=(struct sockaddr_in *)(ia->address);
|
|
/* try to resolve name */
|
|
he=gethostbyname(name);
|
|
if (!he)
|
|
return GWEN_InetAddr_TranslateHError(h_errno);
|
|
/* name resolved, store address */
|
|
memcpy(&(aptr->sin_addr),
|
|
he->h_addr_list[0],
|
|
sizeof(struct in_addr));
|
|
break;
|
|
}
|
|
|
|
case GWEN_AddressFamilyUnix: {
|
|
struct sockaddr_un *aptr;
|
|
|
|
aptr=(struct sockaddr_un *)(ia->address);
|
|
#ifdef PF_UNIX
|
|
aptr->sun_family=PF_UNIX;
|
|
#elif defined (AF_UNIX)
|
|
aptr->sun_family=AF_UNIX;
|
|
#else
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "No unix domain sockets available for this system");
|
|
return GWEN_ERROR_BAD_ADDRESS_FAMILY;
|
|
#endif
|
|
aptr->sun_path[0]=0;
|
|
|
|
if (name) {
|
|
/* ok, address to be set */
|
|
if ((strlen(name)+1)>sizeof(aptr->sun_path)) {
|
|
/* bad address */
|
|
DBG_INFO(GWEN_LOGDOMAIN, "Path too long (%d>%d)",
|
|
(int)(strlen(name)+1), (int)(sizeof(aptr->sun_path)));
|
|
return GWEN_ERROR_BAD_ADDRESS;
|
|
}
|
|
strcpy(aptr->sun_path, name);
|
|
ia->size=SUN_LEN(aptr);
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
return GWEN_INETADDR_ERROR_BAD_ADDRESS_FAMILY;
|
|
} /* switch */
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_InetAddr_GetAddress(const GWEN_INETADDRESS *ia,
|
|
char *buffer, unsigned int bsize)
|
|
{
|
|
const char *s;
|
|
|
|
assert(ia);
|
|
assert(buffer);
|
|
|
|
switch (ia->af) {
|
|
case GWEN_AddressFamilyIP: {
|
|
struct sockaddr_in *aptr;
|
|
|
|
aptr=(struct sockaddr_in *)(ia->address);
|
|
s=inet_ntoa(aptr->sin_addr);
|
|
assert(s);
|
|
if (strlen(s)+1>bsize)
|
|
return GWEN_ERROR_BUFFER_OVERFLOW;
|
|
strcpy(buffer, s);
|
|
break;
|
|
}
|
|
|
|
case GWEN_AddressFamilyUnix: {
|
|
struct sockaddr_un *aptr;
|
|
int i;
|
|
|
|
aptr=(struct sockaddr_un *)(ia->address);
|
|
s=aptr->sun_path;
|
|
i=ia->size;
|
|
i-=sizeof(aptr->sun_family);
|
|
if (i+1>(int)bsize)
|
|
return GWEN_ERROR_BUFFER_OVERFLOW;
|
|
memmove(buffer, s, i);
|
|
buffer[i]=0;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
return GWEN_ERROR_BAD_ADDRESS_FAMILY;
|
|
} /* switch */
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_InetAddr_GetName(const GWEN_INETADDRESS *ia,
|
|
char *buffer, unsigned int bsize)
|
|
{
|
|
struct hostent *he;
|
|
struct in_addr lia;
|
|
|
|
assert(ia);
|
|
assert(buffer);
|
|
|
|
switch (ia->af) {
|
|
case GWEN_AddressFamilyIP: {
|
|
struct sockaddr_in *aptr;
|
|
|
|
aptr=(struct sockaddr_in *)(ia->address);
|
|
/* resolve name from address */
|
|
lia=aptr->sin_addr;
|
|
#ifdef PF_INET
|
|
he=gethostbyaddr((char *)&lia, sizeof(lia), PF_INET);
|
|
#else
|
|
he=gethostbyaddr((char *)&lia, sizeof(lia), AF_INET);
|
|
#endif
|
|
if (!he)
|
|
return GWEN_InetAddr_TranslateHError(h_errno);
|
|
|
|
/* copy name into given buffer */
|
|
assert(he->h_name);
|
|
if (strlen(he->h_name)+1>bsize)
|
|
return GWEN_ERROR_BUFFER_OVERFLOW;
|
|
/* copy the name into the buffer */
|
|
strcpy(buffer, he->h_name);
|
|
break;
|
|
}
|
|
|
|
case GWEN_AddressFamilyUnix: {
|
|
struct sockaddr_un *aptr;
|
|
|
|
aptr=(struct sockaddr_un *)(ia->address);
|
|
/* simply copy path */
|
|
if (strlen(aptr->sun_path)+1>bsize)
|
|
return GWEN_ERROR_BUFFER_OVERFLOW;
|
|
strcpy(buffer, aptr->sun_path);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
return GWEN_INETADDR_ERROR_BAD_ADDRESS_FAMILY;
|
|
|
|
} /* switch */
|
|
|
|
/* finished */
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_InetAddr_GetPort(const GWEN_INETADDRESS *ia)
|
|
{
|
|
int i;
|
|
|
|
assert(ia);
|
|
|
|
switch (ia->af) {
|
|
case GWEN_AddressFamilyIP: {
|
|
struct sockaddr_in *aptr;
|
|
|
|
aptr=(struct sockaddr_in *)(ia->address);
|
|
i=ntohs(aptr->sin_port);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
DBG_INFO(GWEN_LOGDOMAIN, "not an IP address");
|
|
i=0;
|
|
} /* switch */
|
|
|
|
return i;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_InetAddr_SetPort(GWEN_INETADDRESS *ia, int port)
|
|
{
|
|
assert(ia);
|
|
|
|
switch (ia->af) {
|
|
case GWEN_AddressFamilyIP: {
|
|
struct sockaddr_in *aptr;
|
|
|
|
aptr=(struct sockaddr_in *)(ia->address);
|
|
aptr->sin_port=htons(port);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
return GWEN_ERROR_BAD_ADDRESS_FAMILY;
|
|
} /* switch */
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|