From 9c59becb31e81cda3883aedc15bab50bf1a80ea5 Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 14 Dec 1999 01:07:24 +0000 Subject: [PATCH] Added 3 new classes: WMData, WMHost, WMConnection --- WINGs/ChangeLog | 1 + WINGs/Makefile.am | 6 + WINGs/Makefile.in | 12 +- WINGs/WINGs.h | 5 +- WINGs/WUtil.h | 228 ++++++++++++- WINGs/connection.c | 928 +++++++++++++++++++++++++++++++++++++++++++++++++++++ WINGs/data.c | 322 +++++++++++++++++++ WINGs/host.c | 269 ++++++++++++++++ 8 files changed, 1757 insertions(+), 14 deletions(-) create mode 100644 WINGs/connection.c create mode 100644 WINGs/data.c create mode 100644 WINGs/host.c diff --git a/WINGs/ChangeLog b/WINGs/ChangeLog index 837ed3bf..a5c94c5b 100644 --- a/WINGs/ChangeLog +++ b/WINGs/ChangeLog @@ -36,6 +36,7 @@ changes since wmaker 0.61.1: - added wstrerror(int errnum) to return the string associated with errnum. - new wsyserrorwithcode(int error, const char* fmt, ...), similar to wsyserror(), but printing the message for the specified error code. +- added 3 new classes: WMData, WMHost and WMConnection changes since wmaker 0.61.0: ............................ diff --git a/WINGs/Makefile.am b/WINGs/Makefile.am index 625a82e5..beceb5ca 100644 --- a/WINGs/Makefile.am +++ b/WINGs/Makefile.am @@ -92,7 +92,10 @@ libWINGs_a_SOURCES = \ error.c \ findfile.c \ bag.c \ + connection.c \ + data.c \ hashtable.c \ + host.c \ memory.c \ usleep.c @@ -101,6 +104,9 @@ libWUtil_a_SOURCES = \ WINGs.h \ WINGsP.h \ bag.c \ + connection.c \ + data.c \ + host.c \ international.c \ notification.c \ userdefaults.c \ diff --git a/WINGs/Makefile.in b/WINGs/Makefile.in index 9f1a46ad..7e73d674 100644 --- a/WINGs/Makefile.in +++ b/WINGs/Makefile.in @@ -138,10 +138,10 @@ wmquery_LDADD = libWINGs.a $(LIBLIST) EXTRA_DIST = logo.xpm BUGS # wbutton.c -libWINGs_a_SOURCES = WINGs.h WINGsP.h configuration.c international.c notification.c selection.c userdefaults.c wapplication.c wappresource.c wballoon.c wbrowser.c wbutton.c wcolor.c wcolorpanel.c wcolorwell.c wevent.c wfilepanel.c wframe.c wfont.c wfontpanel.c widgets.c wlabel.c wlist.c wmenuitem.c wmisc.c wpanel.c wpixmap.c wpopupbutton.c wprogressindicator.c wscroller.c wscrollview.c wslider.c wsplitview.c wtabview.c wtextfield.c wwindow.c wview.c error.c findfile.c bag.c hashtable.c memory.c usleep.c +libWINGs_a_SOURCES = WINGs.h WINGsP.h configuration.c international.c notification.c selection.c userdefaults.c wapplication.c wappresource.c wballoon.c wbrowser.c wbutton.c wcolor.c wcolorpanel.c wcolorwell.c wevent.c wfilepanel.c wframe.c wfont.c wfontpanel.c widgets.c wlabel.c wlist.c wmenuitem.c wmisc.c wpanel.c wpixmap.c wpopupbutton.c wprogressindicator.c wscroller.c wscrollview.c wslider.c wsplitview.c wtabview.c wtextfield.c wwindow.c wview.c error.c findfile.c bag.c connection.c data.c hashtable.c host.c memory.c usleep.c -libWUtil_a_SOURCES = WINGs.h WINGsP.h bag.c international.c notification.c userdefaults.c wapplication.c wutil.c error.c findfile.c hashtable.c memory.c usleep.c +libWUtil_a_SOURCES = WINGs.h WINGsP.h bag.c connection.c data.c host.c international.c notification.c userdefaults.c wapplication.c wutil.c error.c findfile.c hashtable.c memory.c usleep.c INCLUDES = -I$(top_srcdir)/wrlib -I$(top_srcdir)/src -DRESOURCE_PATH=\"$(datadir)/WINGs\" @HEADER_SEARCH_PATH@ -DDEBUG @@ -167,11 +167,11 @@ wfilepanel.o wframe.o wfont.o wfontpanel.o widgets.o wlabel.o wlist.o \ wmenuitem.o wmisc.o wpanel.o wpixmap.o wpopupbutton.o \ wprogressindicator.o wscroller.o wscrollview.o wslider.o wsplitview.o \ wtabview.o wtextfield.o wwindow.o wview.o error.o findfile.o bag.o \ -hashtable.o memory.o usleep.o +connection.o data.o hashtable.o host.o memory.o usleep.o libWUtil_a_LIBADD = -libWUtil_a_OBJECTS = bag.o international.o notification.o \ -userdefaults.o wapplication.o wutil.o error.o findfile.o hashtable.o \ -memory.o usleep.o +libWUtil_a_OBJECTS = bag.o connection.o data.o host.o international.o \ +notification.o userdefaults.o wapplication.o wutil.o error.o findfile.o \ +hashtable.o memory.o usleep.o AR = ar PROGRAMS = $(noinst_PROGRAMS) diff --git a/WINGs/WINGs.h b/WINGs/WINGs.h index 567c7f40..e58b0838 100644 --- a/WINGs/WINGs.h +++ b/WINGs/WINGs.h @@ -36,11 +36,8 @@ typedef struct { WMSize size; } WMRect; -typedef struct { - int position; - int count; -} WMRange; +/* WMRange was moved in WUtil.h */ #define ClientMessageMask (1L<<30) diff --git a/WINGs/WUtil.h b/WINGs/WUtil.h index 424c9402..c8a3052e 100644 --- a/WINGs/WUtil.h +++ b/WINGs/WUtil.h @@ -5,7 +5,6 @@ #include - /* SunOS 4.x Blargh.... */ #ifndef NULL #define NULL ((void*)0) @@ -91,12 +90,34 @@ typedef enum { } WMNotificationCoalescing; +/* The possible states for connections */ +typedef enum { + WCNotConnected=0, + WCListening, + WCInProgress, + WCFailed, + WCConnected, + WCDied, + WCClosed +} WMConnectionState; + + typedef struct W_Bag WMBag; /* equivalent to a linked list or array */ +typedef struct W_Data WMData; typedef struct W_HashTable WMHashTable; typedef struct W_UserDefaults WMUserDefaults; typedef struct W_Notification WMNotification; typedef struct W_NotificationQueue WMNotificationQueue; +typedef struct W_Host WMHost; +typedef struct W_Connection WMConnection; + + + +typedef struct { + int position; + int count; +} WMRange; @@ -119,7 +140,7 @@ typedef struct { void (*releaseKey)(const void *); } WMHashTableCallbacks; - + #if 0 typedef struct { @@ -128,7 +149,24 @@ typedef struct { } WMSEscapes; #endif - + +/* The connection callbacks */ +typedef struct ConnectionDelegate { + void *data; + + void (*didCatchException)(struct ConnectionDelegate *self, + WMConnection *cPtr); + + void (*didDie)(struct ConnectionDelegate *self, WMConnection *cPtr); + + void (*didInitialize)(struct ConnectionDelegate *self, WMConnection *cPtr); + + void (*didReceiveInput)(struct ConnectionDelegate *self, WMConnection *cPtr); + + void (*didTimeout)(struct ConnectionDelegate *self, WMConnection *cPtr); + +} ConnectionDelegate; + typedef void WMNotificationObserverAction(void *observerData, WMNotification *notification); @@ -273,7 +311,73 @@ void WMFreeBag(WMBag *bag); WMBag *WMMapBag(WMBag *bag, void* (*function)(void*)); -/*......................................................................*/ +/*-------------------------------------------------------------------------*/ + +/* WMData handling */ + +/* Creating/destroying data */ + +WMData* WMCreateDataWithCapacity(unsigned capacity); + +WMData* WMCreateDataWithLength(unsigned length); + +WMData* WMCreateDataWithBytes(void *bytes, unsigned length); + +WMData* WMCreateDataWithBytesNoCopy(void *bytes, unsigned length); + +WMData* WMCreateDataWithData(WMData *aData); + +WMData* WMRetainData(WMData *aData); + +void WMReleaseData(WMData *aData); + +/* Adjusting capacity */ + +void WMSetDataCapacity(WMData *aData, unsigned capacity); + +void WMSetDataLength(WMData *aData, unsigned length); + +void WMIncreaseDataLengthBy(WMData *aData, unsigned extraLength); + +/* Accessing data */ + +const void* WMDataBytes(WMData *aData); + +void WMGetDataBytes(WMData *aData, void *buffer); + +void WMGetDataBytesWithLength(WMData *aData, void *buffer, unsigned length); + +void WMGetDataBytesWithRange(WMData *aData, void *buffer, WMRange aRange); + +WMData* WMGetSubdataWithRange(WMData *aData, WMRange aRange); + +/* Testing data */ + +Bool WMIsDataEqualToData(WMData *aData, WMData *anotherData); + +unsigned WMGetDataLength(WMData *aData); + +unsigned WMGetDataHash(WMData *aData); + +/* Adding data */ + +void WMAppendDataBytes(WMData *aData, void *bytes, unsigned length); + +void WMAppendData(WMData *aData, WMData *anotherData); + +/* Modifying data */ + +void WMReplaceDataBytesInRange(WMData *aData, WMRange aRange, void *bytes); + +void WMResetDataBytesInRange(WMData *aData, WMRange aRange); + +void WMSetData(WMData *aData, WMData *anotherData); + +/* Storing data */ + + +/*--------------------------------------------------------------------------*/ + WMNotification *WMCreateNotification(char *name, void *object, void *clientData); @@ -361,6 +465,122 @@ proplist_t WMGetUDSearchList(WMUserDefaults *database); void WMSetUDSearchList(WMUserDefaults *database, proplist_t list); +/*-------------------------------------------------------------------------*/ + +/* WMHost: host handling */ + +WMHost* WMGetCurrentHost(); + +WMHost* WMGetHostWithName(char* name); + +WMHost* WMGetHostWithAddress(char* address); + +WMHost* WMRetainHost(WMHost *hPtr); + +void WMReleaseHost(WMHost *hPtr); + +/* + * Host cache management + * If enabled, only one object representing each host will be created, and + * a shared instance will be returned by all methods that return a host. + * Enabled by default. + */ +void WMSetHostCacheEnabled(Bool flag); + +Bool WMIsHostCacheEnabled(); + +void WMFlushHostCache(); + +/* + * Compare hosts: Hosts are equal if they share at least one address + */ +Bool WMIsHostEqualToHost(WMHost* hPtr, WMHost* anotherHost); + +/* + * Host names. + * WMGetHostName() will return first name (official) if a host has several. + * WMGetHostNames() will return a R/O WMBag with all the names of the host. + */ +char* WMGetHostName(WMHost* hPtr); + +/* The returned bag is R/O. Do not modify it, and do not free it! */ +WMBag* WMGetHostNames(WMHost* hPtr); + +/* + * Host addresses. + * Addresses are represented as "Dotted Decimal" strings, e.g. "192.42.172.1" + * WMGetHostAddress() will return an arbitrary address if a host has several. + * WMGetHostAddresses() will return a R/O WMBag with all addresses of the host. + */ +char* WMGetHostAddress(WMHost* hPtr); + +/* The returned bag is R/O. Do not modify it, and do not free it! */ +WMBag* WMGetHostAddresses(WMHost* hPtr); + + +/*-------------------------------------------------------------------------*/ + +/* WMConnection functions */ + +WMConnection* WMCreateConnectionAsServerAtAddress(char *host, char *service, + char *protocol); + +WMConnection* WMCreateConnectionToAddress(char *host, char *service, + char *protocol); + +WMConnection* WMCreateConnectionToAddressAndNotify(char *host, char *service, + char *protocol); + +void WMCloseConnection(WMConnection *cPtr); + +void WMDestroyConnection(WMConnection *cPtr); + +WMConnection* WMAcceptConnection(WMConnection *listener); + +/* Release the returned data! */ +WMData* WMGetConnectionAvailableData(WMConnection *cPtr); + +int WMSendConnectionData(WMConnection *cPtr, WMData *data); + +Bool WMEnqueueConnectionData(WMConnection *cPtr, WMData *data); + +#define WMFlushConnection(cPtr) WMSendConnectionData((cPtr), NULL) + +void WMSetConnectionDelegate(WMConnection *cPtr, ConnectionDelegate *delegate); + +/* Connection info */ + +char* WMGetConnectionAddress(WMConnection *cPtr); + +char* WMGetConnectionService(WMConnection *cPtr); + +char* WMGetConnectionProtocol(WMConnection *cPtr); + +void WMSetConnectionNonBlocking(WMConnection *cPtr, Bool flag); + +void* WMGetConnectionClientData(WMConnection *cPtr); + +void WMSetConnectionClientData(WMConnection *cPtr, void *data); + +unsigned int WMGetConnectionFlags(WMConnection *cPtr); + +void WMSetConnectionFlags(WMConnection *cPtr, unsigned int flags); + +int WMGetConnectionSocket(WMConnection *cPtr); + +WMConnectionState WMGetConnectionState(WMConnection *cPtr); + +void WMSetConnectionSendTimeout(WMConnection *cPtr, unsigned int timeout); + + +/* Global variables */ + +extern int WCErrorCode; + + +/*-------------------------------------------------------------------------*/ + + #ifdef __cplusplus } diff --git a/WINGs/connection.c b/WINGs/connection.c new file mode 100644 index 00000000..1bd76d5d --- /dev/null +++ b/WINGs/connection.c @@ -0,0 +1,928 @@ +/* + * WINGs WMConnection function library + * + * Copyright (c) 1999 Dan Pascu + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +/* + * TODO: + * - decide if we want to support connections with external sockets, else + * clean up the structure of the unneeded members. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __FreeBSD__ +#include +#endif + +#include "WINGs.h" + + +/* Some older systems does not define this (linux libc5, maybe others too) */ +#ifndef SHUT_RDWR +# define SHUT_RDWR 2 +#endif + +/* for SunOS */ +#ifndef SA_RESTART +# define SA_RESTART 0 +#endif + +/* Stuff for setting the sockets into non-blocking mode. */ +#ifdef __POSIX_SOURCE +# define NONBLOCK_OPT O_NONBLOCK +#else +# define NONBLOCK_OPT FNDELAY +#endif + + +#define NETBUF_SIZE 4096 + + +#define DEF_TIMEOUT 600 /* 600 seconds == 10 minutes */ + + +int WCErrorCode = 0; + + + +static Bool SigInitialized = False; + + + +typedef struct TimeoutData { + unsigned timeout; + WMHandlerID *handler; +} TimeoutData; + + + +typedef struct W_Connection { + int sock; /* the socket we speak through */ + + struct { + WMHandlerID *read; /* the input read handler */ + WMHandlerID *write; /* the input write handler */ + WMHandlerID *exception; /* the input exception handler */ + } handler; + + ConnectionDelegate *delegate; /* client delegates */ + void *clientData; /* client data */ + unsigned int uflags; /* flags for the client */ + + WMBag *outputQueue; + unsigned bufPos; + + TimeoutData sendTimeout; + + WMConnectionState state; + + char *address; + char *service; + char *protocol; + + Bool closeOnRelease; + Bool wasNonBlocking; + Bool isNonBlocking; + +} W_Connection; + + + + +static void +clearOutputQueue(WMConnection *cPtr) /*FOLD00*/ +{ + int i; + + cPtr->bufPos = 0; + + for (i=0; ioutputQueue); i++) + WMReleaseData(WMGetFromBag(cPtr->outputQueue, i)); + + WMEmptyBag(cPtr->outputQueue); +} + + +static void +sendTimeout(void *cdata) /*FOLD00*/ +{ + WMConnection *cPtr = (WMConnection*) cdata; + TimeoutData *tPtr = &cPtr->sendTimeout; + + tPtr->handler = NULL; + if (cPtr->handler.write) { + WMDeleteInputHandler(cPtr->handler.write); + cPtr->handler.write = NULL; + } + if (WMGetBagItemCount(cPtr->outputQueue)>0) { + clearOutputQueue(cPtr); + if (cPtr->delegate && cPtr->delegate->didTimeout) + (*cPtr->delegate->didTimeout)(cPtr->delegate, cPtr); + } +} + + +static void +inputHandler(int fd, int mask, void *clientData) /*FOLD00*/ +{ + WMConnection *cPtr = (WMConnection*)clientData; + + if (cPtr->state==WCClosed || cPtr->state==WCDied) + return; + + if ((mask & WIWriteMask)) { + if (cPtr->state == WCInProgress) { + int result; + int len = sizeof(result); + + if (getsockopt(cPtr->sock, SOL_SOCKET, SO_ERROR, + (void*)&result, &len) == 0 && result != 0) { + cPtr->state = WCFailed; + WCErrorCode = result; + } else { + cPtr->state = WCConnected; + } + + if (cPtr->handler.write) { + WMDeleteInputHandler(cPtr->handler.write); + cPtr->handler.write = NULL; + } + + if (cPtr->delegate && cPtr->delegate->didInitialize) + (*cPtr->delegate->didInitialize)(cPtr->delegate, cPtr); + + if (cPtr->state == WCFailed) + return; + } else if (cPtr->state == WCConnected) { + WMFlushConnection(cPtr); + } + } + + if (!cPtr->delegate) + return; + + /* if the connection died, may get destroyed in the delegate, so retain */ + wretain(cPtr); + + if ((mask & WIReadMask) && cPtr->delegate->didReceiveInput) + (*cPtr->delegate->didReceiveInput)(cPtr->delegate, cPtr); + + if ((mask & WIExceptMask) && cPtr->delegate->didCatchException) + (*cPtr->delegate->didCatchException)(cPtr->delegate, cPtr); + + wrelease(cPtr); +} + + +static Bool +setSocketNonBlocking(int sock, Bool flag) /*FOLD00*/ +{ + int state; + Bool isNonBlock; + + state = fcntl(sock, F_GETFL, 0); + + if (state < 0) { + wsyserror("Failed to get socket flags with fcntl."); + return False; + } + + isNonBlock = (state & NONBLOCK_OPT) != 0; + + if (flag) { + if (isNonBlock) + return True; + state |= NONBLOCK_OPT; + } else { + if (!isNonBlock) + return True; + state &= ~NONBLOCK_OPT; + } + + if (fcntl(sock, F_SETFL, state) < 0) { + wsyserror("Failed to set socket flags with fcntl."); + return False; + } + + return True; +} + + +static void +setConnectionAddress(WMConnection *cPtr, struct sockaddr_in *socketaddr) /*FOLD00*/ +{ + wassertr(cPtr->address==NULL); + + cPtr->address = wstrdup(inet_ntoa(socketaddr->sin_addr)); + cPtr->service = wmalloc(16); + sprintf(cPtr->service, "%hu", ntohs(socketaddr->sin_port)); + cPtr->protocol = wstrdup("tcp"); +} + + +static struct sockaddr_in* +getSocketAddress(char* name, char* service, char* protocol) /*FOLD00*/ +{ + static struct sockaddr_in socketaddr; + struct servent *sp; + + if (!protocol || protocol[0]=='\0') + protocol = "tcp"; + + memset(&socketaddr, 0, sizeof(struct sockaddr_in)); + socketaddr.sin_family = AF_INET; + + /* + * If we were given a hostname, we use any address for that host. + * Otherwise we expect the given name to be an address unless it is + * NULL (any address). + */ + if (name && name[0]!='\0') { + WMHost *host = WMGetHostWithName(name); + + if (!host) + return NULL; /* name is not a hostname nor a number and dot adr */ + + name = WMGetHostAddress(host); + if (inet_aton(name, &socketaddr.sin_addr) == 0) { + WMReleaseHost(host); + return NULL; + } + WMReleaseHost(host); + } else { + socketaddr.sin_addr.s_addr = htonl(INADDR_ANY); + } + + if (!service || service[0]=='\0') { + socketaddr.sin_port = 0; + } else if ((sp = getservbyname(service, protocol))==0) { + char *endptr; + unsigned portNumber; + + portNumber = strtoul(service, &endptr, 10); + + if (service[0]!='\0' && *endptr=='\0' && portNumber<65536) { + socketaddr.sin_port = htons(portNumber); + } else { + return NULL; + } + } else { + socketaddr.sin_port = sp->s_port; + } + + return &socketaddr; +} + + +static WMConnection* +createConnectionWithSocket(int sock, Bool closeOnRelease) /*FOLD00*/ +{ + WMConnection *cPtr; + struct sigaction sig_action; + + cPtr = wmalloc(sizeof(WMConnection)); + wretain(cPtr); + memset(cPtr, 0, sizeof(WMConnection)); + + cPtr->sock = sock; + cPtr->sendTimeout.timeout = DEF_TIMEOUT; + cPtr->sendTimeout.handler = NULL; + cPtr->closeOnRelease = closeOnRelease; + cPtr->outputQueue = WMCreateBag(16); + cPtr->state = WCNotConnected; + + /* ignore dead pipe */ + if (!SigInitialized) { + sig_action.sa_handler = SIG_IGN; + sig_action.sa_flags = SA_RESTART; + sigaction(SIGPIPE, &sig_action, NULL); + SigInitialized = True; + } + + return cPtr; +} + + +#if 0 +WMConnection* +WMCreateConnectionWithSocket(int sock, Bool closeOnRelease) /*FOLD00*/ +{ + WMConnection *cPtr; + struct sockaddr_in clientname; + int size, n; + + cPtr = createConnectionWithSocket(sock, closeOnRelease); + cPtr->wasNonBlocking = WMIsConnectionNonBlocking(cPtr); + cPtr->isNonBlocking = cPtr->wasNonBlocking; + + // some way to find out if it is connected, and binded. can't find + // if it listens though!!! + + size = sizeof(clientname); + n = getpeername(sock, (struct sockaddr*) &clientname, &size); + if (n==0) { + /* Since we have a peer, it means we are connected */ + cPtr->state = WCConnected; + } else { + size = sizeof(clientname); + n = getsockname(sock, (struct sockaddr*) &clientname, &size); + if (n==0) { + /* We don't have a peer, but we are binded to an address. + * Assume we are listening on it (we don't know that for sure!) + */ + cPtr->state = WCListening; + } else { + cPtr->state = WCNotConnected; + } + } + + return cPtr; +} +#endif + + +/* + * host is the name on which we want to listen for incoming connections, + * and it must be a name of this host, or NULL if we want to listen + * on any incoming address. + * service is either a service name as present in /etc/services, or the port + * number we want to listen on. If NULL, a random port between + * 1024 and 65535 will be assigned to us. + * protocol is one of "tcp" or "udp". If NULL, "tcp" will be used by default. + * currently only "tcp" is supported. + */ +WMConnection* +WMCreateConnectionAsServerAtAddress(char *host, char *service, char *protocol) /*FOLD00*/ +{ + WMConnection *cPtr; + struct sockaddr_in *socketaddr; + int sock, size, on; + + if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) { + WCErrorCode = 0; + wwarning("Bad address-service-protocol combination"); + return NULL; + } + + /* Create the actual socket */ + sock = socket(PF_INET, SOCK_STREAM, 0); + if (sock<0) { + WCErrorCode = errno; + wsyserror("Unable to create socket"); + return NULL; + } + + /* + * Set socket options. We try to make the port reusable and have it + * close as fast as possible without waiting in unnecessary wait states + * on close. + */ + on = 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); + + if (bind(sock, (struct sockaddr *)socketaddr, sizeof(*socketaddr)) < 0) { + WCErrorCode = errno; + wsyserror("Unable to bind to address '%s:%hu'", + inet_ntoa(socketaddr->sin_addr), + ntohs(socketaddr->sin_port)); + close(sock); + return NULL; + } + + if (listen(sock, 10) < 0) { + WCErrorCode = errno; + wsyserror("Unable to listen on port '%hu'", + ntohs(socketaddr->sin_port)); + close(sock); + return NULL; + } + + /* Find out what is the address/service/protocol we get */ + /* In case some of address/service/protocol were NULL */ + size = sizeof(*socketaddr); + if (getsockname(sock, (struct sockaddr*)socketaddr, &size) < 0) { + WCErrorCode = errno; + wsyserror("Unable to get socket address"); + close(sock); + return NULL; + } + + cPtr = createConnectionWithSocket(sock, True); + cPtr->state = WCListening; + WMSetConnectionNonBlocking(cPtr, True); + + setConnectionAddress(cPtr, socketaddr); + + return cPtr; +} + + +WMConnection* +WMCreateConnectionToAddress(char *host, char *service, char *protocol) /*FOLD00*/ +{ + WMConnection *cPtr; + struct sockaddr_in *socketaddr; + int sock; + + if (service==NULL || service[0]=='\0') { + WCErrorCode = 0; + wwarning("Bad argument - service is not specified"); + return NULL; + } + + if (host==NULL || host[0]=='\0') + host = "localhost"; + + if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) { + WCErrorCode = 0; + wwarning("Bad address-service-protocol combination"); + return NULL; + } + + /* Create the actual socket */ + sock = socket(PF_INET, SOCK_STREAM, 0); + if (sock<0) { + WCErrorCode = errno; + wsyserror("Unable to create socket"); + return NULL; + } + /* make socket blocking while we connect. */ + setSocketNonBlocking(sock, False); + if (connect(sock, (struct sockaddr*)socketaddr, sizeof(*socketaddr)) < 0) { + WCErrorCode = errno; + wsyserror("Unable to make connection to address '%s:%hu'", + inet_ntoa(socketaddr->sin_addr), + ntohs(socketaddr->sin_port)); + close(sock); + return NULL; + } + + cPtr = createConnectionWithSocket(sock, True); + cPtr->state = WCConnected; + WMSetConnectionNonBlocking(cPtr, True); + setConnectionAddress(cPtr, socketaddr); + + return cPtr; +} + + +WMConnection* +WMCreateConnectionToAddressAndNotify(char *host, char *service, char *protocol) /*FOLD00*/ +{ + WMConnection *cPtr; + /*TimeoutData *tPtr;*/ + struct sockaddr_in *socketaddr; + int sock; + Bool isNonBlocking; + + if (service==NULL || service[0]=='\0') { + WCErrorCode = 0; + wwarning("Bad argument - service is not specified"); + return NULL; + } + + if (host==NULL || host[0]=='\0') + host = "localhost"; + + if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) { + WCErrorCode = 0; + wwarning("Bad address-service-protocol combination"); + return NULL; + } + + /* Create the actual socket */ + sock = socket(PF_INET, SOCK_STREAM, 0); + if (sock<0) { + WCErrorCode = errno; + wsyserror("Unable to create socket"); + return NULL; + } + isNonBlocking = setSocketNonBlocking(sock, True); + if (connect(sock, (struct sockaddr*)socketaddr, sizeof(*socketaddr)) < 0) { + if (errno!=EINPROGRESS) { + WCErrorCode = errno; + wsyserror("Unable to make connection to address '%s:%hu'", + inet_ntoa(socketaddr->sin_addr), + ntohs(socketaddr->sin_port)); + close(sock); + return NULL; + } + } + + cPtr = createConnectionWithSocket(sock, True); + cPtr->state = WCInProgress; + cPtr->isNonBlocking = isNonBlocking; + + /*tPtr = &cPtr->sendTimeout; + tPtr->handler = WMAddTimerHandler(tPtr->timeout*1000, connectTimeout, cPtr); + */ + cPtr->handler.write = WMAddInputHandler(cPtr->sock, WIWriteMask, + inputHandler, cPtr); + + setConnectionAddress(cPtr, socketaddr); + + return cPtr; +} + + +static void +removeAllHandlers(WMConnection *cPtr) /*FOLD00*/ +{ + if (cPtr->handler.read) + WMDeleteInputHandler(cPtr->handler.read); + if (cPtr->handler.write) + WMDeleteInputHandler(cPtr->handler.write); + if (cPtr->handler.exception) + WMDeleteInputHandler(cPtr->handler.exception); + if (cPtr->sendTimeout.handler) + WMDeleteTimerHandler(cPtr->sendTimeout.handler); + + cPtr->handler.read = NULL; + cPtr->handler.write = NULL; + cPtr->handler.exception = NULL; + cPtr->sendTimeout.handler = NULL; +} + + +void +WMDestroyConnection(WMConnection *cPtr) /*FOLD00*/ +{ + if (cPtr->closeOnRelease && cPtr->sock>=0) { + shutdown(cPtr->sock, SHUT_RDWR); + close(cPtr->sock); + } + + removeAllHandlers(cPtr); + clearOutputQueue(cPtr); + WMFreeBag(cPtr->outputQueue); + + if (cPtr->address) { + wfree(cPtr->address); + wfree(cPtr->service); + wfree(cPtr->protocol); + } + + wrelease(cPtr); +} + + +void +WMCloseConnection(WMConnection *cPtr) /*FOLD00*/ +{ + if (cPtr->sock>=0) { + shutdown(cPtr->sock, SHUT_RDWR); + close(cPtr->sock); + cPtr->sock = -1; + } + + removeAllHandlers(cPtr); + clearOutputQueue(cPtr); + + cPtr->state = WCClosed; +} + + +WMConnection* +WMAcceptConnection(WMConnection *listener) /*FOLD00*/ +{ + struct sockaddr_in clientname; + int size; + int newSock; + WMConnection *newConnection; + + if (listener->state!=WCListening) { + wwarning("Called 'WMAcceptConnection()' on a non-listening connection"); + WCErrorCode = 0; + return NULL; + } + + size = sizeof(clientname); + newSock = accept(listener->sock, (struct sockaddr*) &clientname, &size); + if (newSock<0) { + if (errno!=EAGAIN && errno!=EWOULDBLOCK) { + WCErrorCode = errno; + wsyserror("Could not accept connection"); + } else { + WCErrorCode = 0; + } + return NULL; + } + + newConnection = createConnectionWithSocket(newSock, True); + WMSetConnectionNonBlocking(newConnection, True); + newConnection->state = WCConnected; + setConnectionAddress(newConnection, &clientname); + + return newConnection; +} + + +char* +WMGetConnectionAddress(WMConnection *cPtr) /*FOLD00*/ +{ + return cPtr->address; +} + + +char* +WMGetConnectionService(WMConnection *cPtr) /*FOLD00*/ +{ + return cPtr->service; +} + + +char* +WMGetConnectionProtocol(WMConnection *cPtr) +{ + return cPtr->protocol; +} + + +int +WMGetConnectionSocket(WMConnection *cPtr) /*FOLD00*/ +{ + return cPtr->sock; +} + + +WMConnectionState +WMGetConnectionState(WMConnection *cPtr) /*FOLD00*/ +{ + return cPtr->state; +} + + +Bool +WMEnqueueConnectionData(WMConnection *cPtr, WMData *data) /*FOLD00*/ +{ + wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, False); + wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, False); + + if (cPtr->state!=WCConnected) + return False; + + WMPutInBag(cPtr->outputQueue, WMRetainData(data)); + return True; +} + + +int +WMSendConnectionData(WMConnection *cPtr, WMData *data) /*FOLD00*/ +{ + int bytes, pos, len, totalTransfer; + TimeoutData *tPtr = &cPtr->sendTimeout; + const void *dataBytes; + + wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, -1); + wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, -1); + + if (cPtr->state!=WCConnected) + return -1; + + /* If we have no data just flush the queue, else try to send data */ + if (data && WMGetDataLength(data)>0) { + WMPutInBag(cPtr->outputQueue, WMRetainData(data)); + /* If there already was something in queue, and also a write input + * handler is established, it means we were unable to send, so + * return and let the write handler notify us when we can send. + */ + if (WMGetBagItemCount(cPtr->outputQueue)>1 && cPtr->handler.write) + return 0; + } + + totalTransfer = 0; + + while (WMGetBagItemCount(cPtr->outputQueue) > 0) { + data = WMGetFromBag(cPtr->outputQueue, 0); + dataBytes = WMDataBytes(data); + len = WMGetDataLength(data); + pos = cPtr->bufPos; /* where we're left last time */ + while(pos < len) { + again: + bytes = write(cPtr->sock, dataBytes+pos, len - pos); + if(bytes<0) { + switch (errno) { + case EINTR: + goto again; + case EWOULDBLOCK: + /* save the position where we're left and add a timeout */ + cPtr->bufPos = pos; + if (!tPtr->handler) { + tPtr->handler = WMAddTimerHandler(tPtr->timeout*1000, + sendTimeout, cPtr); + } + if (!cPtr->handler.write) { + cPtr->handler.write = + WMAddInputHandler(cPtr->sock, WIWriteMask, + inputHandler, cPtr); + } + return totalTransfer; + default: + WCErrorCode = errno; + cPtr->state = WCDied; + /*clearOutputQueue(cPtr);*/ + removeAllHandlers(cPtr); + if (cPtr->delegate && cPtr->delegate->didDie) + (*cPtr->delegate->didDie)(cPtr->delegate, cPtr); + return -1; + } + } + pos += bytes; + totalTransfer += bytes; + } + WMReleaseData(data); + WMDeleteFromBag(cPtr->outputQueue, 0); + cPtr->bufPos = 0; + if (tPtr->handler) { + WMDeleteTimerHandler(tPtr->handler); + tPtr->handler = NULL; + } + if (cPtr->handler.write) { + WMDeleteInputHandler(cPtr->handler.write); + cPtr->handler.write = NULL; + } + } + + return totalTransfer; +} + + +/* + * WMGetConnectionAvailableData(connection): + * + * will return a WMData structure containing the available data on the + * specified connection. If connection is non-blocking (default) and no data + * is available when this function is called, an empty WMData is returned. + * + * If an error occurs while reading or the other side closed connection, + * it will return NULL. + * Also trying to read from an already died or closed connection is + * considered to be an error condition, and will return NULL. + */ +WMData* +WMGetConnectionAvailableData(WMConnection *cPtr) /*FOLD00*/ +{ + char buffer[NETBUF_SIZE]; + int nbytes; + WMData *aData; + + wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, NULL); + wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, NULL); + + if (cPtr->state!=WCConnected) + return NULL; + + aData = NULL; + +again: + nbytes = read(cPtr->sock, buffer, NETBUF_SIZE); + if (nbytes<0) { + switch (errno) { + case EINTR: + goto again; + case EWOULDBLOCK: + aData = WMCreateDataWithCapacity(0); + break; + default: + WCErrorCode = errno; + cPtr->state = WCDied; + removeAllHandlers(cPtr); + if (cPtr->delegate && cPtr->delegate->didDie) + (*cPtr->delegate->didDie)(cPtr->delegate, cPtr); + break; + } + } else if (nbytes==0) { /* the other side has closed connection */ + cPtr->state = WCClosed; + removeAllHandlers(cPtr); + if (cPtr->delegate && cPtr->delegate->didDie) + (*cPtr->delegate->didDie)(cPtr->delegate, cPtr); + } else { + aData = WMCreateDataWithBytes(buffer, nbytes); + } + + return aData; +} + + +void +WMSetConnectionDelegate(WMConnection *cPtr, ConnectionDelegate *delegate) /*FOLD00*/ +{ + wassertr(cPtr->sock >= 0); + /* Don't try to set the delegate multiple times */ + wassertr(cPtr->delegate == NULL); + + cPtr->delegate = delegate; + if (delegate && delegate->didReceiveInput && !cPtr->handler.read) + cPtr->handler.read = WMAddInputHandler(cPtr->sock, WIReadMask, + inputHandler, cPtr); + if (delegate && delegate->didCatchException && !cPtr->handler.exception) + cPtr->handler.exception = WMAddInputHandler(cPtr->sock, WIExceptMask, + inputHandler, cPtr); +} + + +#if 0 +Bool +WMIsConnectionNonBlocking(WMConnection *cPtr) /*FOLD00*/ +{ +#if 1 + int state; + + state = fcntl(cPtr->sock, F_GETFL, 0); + + if (state < 0) { + wsyserror("Failed to get socket flags with fcntl."); + /* If we can't use fcntl on socket, this probably also means we could + * not use fcntl to set non-blocking mode, and since a socket defaults + * to blocking when created, return False as the best assumption */ + return False; + } + + return ((state & NONBLOCK_OPT)!=0); +#else + return cPtr->isNonBlocking; +#endif +} +#endif + + +void +WMSetConnectionNonBlocking(WMConnection *cPtr, Bool flag) /*FOLD00*/ +{ + if (cPtr->sock < 0) + return; + + if (cPtr->isNonBlocking == flag) + return; + + if (setSocketNonBlocking(cPtr->sock, flag)==True) + cPtr->isNonBlocking = flag; +} + + +void* +WMGetConnectionClientData(WMConnection *cPtr) /*FOLD00*/ +{ + return cPtr->clientData; +} + + +void +WMSetConnectionClientData(WMConnection *cPtr, void *data) /*FOLD00*/ +{ + cPtr->clientData = data; +} + + +unsigned int +WMGetConnectionFlags(WMConnection *cPtr) /*FOLD00*/ +{ + return cPtr->uflags; +} + + +void +WMSetConnectionFlags(WMConnection *cPtr, unsigned int flags) /*FOLD00*/ +{ + cPtr->uflags = flags; +} + + +void +WMSetConnectionSendTimeout(WMConnection *cPtr, unsigned int timeout) /*FOLD00*/ +{ + if (timeout == 0) + timeout = DEF_TIMEOUT; + + cPtr->sendTimeout.timeout = timeout; +} + + diff --git a/WINGs/data.c b/WINGs/data.c new file mode 100644 index 00000000..db505ca8 --- /dev/null +++ b/WINGs/data.c @@ -0,0 +1,322 @@ +/* + * WINGs WMData function library + * + * Copyright (c) 1999 Dan Pascu + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + + +#include +#include "WUtil.h" + + +typedef struct W_Data { + unsigned length; /* How many bytes we have */ + unsigned capacity; /* How many bytes it can hold */ + unsigned growth; /* How much to grow */ + void *bytes; /* Actual data */ + unsigned retainCount; +} W_Data; + + + + +/* Creating and destroying data objects */ + +WMData* +WMCreateDataWithCapacity(unsigned capacity) /*FOLD00*/ +{ + WMData *aData; + + aData = (WMData*)wmalloc(sizeof(WMData)); + + if (capacity>0) + aData->bytes = wmalloc(capacity); + else + aData->bytes = NULL; + aData->capacity = capacity; + aData->growth = capacity/2 > 0 ? capacity/2 : 1; + aData->length = 0; + aData->retainCount = 1; + + return aData; +} + + +WMData* +WMCreateDataWithLength(unsigned length) /*FOLD00*/ +{ + WMData *aData; + + aData = WMCreateDataWithCapacity(length); + if (length>0) { + memset(aData->bytes, 0, length); + aData->length = length; + } + + return aData; +} + + +WMData* +WMCreateDataWithBytes(void *bytes, unsigned length) /*FOLD00*/ +{ + WMData *aData; + + aData = WMCreateDataWithCapacity(length); + aData->length = length; + memcpy(aData->bytes, bytes, length); + + return aData; +} + + +WMData* +WMCreateDataWithBytesNoCopy(void *bytes, unsigned length) /*FOLD00*/ +{ + WMData *aData; + + aData = (WMData*)wmalloc(sizeof(WMData)); + aData->length = length; + aData->capacity = length; + aData->growth = length/2 > 0 ? length/2 : 1; + aData->bytes = bytes; + aData->retainCount = 1; + + return aData; +} + + +WMData* +WMCreateDataWithData(WMData *aData) /*FOLD00*/ +{ + if (aData->length > 0) + return WMCreateDataWithBytes(aData->bytes, aData->length); + else + return WMCreateDataWithCapacity(0); +} + + +WMData* +WMRetainData(WMData *aData) /*FOLD00*/ +{ + aData->retainCount++; + return aData; +} + + +void +WMReleaseData(WMData *aData) /*FOLD00*/ +{ + aData->retainCount--; + if (aData->retainCount > 0) + return; + if (aData->bytes) + wfree(aData->bytes); + wfree(aData); +} + + + +/* Adjusting capacity */ + +void +WMSetDataCapacity(WMData *aData, unsigned capacity) /*FOLD00*/ +{ + if (aData->capacity != capacity) { + aData->bytes = wrealloc(aData->bytes, capacity); + aData->capacity = capacity; + aData->growth = capacity/2 > 0 ? capacity/2 : 1; + } + if (aData->length > capacity) { + aData->length = capacity; + } +} + + +void +WMSetDataLength(WMData *aData, unsigned length) /*FOLD00*/ +{ + if (length > aData->capacity) { + WMSetDataCapacity(aData, length); + } + if (length > aData->length) { + memset(aData->bytes + aData->length, 0, length - aData->length); + } + aData->length = length; +} + + +void +WMIncreaseDataLengthBy(WMData *aData, unsigned extraLength) /*FOLD00*/ +{ + WMSetDataLength(aData, aData->length + extraLength); +} + + +/* Accessing data */ + +const void* +WMDataBytes(WMData *aData) /*FOLD00*/ +{ + return aData->bytes; +} + + +void +WMGetDataBytes(WMData *aData, void *buffer) /*FOLD00*/ +{ + wassertr(aData->length > 0); + + memcpy(buffer, aData->bytes, aData->length); +} + + +void +WMGetDataBytesWithLength(WMData *aData, void *buffer, unsigned length) /*FOLD00*/ +{ + wassertr(aData->length > 0); + wassertr(length <= aData->length); + + memcpy(buffer, aData->bytes, length); +} + + +void +WMGetDataBytesWithRange(WMData *aData, void *buffer, WMRange aRange) /*FOLD00*/ +{ + wassertr(aRange.position < aData->length); + wassertr(aRange.count <= aData->length-aRange.position); + + memcpy(buffer, aData->bytes + aRange.position, aRange.count); +} + + +WMData* +WMGetSubdataWithRange(WMData *aData, WMRange aRange) /*FOLD00*/ +{ + void *buffer; + + /* return an empty subdata instead if aRange.count is 0 ? */ + wassertrv(aRange.count > 0, NULL); + + buffer = wmalloc(aRange.count); + WMGetDataBytesWithRange(aData, buffer, aRange); + return WMCreateDataWithBytesNoCopy(buffer, aRange.count); +} + + +/* Testing data */ + +Bool +WMIsDataEqualToData(WMData *aData, WMData *anotherData) /*FOLD00*/ +{ + if (aData->length != anotherData->length) + return False; + else if (!aData->bytes && !anotherData->bytes) /* both are empty */ + return True; + else if (!aData->bytes || !anotherData->bytes) /* one of them is empty */ + return False; + return (memcmp(aData->bytes, anotherData->bytes, aData->length)==0); +} + + +unsigned +WMGetDataLength(WMData *aData) /*FOLD00*/ +{ + return aData->length; +} + + +unsigned +WMGetDataHash(WMData *aData) /*FOLD00*/ +{ + return aData->length; +} + + +/* Adding data */ +void +WMAppendDataBytes(WMData *aData, void *bytes, unsigned length) /*FOLD00*/ +{ + unsigned oldLength = aData->length; + unsigned newLength = oldLength + length; + + if (newLength > aData->capacity) { + unsigned nextCapacity = aData->capacity + aData->growth; + unsigned nextGrowth = aData->capacity ? aData->capacity : 1; + + while (nextCapacity < newLength) { + unsigned tmp = nextCapacity + nextGrowth; + + nextGrowth = nextCapacity; + nextCapacity = tmp; + } + WMSetDataCapacity(aData, nextCapacity); + aData->growth = nextGrowth; + } + memcpy(aData->bytes + oldLength, bytes, length); + aData->length = newLength; +} + + +void +WMAppendData(WMData *aData, WMData *anotherData) /*FOLD00*/ +{ + if (anotherData->length > 0) + WMAppendDataBytes(aData, anotherData->bytes, anotherData->length); +} + + + +/* Modifying data */ + +void +WMReplaceDataBytesInRange(WMData *aData, WMRange aRange, void *bytes) /*FOLD00*/ +{ + wassertr(aRange.position < aData->length); + wassertr(aRange.count <= aData->length-aRange.position); + + memcpy(aData->bytes + aRange.position, bytes, aRange.count); +} + + +void +WMResetDataBytesInRange(WMData *aData, WMRange aRange) /*FOLD00*/ +{ + wassertr(aRange.position < aData->length); + wassertr(aRange.count <= aData->length-aRange.position); + + memset(aData->bytes + aRange.position, 0, aRange.count); +} + + +void +WMSetData(WMData *aData, WMData *anotherData) /*FOLD00*/ +{ + unsigned length = anotherData->length; + + WMSetDataCapacity(aData, length); + if (length > 0) + memcpy(aData->bytes, anotherData->bytes, length); + aData->length = length; +} + + +/* Storing data */ + + diff --git a/WINGs/host.c b/WINGs/host.c new file mode 100644 index 00000000..a7d09645 --- /dev/null +++ b/WINGs/host.c @@ -0,0 +1,269 @@ +/* + * WINGs WMHost function library + * + * Copyright (c) 1999 Dan Pascu + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + + +#include +#include +#include +#include +#include +#include + +#include "WUtil.h" + + +typedef struct W_Host { + char *name; + + WMBag *names; + WMBag *addresses; + int nameCount; + int addressCount; + + int refCount; +} W_Host; + + +static WMHashTable *hostCache = NULL; +static Bool hostCacheEnabled = True; + + +/* Max hostname length (RFC 1123) */ +#define W_MAXHOSTNAMELEN 255 + +WMHost* +WMGetCurrentHost() +{ + char name[W_MAXHOSTNAMELEN+1]; + + if (gethostname(name, W_MAXHOSTNAMELEN) < 0) { + wsyserror("Cannot get current host name"); + return NULL; + } + + name[W_MAXHOSTNAMELEN] = '\0'; + + return WMGetHostWithName(name); +} + + +WMHost* +WMGetHostWithName(char* name) +{ + struct hostent *host; + struct in_addr in; + WMHost *hPtr; + int i; + + if (name == NULL) { + wwarning("NULL host name in 'WMGetHostWithName()'"); + return NULL; + } + + if (!hostCache) + hostCache = WMCreateHashTable(WMStringPointerHashCallbacks); + + hPtr = WMHashGet(hostCache, name); + if (hPtr) { + WMRetainHost(hPtr); + return hPtr; + } + + host = gethostbyname(name); + if (host == NULL) { + wwarning("Invalid host name/address '%s'", name); + return NULL; + } + + hPtr = (WMHost*)wmalloc(sizeof(WMHost)); + memset(hPtr, 0, sizeof(WMHost)); + + hPtr->names = WMCreateBag(1); + hPtr->addresses = WMCreateBag(1); + + WMPutInBag(hPtr->names, wstrdup(host->h_name)); + + for (i=0; host->h_aliases[i]!=NULL; i++) { + WMPutInBag(hPtr->names, wstrdup(host->h_aliases[i])); + } + + hPtr->nameCount = WMGetBagItemCount(hPtr->names); + + for (i=0; host->h_addr_list[i]!=NULL; i++) { + memcpy((void*)&in.s_addr, (const void*)host->h_addr_list[i], + host->h_length); + WMPutInBag(hPtr->addresses, wstrdup(inet_ntoa(in))); + } + + hPtr->addressCount = WMGetBagItemCount(hPtr->addresses); + + hPtr->refCount = 1; + + if (hostCacheEnabled) { + hPtr->name = wstrdup(name); + wassertr(WMHashInsert(hostCache, hPtr->name, hPtr)==NULL); + hPtr->refCount++; + } + + return hPtr; +} + + +WMHost* +WMGetHostWithAddress(char* address) +{ + if (address == NULL) { + wwarning("NULL address in 'WMGetHostWithAddress()'"); + return NULL; + } + + return WMGetHostWithName(address); +#if 0 + hostaddr.s_addr = inet_addr((char*)[address cString]); + if (hostaddr.s_addr == -1) { + return NULL; + } + + h = gethostbyaddr((char*)&hostaddr, sizeof(hostaddr), AF_INET); +#endif +} + + +WMHost* +WMRetainHost(WMHost *hPtr) +{ + hPtr->refCount++; + return hPtr; +} + + +void +WMReleaseHost(WMHost *hPtr) +{ + int i; + + hPtr->refCount--; + + if (hPtr->refCount > 0) + return; + + for (i=0; inames); i++) + wfree(WMGetFromBag(hPtr->names, i)); + for (i=0; iaddresses); i++) + wfree(WMGetFromBag(hPtr->addresses, i)); + + WMFreeBag(hPtr->names); + WMFreeBag(hPtr->addresses); + + if (hPtr->name) { + WMHashRemove(hostCache, hPtr->name); + wfree(hPtr->name); + } + + wfree(hPtr); +} + + +void +WMSetHostCacheEnabled(Bool flag) +{ + hostCacheEnabled = flag; +} + + +Bool +WMIsHostCacheEnabled() +{ + return hostCacheEnabled; +} + + +void +WMFlushHostCache() +{ + if (hostCache && WMCountHashTable(hostCache)>0) { + WMBag *hostBag = WMCreateBag(WMCountHashTable(hostCache)); + WMHashEnumerator enumer = WMEnumerateHashTable(hostCache); + WMHost *hPtr; + int i; + + while ((hPtr = WMNextHashEnumeratorItem(&enumer))) { + /* we can't release the host here, because we can't change the + * hash while using the enumerator functions. */ + WMPutInBag(hostBag, hPtr); + } + for (i=0; iaddressCount; i++) { + if (WMGetFirstInBag(hPtr->addresses, WMGetFromBag(aPtr->addresses, i))) + return True; + } + + return False; +} + + +char* +WMGetHostName(WMHost *hPtr) +{ + return WMGetFromBag(hPtr->names, 0); +} + + +WMBag* +WMGetHostNames(WMHost *hPtr) +{ + return hPtr->names; +} + + +char* +WMGetHostAddress(WMHost *hPtr) +{ + return (hPtr->addressCount > 0 ? WMGetFromBag(hPtr->addresses, 0) : NULL); +} + + +WMBag* +WMGetHostAddresses(WMHost *hPtr) +{ + return hPtr->addresses; +} + + + + -- 2.11.4.GIT