mirror of
https://github.com/gryf/wmaker.git
synced 2025-12-19 12:28:22 +01:00
Added 3 new classes: WMData, WMHost, WMConnection
This commit is contained in:
@@ -36,6 +36,7 @@ changes since wmaker 0.61.1:
|
|||||||
- added wstrerror(int errnum) to return the string associated with errnum.
|
- added wstrerror(int errnum) to return the string associated with errnum.
|
||||||
- new wsyserrorwithcode(int error, const char* fmt, ...), similar to
|
- new wsyserrorwithcode(int error, const char* fmt, ...), similar to
|
||||||
wsyserror(), but printing the message for the specified error code.
|
wsyserror(), but printing the message for the specified error code.
|
||||||
|
- added 3 new classes: WMData, WMHost and WMConnection
|
||||||
|
|
||||||
changes since wmaker 0.61.0:
|
changes since wmaker 0.61.0:
|
||||||
............................
|
............................
|
||||||
|
|||||||
@@ -92,7 +92,10 @@ libWINGs_a_SOURCES = \
|
|||||||
error.c \
|
error.c \
|
||||||
findfile.c \
|
findfile.c \
|
||||||
bag.c \
|
bag.c \
|
||||||
|
connection.c \
|
||||||
|
data.c \
|
||||||
hashtable.c \
|
hashtable.c \
|
||||||
|
host.c \
|
||||||
memory.c \
|
memory.c \
|
||||||
usleep.c
|
usleep.c
|
||||||
|
|
||||||
@@ -101,6 +104,9 @@ libWUtil_a_SOURCES = \
|
|||||||
WINGs.h \
|
WINGs.h \
|
||||||
WINGsP.h \
|
WINGsP.h \
|
||||||
bag.c \
|
bag.c \
|
||||||
|
connection.c \
|
||||||
|
data.c \
|
||||||
|
host.c \
|
||||||
international.c \
|
international.c \
|
||||||
notification.c \
|
notification.c \
|
||||||
userdefaults.c \
|
userdefaults.c \
|
||||||
|
|||||||
@@ -138,10 +138,10 @@ wmquery_LDADD = libWINGs.a $(LIBLIST)
|
|||||||
EXTRA_DIST = logo.xpm BUGS
|
EXTRA_DIST = logo.xpm BUGS
|
||||||
|
|
||||||
# wbutton.c
|
# 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
|
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 \
|
wmenuitem.o wmisc.o wpanel.o wpixmap.o wpopupbutton.o \
|
||||||
wprogressindicator.o wscroller.o wscrollview.o wslider.o wsplitview.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 \
|
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_LIBADD =
|
||||||
libWUtil_a_OBJECTS = bag.o international.o notification.o \
|
libWUtil_a_OBJECTS = bag.o connection.o data.o host.o international.o \
|
||||||
userdefaults.o wapplication.o wutil.o error.o findfile.o hashtable.o \
|
notification.o userdefaults.o wapplication.o wutil.o error.o findfile.o \
|
||||||
memory.o usleep.o
|
hashtable.o memory.o usleep.o
|
||||||
AR = ar
|
AR = ar
|
||||||
PROGRAMS = $(noinst_PROGRAMS)
|
PROGRAMS = $(noinst_PROGRAMS)
|
||||||
|
|
||||||
|
|||||||
@@ -36,11 +36,8 @@ typedef struct {
|
|||||||
WMSize size;
|
WMSize size;
|
||||||
} WMRect;
|
} WMRect;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int position;
|
|
||||||
int count;
|
|
||||||
} WMRange;
|
|
||||||
|
|
||||||
|
/* WMRange was moved in WUtil.h */
|
||||||
|
|
||||||
#define ClientMessageMask (1L<<30)
|
#define ClientMessageMask (1L<<30)
|
||||||
|
|
||||||
|
|||||||
228
WINGs/WUtil.h
228
WINGs/WUtil.h
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
|
||||||
/* SunOS 4.x Blargh.... */
|
/* SunOS 4.x Blargh.... */
|
||||||
#ifndef NULL
|
#ifndef NULL
|
||||||
#define NULL ((void*)0)
|
#define NULL ((void*)0)
|
||||||
@@ -91,12 +90,34 @@ typedef enum {
|
|||||||
} WMNotificationCoalescing;
|
} 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_Bag WMBag; /* equivalent to a linked list or array */
|
||||||
|
typedef struct W_Data WMData;
|
||||||
typedef struct W_HashTable WMHashTable;
|
typedef struct W_HashTable WMHashTable;
|
||||||
typedef struct W_UserDefaults WMUserDefaults;
|
typedef struct W_UserDefaults WMUserDefaults;
|
||||||
typedef struct W_Notification WMNotification;
|
typedef struct W_Notification WMNotification;
|
||||||
typedef struct W_NotificationQueue WMNotificationQueue;
|
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 *);
|
void (*releaseKey)(const void *);
|
||||||
} WMHashTableCallbacks;
|
} WMHashTableCallbacks;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -128,7 +149,24 @@ typedef struct {
|
|||||||
} WMSEscapes;
|
} WMSEscapes;
|
||||||
#endif
|
#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,
|
typedef void WMNotificationObserverAction(void *observerData,
|
||||||
WMNotification *notification);
|
WMNotification *notification);
|
||||||
@@ -273,7 +311,73 @@ void WMFreeBag(WMBag *bag);
|
|||||||
|
|
||||||
WMBag *WMMapBag(WMBag *bag, void* (*function)(void*));
|
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);
|
WMNotification *WMCreateNotification(char *name, void *object, void *clientData);
|
||||||
|
|
||||||
@@ -361,6 +465,122 @@ proplist_t WMGetUDSearchList(WMUserDefaults *database);
|
|||||||
void WMSetUDSearchList(WMUserDefaults *database, proplist_t list);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
928
WINGs/connection.c
Normal file
928
WINGs/connection.c
Normal 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
322
WINGs/data.c
Normal 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
269
WINGs/host.c
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user