1
0
mirror of https://github.com/gryf/wmaker.git synced 2025-12-19 20:38:08 +01:00

Added 3 new classes: WMData, WMHost, WMConnection

This commit is contained in:
dan
1999-12-14 01:07:24 +00:00
parent d39bb888a0
commit 9c59becb31
8 changed files with 1757 additions and 14 deletions

View File

@@ -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:
............................

View File

@@ -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 \

View File

@@ -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)

View File

@@ -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)

View File

@@ -5,7 +5,6 @@
#include <sys/types.h>
/* 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;
@@ -129,6 +150,23 @@ typedef struct {
#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
}

928
WINGs/connection.c Normal file
View File

@@ -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 <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <signal.h>
#ifdef __FreeBSD__
#include <sys/signal.h>
#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; i<WMGetBagItemCount(cPtr->outputQueue); 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;
}

322
WINGs/data.c Normal file
View File

@@ -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 <string.h>
#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 */

269
WINGs/host.c Normal file
View File

@@ -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 <unistd.h>
#include <string.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#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; i<WMGetBagItemCount(hPtr->names); i++)
wfree(WMGetFromBag(hPtr->names, i));
for (i=0; i<WMGetBagItemCount(hPtr->addresses); 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; i<WMGetBagItemCount(hostBag); i++)
WMReleaseHost(WMGetFromBag(hostBag, i));
WMFreeBag(hostBag);
WMResetHashTable(hostCache);
}
}
Bool
WMIsHostEqualToHost(WMHost* hPtr, WMHost* aPtr)
{
int i;
wassertrv(hPtr!=NULL && aPtr!=NULL, False);
if (hPtr == aPtr)
return True;
for (i=0; i<aPtr->addressCount; 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;
}