mirror of
https://github.com/gryf/wmaker.git
synced 2025-12-28 09:22:27 +01:00
Remove network support from WINGs
- nobody used it Amend network stuff removal still more wings network removals [crmafra: squashed together three patches]
This commit is contained in:
committed by
Carlos R. Mafra
parent
55959b4f7e
commit
1f2b9999b9
@@ -1,51 +0,0 @@
|
|||||||
Methods of handling WMConnectionDidDieNotification notification events
|
|
||||||
(same for WMConnectionDidTimeoutNotification)
|
|
||||||
----------------------------------------------------------------------
|
|
||||||
|
|
||||||
Once your program got this notification (you need to install an observer for
|
|
||||||
it), there are some ways to handle it:
|
|
||||||
|
|
||||||
1. Make your observer enqueue a new notification in the ASAP queue, and the
|
|
||||||
observer for this new notification (it can be the same function if you
|
|
||||||
arrange to distinguish between the two cases), should remove the connection.
|
|
||||||
You can also close the connection before enqueuing the new notification to
|
|
||||||
the ASAP queue, but is not strictly necessarily, since it will be closed
|
|
||||||
when the observer for the new enqueued notification will be called and you
|
|
||||||
will call the close/remove function there. This is just to make sure your
|
|
||||||
connection will be silent, and won't generate new events until you reach
|
|
||||||
that point.
|
|
||||||
This is by far the best method, since it will assure you that if you
|
|
||||||
enqueue more than one notification to remove the same connection, they will
|
|
||||||
be coalesced, and called only once.
|
|
||||||
|
|
||||||
2. In your observer, put the died/closed connection in an array or bag, and
|
|
||||||
destroy all the connections present in the array/bag, in your main loop,
|
|
||||||
after you call the WHandleEvents()/WMHandleEvent(). Also closing the
|
|
||||||
connection can be done before putting the connection in the array/bag, but
|
|
||||||
is optional as noted above. In this case you need to make sure you don't
|
|
||||||
put in the array/bag the same connection more than once, in case the
|
|
||||||
DieNotification is sent more that once to you. This is automagically solved
|
|
||||||
by method 1.
|
|
||||||
|
|
||||||
3. In case it's your only connection, and you plan to exit if it was closed or
|
|
||||||
died, then you can safely close/remove it, and exit. As long as you no
|
|
||||||
longer access it, there is no problem.
|
|
||||||
|
|
||||||
4. Make you observer remove the connection. Then make sure that after that
|
|
||||||
point your code no longer tries to access that connection (this usually
|
|
||||||
means until your code gets back to the main loop). This is almost always
|
|
||||||
very hard to achive and subject to hidden errors. I do not recommend this
|
|
||||||
way of handling the died notification. It is ugly and very complicated to
|
|
||||||
handle if the program is in a very deeply nested function when it finds out
|
|
||||||
that the connection died. If you use it and get plenty of SIGSEGVs then you
|
|
||||||
know why. This method was not presented here to be used, but to show what
|
|
||||||
should be avoided in dealing with the died notification, in case someone
|
|
||||||
gets the idea to try it this way.
|
|
||||||
|
|
||||||
|
|
||||||
Note: read/write operations means to use our read/write functions (like
|
|
||||||
WMGetMessage()/WMSendMessage()), not the C library ones read()/write().
|
|
||||||
Note2: removing a connection is done by WMDestroyConnection(), while
|
|
||||||
WMCloseConnection() only closes the socket, and removed any pending
|
|
||||||
queues and timers on the connection.
|
|
||||||
|
|
||||||
@@ -18,13 +18,11 @@ puzzle_DEPENDENCIES = $(top_builddir)/WINGs/libWINGs.la
|
|||||||
|
|
||||||
connect_DEPENDENCIES = $(top_builddir)/WINGs/libWUtil.la
|
connect_DEPENDENCIES = $(top_builddir)/WINGs/libWUtil.la
|
||||||
|
|
||||||
connect_LDADD = $(top_builddir)/WINGs/libWUtil.la @LIBRARY_SEARCH_PATH@ \
|
connect_LDADD = $(top_builddir)/WINGs/libWUtil.la @LIBRARY_SEARCH_PATH@ @INTLIBS@
|
||||||
@NETLIBS@ @INTLIBS@
|
|
||||||
|
|
||||||
server_DEPENDENCIES = $(top_builddir)/WINGs/libWUtil.la
|
server_DEPENDENCIES = $(top_builddir)/WINGs/libWUtil.la
|
||||||
|
|
||||||
server_LDADD = $(top_builddir)/WINGs/libWUtil.la @LIBRARY_SEARCH_PATH@ \
|
server_LDADD = $(top_builddir)/WINGs/libWUtil.la @LIBRARY_SEARCH_PATH@ @INTLIBS@
|
||||||
@NETLIBS@ @INTLIBS@
|
|
||||||
|
|
||||||
|
|
||||||
INCLUDES = -I$(top_srcdir)/WINGs -I$(top_srcdir)/wrlib -I$(top_srcdir)/src \
|
INCLUDES = -I$(top_srcdir)/WINGs -I$(top_srcdir)/wrlib -I$(top_srcdir)/src \
|
||||||
|
|||||||
@@ -1,172 +0,0 @@
|
|||||||
/*
|
|
||||||
* WINGs connect.c: example how to create a network client using WMConnection
|
|
||||||
*
|
|
||||||
* Copyright (c) 1999-2003 Dan Pascu
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <WINGs/WINGs.h>
|
|
||||||
|
|
||||||
static int initialized = 0;
|
|
||||||
|
|
||||||
static void didReceiveInput(ConnectionDelegate * self, WMConnection * cPtr);
|
|
||||||
|
|
||||||
static void connectionDidDie(ConnectionDelegate * self, WMConnection * cPtr);
|
|
||||||
|
|
||||||
static void didInitialize(ConnectionDelegate * self, WMConnection * cPtr);
|
|
||||||
|
|
||||||
static ConnectionDelegate socketDelegate = {
|
|
||||||
NULL, /* data */
|
|
||||||
NULL, /* canResumeSending */
|
|
||||||
NULL, /* didCatchException */
|
|
||||||
connectionDidDie, /* didDie */
|
|
||||||
didInitialize, /* didInitialize */
|
|
||||||
didReceiveInput, /* didReceiveInput */
|
|
||||||
NULL /* didTimeout */
|
|
||||||
};
|
|
||||||
|
|
||||||
void wAbort(Bool foo)
|
|
||||||
{
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *getMessage(WMConnection * cPtr)
|
|
||||||
{
|
|
||||||
char *buffer;
|
|
||||||
WMData *aData;
|
|
||||||
int length;
|
|
||||||
|
|
||||||
aData = WMGetConnectionAvailableData(cPtr);
|
|
||||||
if (!aData)
|
|
||||||
return NULL;
|
|
||||||
if ((length = WMGetDataLength(aData)) == 0) {
|
|
||||||
WMReleaseData(aData);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer = (char *)wmalloc(length + 1);
|
|
||||||
WMGetDataBytes(aData, buffer);
|
|
||||||
buffer[length] = '\0';
|
|
||||||
WMReleaseData(aData);
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void inputHandler(int fd, int mask, void *clientData)
|
|
||||||
{
|
|
||||||
WMConnection *cPtr = (WMConnection *) clientData;
|
|
||||||
WMData *aData;
|
|
||||||
char buf[4096];
|
|
||||||
int n;
|
|
||||||
|
|
||||||
if (!initialized)
|
|
||||||
return;
|
|
||||||
|
|
||||||
n = read(fd, buf, 4096);
|
|
||||||
if (n > 0) {
|
|
||||||
aData = WMCreateDataWithBytes(buf, n);
|
|
||||||
WMSendConnectionData(cPtr, aData);
|
|
||||||
WMReleaseData(aData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void didReceiveInput(ConnectionDelegate * self, WMConnection * cPtr)
|
|
||||||
{
|
|
||||||
char *buffer;
|
|
||||||
|
|
||||||
buffer = getMessage(cPtr);
|
|
||||||
if (!buffer) {
|
|
||||||
fprintf(stderr, "Connection closed by peer.\n");
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("%s", buffer);
|
|
||||||
|
|
||||||
wfree(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void connectionDidDie(ConnectionDelegate * self, WMConnection * cPtr)
|
|
||||||
{
|
|
||||||
WMCloseConnection(cPtr);
|
|
||||||
|
|
||||||
fprintf(stderr, "Connection closed by peer.\n");
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void didInitialize(ConnectionDelegate * self, WMConnection * cPtr)
|
|
||||||
{
|
|
||||||
int state = WMGetConnectionState(cPtr);
|
|
||||||
WMHost *host;
|
|
||||||
|
|
||||||
if (state == WCConnected) {
|
|
||||||
host = WMGetHostWithAddress(WMGetConnectionAddress(cPtr));
|
|
||||||
fprintf(stderr, "connected to '%s:%s'\n",
|
|
||||||
host ? WMGetHostName(host) : WMGetConnectionAddress(cPtr), WMGetConnectionService(cPtr));
|
|
||||||
initialized = 1;
|
|
||||||
if (host)
|
|
||||||
WMReleaseHost(host);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
wsyserrorwithcode(WCErrorCode, "Unable to connect");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
char *ProgName, *host, *port;
|
|
||||||
int i;
|
|
||||||
WMConnection *sPtr;
|
|
||||||
|
|
||||||
wsetabort(wAbort);
|
|
||||||
|
|
||||||
WMInitializeApplication("connect", &argc, argv);
|
|
||||||
|
|
||||||
ProgName = strrchr(argv[0], '/');
|
|
||||||
if (!ProgName)
|
|
||||||
ProgName = argv[0];
|
|
||||||
else
|
|
||||||
ProgName++;
|
|
||||||
|
|
||||||
host = NULL;
|
|
||||||
port = "34567";
|
|
||||||
|
|
||||||
if (argc > 1) {
|
|
||||||
for (i = 1; i < argc; i++) {
|
|
||||||
if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) {
|
|
||||||
printf("usage: %s [host [port]]\n\n", ProgName);
|
|
||||||
exit(0);
|
|
||||||
} else {
|
|
||||||
if (!host)
|
|
||||||
host = argv[i];
|
|
||||||
else
|
|
||||||
port = argv[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Trying to make connection to '%s:%s'\n", host ? host : "localhost", port);
|
|
||||||
|
|
||||||
sPtr = WMCreateConnectionToAddressAndNotify(host, port, NULL);
|
|
||||||
if (!sPtr) {
|
|
||||||
wfatal("could not create connection. exiting");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
WMSetConnectionDelegate(sPtr, &socketDelegate);
|
|
||||||
|
|
||||||
/* watch what user types and send it over the connection */
|
|
||||||
WMAddInputHandler(0, WIReadMask, inputHandler, sPtr);
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
WHandleEvents();
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,661 +0,0 @@
|
|||||||
/*
|
|
||||||
* WINGs server.c: example how to create a network server using WMConnection
|
|
||||||
*
|
|
||||||
* Copyright (c) 2001-2003 Dan Pascu
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <WINGs/WINGs.h>
|
|
||||||
|
|
||||||
#define _(P) P
|
|
||||||
#define MAXCMD_SIZE 512
|
|
||||||
|
|
||||||
char *SEConnectionShouldBeRemovedNotification = "SEConnectionShouldBeRemovedNotification";
|
|
||||||
|
|
||||||
static void didReceiveInput(ConnectionDelegate * self, WMConnection * cPtr);
|
|
||||||
|
|
||||||
static void connectionDidDie(ConnectionDelegate * self, WMConnection * cPtr);
|
|
||||||
|
|
||||||
static void connectionDidTimeout(ConnectionDelegate * self, WMConnection * cPtr);
|
|
||||||
|
|
||||||
extern char *SEConnectionShouldBeRemovedNotification;
|
|
||||||
|
|
||||||
static WMUserDefaults *timeDB = NULL;
|
|
||||||
static char *ServerAddress = NULL;
|
|
||||||
static char *ServerPort = NULL;
|
|
||||||
static WMArray *allowedHostList = NULL;
|
|
||||||
static WMArray *clientConnections = NULL;
|
|
||||||
static WMConnection *serverPtr = NULL;
|
|
||||||
|
|
||||||
static ConnectionDelegate socketDelegate = {
|
|
||||||
NULL, /* client data */
|
|
||||||
NULL, /* canResumeSending */
|
|
||||||
NULL, /* didCatchException */
|
|
||||||
connectionDidDie, /* didDie */
|
|
||||||
NULL, /* didInitialize */
|
|
||||||
didReceiveInput, /* didReceiveInput */
|
|
||||||
connectionDidTimeout /* didTimeout */
|
|
||||||
};
|
|
||||||
|
|
||||||
void wAbort(Bool foo)
|
|
||||||
{
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void printHelp(char *progname)
|
|
||||||
{
|
|
||||||
printf(_("usage: %s [options]\n\n"), progname);
|
|
||||||
puts(_(" --help print this message"));
|
|
||||||
puts(_(" --listen [address:]port only listen on the specified address/port"));
|
|
||||||
puts(_(" --allow host1[,host2...] only allow connections from listed hosts\n"));
|
|
||||||
puts(_(" By default server listens on all interfaces and port 34567, unless"
|
|
||||||
" something\nelse is specified with the --listen option. If address is"
|
|
||||||
" omitted or the keyword\n'Any' is used, it will listen on all interfaces else"
|
|
||||||
" only on the specified one.\n\nFor example --listen localhost: will"
|
|
||||||
" listen on the default port 34567, but only\non connections comming"
|
|
||||||
" in through the loopback interface.\n\n Also by default the server"
|
|
||||||
" listens to incoming connections from any host,\nunless a list of"
|
|
||||||
" hosts is given with the --allow option, in which case it will\nreject"
|
|
||||||
" connections not comming from those hosts.\nThe list of hosts is comma"
|
|
||||||
" separated and should NOT contain ANY spaces."));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void enqueueConnectionForRemoval(WMConnection * cPtr)
|
|
||||||
{
|
|
||||||
WMNotification *notif;
|
|
||||||
|
|
||||||
/*don't release notif here. it will be released by queue after processing */
|
|
||||||
notif = WMCreateNotification(SEConnectionShouldBeRemovedNotification, cPtr, NULL);
|
|
||||||
WMEnqueueNotification(WMGetDefaultNotificationQueue(), notif, WMPostASAP);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sendMessage(WMConnection * cPtr, char *message)
|
|
||||||
{
|
|
||||||
WMData *aData;
|
|
||||||
int res;
|
|
||||||
|
|
||||||
if (WMGetConnectionState(cPtr) != WCConnected)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
aData = WMCreateDataWithBytes(message, strlen(message));
|
|
||||||
res = WMSendConnectionData(cPtr, aData);
|
|
||||||
WMReleaseData(aData);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Bool enqueueMessage(WMConnection * cPtr, char *message)
|
|
||||||
{
|
|
||||||
WMData *aData;
|
|
||||||
Bool res;
|
|
||||||
|
|
||||||
if (WMGetConnectionState(cPtr) != WCConnected)
|
|
||||||
return False;
|
|
||||||
|
|
||||||
aData = WMCreateDataWithBytes(message, strlen(message));
|
|
||||||
res = WMEnqueueConnectionData(cPtr, aData);
|
|
||||||
WMReleaseData(aData);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *findDelimiter(char *data, const char *endPtr)
|
|
||||||
{
|
|
||||||
wassertrv(data < endPtr, NULL);
|
|
||||||
|
|
||||||
while (data < endPtr && *data != '\n' && *data != '\r' && *data != ';' && *data != '\0')
|
|
||||||
data++;
|
|
||||||
|
|
||||||
if (data < endPtr)
|
|
||||||
return data;
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static WMArray *getAvailableMessages(WMConnection * cPtr)
|
|
||||||
{
|
|
||||||
char *ptr, *crtPos, *buffer;
|
|
||||||
const char *bytes, *endPtr;
|
|
||||||
WMData *aData, *receivedData, *holdData;
|
|
||||||
WMRange range;
|
|
||||||
WMArray *messages;
|
|
||||||
int length;
|
|
||||||
|
|
||||||
receivedData = WMGetConnectionAvailableData(cPtr);
|
|
||||||
if (!receivedData)
|
|
||||||
return NULL;
|
|
||||||
if ((length = WMGetDataLength(receivedData)) == 0) {
|
|
||||||
WMReleaseData(receivedData);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
holdData = (WMData *) WMGetConnectionClientData(cPtr);
|
|
||||||
if (holdData) {
|
|
||||||
WMAppendData(holdData, receivedData);
|
|
||||||
WMReleaseData(receivedData);
|
|
||||||
WMSetConnectionClientData(cPtr, NULL);
|
|
||||||
aData = holdData;
|
|
||||||
} else {
|
|
||||||
aData = receivedData;
|
|
||||||
}
|
|
||||||
|
|
||||||
length = WMGetDataLength(aData);
|
|
||||||
bytes = (char *)WMDataBytes(aData);
|
|
||||||
endPtr = bytes + length;
|
|
||||||
|
|
||||||
messages = WMCreateArrayWithDestructor(1, wfree);
|
|
||||||
crtPos = (char *)bytes;
|
|
||||||
while (crtPos < endPtr && (ptr = findDelimiter(crtPos, endPtr)) != NULL) {
|
|
||||||
range.position = (crtPos - bytes);
|
|
||||||
range.count = (ptr - crtPos);
|
|
||||||
if (range.count > MAXCMD_SIZE) {
|
|
||||||
/* Hmmm... The message is too long. Possibly that someone is
|
|
||||||
* flooding us, or there is a dumb client which do not know
|
|
||||||
* who is talking to. */
|
|
||||||
sendMessage(cPtr, "Command too long\n\r");
|
|
||||||
WMFreeArray(messages);
|
|
||||||
WMReleaseData(aData);
|
|
||||||
WMCloseConnection(cPtr);
|
|
||||||
enqueueConnectionForRemoval(cPtr);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
buffer = wmalloc(range.count + 1);
|
|
||||||
WMGetDataBytesWithRange(aData, buffer, range);
|
|
||||||
buffer[range.count] = '\0';
|
|
||||||
WMAddToArray(messages, buffer);
|
|
||||||
crtPos = ptr;
|
|
||||||
while (crtPos < endPtr && (*crtPos == '\n' || *crtPos == '\r' ||
|
|
||||||
*crtPos == '\t' || *crtPos == '\0' ||
|
|
||||||
*crtPos == ';' || *crtPos == ' ')) {
|
|
||||||
crtPos++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (crtPos < endPtr) {
|
|
||||||
range.position = (crtPos - bytes);
|
|
||||||
range.count = (endPtr - crtPos);
|
|
||||||
if (range.count > MAXCMD_SIZE) {
|
|
||||||
/* Flooooooding!!!! */
|
|
||||||
sendMessage(cPtr, "Message too long\n\r");
|
|
||||||
WMFreeArray(messages);
|
|
||||||
WMReleaseData(aData);
|
|
||||||
WMCloseConnection(cPtr);
|
|
||||||
enqueueConnectionForRemoval(cPtr);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
holdData = WMGetSubdataWithRange(aData, range);
|
|
||||||
WMSetConnectionClientData(cPtr, holdData);
|
|
||||||
}
|
|
||||||
WMReleaseData(aData);
|
|
||||||
|
|
||||||
if (WMGetArrayItemCount(messages) == 0) {
|
|
||||||
WMFreeArray(messages);
|
|
||||||
messages = NULL;
|
|
||||||
}
|
|
||||||
return messages;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void complainAboutBadArgs(WMConnection * cPtr, char *cmdName, char *badArgs)
|
|
||||||
{
|
|
||||||
char *buf = wmalloc(strlen(cmdName) + strlen(badArgs) + 100);
|
|
||||||
|
|
||||||
sprintf(buf, _("Invalid parameters '%s' for command %s. Use HELP for"
|
|
||||||
" a list of commands.\n"), badArgs, cmdName);
|
|
||||||
sendMessage(cPtr, buf);
|
|
||||||
wfree(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sendUpdateMessage(WMConnection * cPtr, char *id, int time)
|
|
||||||
{
|
|
||||||
char *buf = wmalloc(strlen(id) + 100);
|
|
||||||
|
|
||||||
sprintf(buf, "%s has %i minutes left\n", id, time);
|
|
||||||
sendMessage(cPtr, buf);
|
|
||||||
wfree(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void showId(WMConnection * cPtr)
|
|
||||||
{
|
|
||||||
sendMessage(cPtr, "Server example based on WMConnection\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void showHelp(WMConnection * cPtr)
|
|
||||||
{
|
|
||||||
char *buf = wmalloc(strlen(WMGetApplicationName()) + 16);
|
|
||||||
|
|
||||||
sprintf(buf, _("%s commands:\n\n"), WMGetApplicationName());
|
|
||||||
|
|
||||||
enqueueMessage(cPtr, _("\n"));
|
|
||||||
enqueueMessage(cPtr, buf);
|
|
||||||
enqueueMessage(cPtr, _("GET <id>\t- return time left (in minutes) " "for user with id <id>\n"));
|
|
||||||
enqueueMessage(cPtr, _("SET <id> <time>\t- set time limit to <time> " "minutes for user with id <id>\n"));
|
|
||||||
enqueueMessage(cPtr, _("ADD <id> <time>\t- add <time> minutes " "for user with id <id>\n"));
|
|
||||||
enqueueMessage(cPtr, _("SUB <id> <time>\t- subtract <time> minutes " "for user with id <id>\n"));
|
|
||||||
enqueueMessage(cPtr, _("REMOVE <id>\t- remove time limitations for " "user with id <id>\n"));
|
|
||||||
enqueueMessage(cPtr, _("LIST\t\t- list all users and their " "corresponding time limit\n"));
|
|
||||||
enqueueMessage(cPtr, _("ID\t\t- returns the Time Manager " "identification string\n"));
|
|
||||||
enqueueMessage(cPtr, _("EXIT\t\t- exits session\n"));
|
|
||||||
enqueueMessage(cPtr, _("QUIT\t\t- exits session\n"));
|
|
||||||
enqueueMessage(cPtr, _("HELP\t\t- show this message\n\n"));
|
|
||||||
/* Just flush the queue we made before */
|
|
||||||
WMFlushConnection(cPtr);
|
|
||||||
wfree(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void listUsers(WMConnection * cPtr)
|
|
||||||
{
|
|
||||||
WMPropList *userList;
|
|
||||||
char *id;
|
|
||||||
int i, time;
|
|
||||||
|
|
||||||
userList = WMGetUDKeys(timeDB);
|
|
||||||
|
|
||||||
for (i = 0; i < WMGetPropListItemCount(userList); i++) {
|
|
||||||
id = WMGetFromPLString(WMGetFromPLArray(userList, i));
|
|
||||||
time = WMGetUDIntegerForKey(timeDB, id);
|
|
||||||
sendUpdateMessage(cPtr, id, time);
|
|
||||||
}
|
|
||||||
|
|
||||||
WMReleasePropList(userList);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setTimeForUser(WMConnection * cPtr, char *cmdArgs)
|
|
||||||
{
|
|
||||||
char *id;
|
|
||||||
int i, time;
|
|
||||||
|
|
||||||
id = wmalloc(strlen(cmdArgs));
|
|
||||||
if (sscanf(cmdArgs, "%s %d", id, &time) != 2) {
|
|
||||||
complainAboutBadArgs(cPtr, "SET", cmdArgs);
|
|
||||||
wfree(id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (time < 0)
|
|
||||||
time = 0;
|
|
||||||
|
|
||||||
WMSetUDIntegerForKey(timeDB, time, id);
|
|
||||||
|
|
||||||
for (i = 0; i < WMGetArrayItemCount(clientConnections); i++) {
|
|
||||||
cPtr = WMGetFromArray(clientConnections, i);
|
|
||||||
sendUpdateMessage(cPtr, id, time);
|
|
||||||
}
|
|
||||||
wfree(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void addTimeToUser(WMConnection * cPtr, char *cmdArgs)
|
|
||||||
{
|
|
||||||
char *id;
|
|
||||||
int i, time, newTime;
|
|
||||||
|
|
||||||
id = wmalloc(strlen(cmdArgs));
|
|
||||||
if (sscanf(cmdArgs, "%s %d", id, &time) != 2) {
|
|
||||||
complainAboutBadArgs(cPtr, "ADD", cmdArgs);
|
|
||||||
wfree(id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
newTime = WMGetUDIntegerForKey(timeDB, id) + time;
|
|
||||||
if (newTime < 0)
|
|
||||||
newTime = 0;
|
|
||||||
|
|
||||||
WMSetUDIntegerForKey(timeDB, newTime, id);
|
|
||||||
|
|
||||||
for (i = 0; i < WMGetArrayItemCount(clientConnections); i++) {
|
|
||||||
cPtr = WMGetFromArray(clientConnections, i);
|
|
||||||
sendUpdateMessage(cPtr, id, newTime);
|
|
||||||
}
|
|
||||||
wfree(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void subTimeFromUser(WMConnection * cPtr, char *cmdArgs)
|
|
||||||
{
|
|
||||||
char *id;
|
|
||||||
int i, time, newTime;
|
|
||||||
|
|
||||||
id = wmalloc(strlen(cmdArgs));
|
|
||||||
if (sscanf(cmdArgs, "%s %d", id, &time) != 2) {
|
|
||||||
complainAboutBadArgs(cPtr, "SUB", cmdArgs);
|
|
||||||
wfree(id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
newTime = WMGetUDIntegerForKey(timeDB, id) - time;
|
|
||||||
if (newTime < 0)
|
|
||||||
newTime = 0;
|
|
||||||
|
|
||||||
WMSetUDIntegerForKey(timeDB, newTime, id);
|
|
||||||
|
|
||||||
for (i = 0; i < WMGetArrayItemCount(clientConnections); i++) {
|
|
||||||
cPtr = WMGetFromArray(clientConnections, i);
|
|
||||||
sendUpdateMessage(cPtr, id, newTime);
|
|
||||||
}
|
|
||||||
wfree(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void removeTimeForUser(WMConnection * cPtr, char *cmdArgs)
|
|
||||||
{
|
|
||||||
char *ptr;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (cmdArgs[0] == '\0') {
|
|
||||||
sendMessage(cPtr, _("Missing parameter for command REMOVE."
|
|
||||||
" Use HELP for a list of commands.\n"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr = cmdArgs;
|
|
||||||
while (*ptr && *ptr != ' ' && *ptr != '\t')
|
|
||||||
ptr++;
|
|
||||||
*ptr = '\0';
|
|
||||||
|
|
||||||
WMRemoveUDObjectForKey(timeDB, cmdArgs);
|
|
||||||
|
|
||||||
for (i = 0; i < WMGetArrayItemCount(clientConnections); i++) {
|
|
||||||
cPtr = WMGetFromArray(clientConnections, i);
|
|
||||||
sendUpdateMessage(cPtr, cmdArgs, -1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void getTimeForUser(WMConnection * cPtr, char *cmdArgs)
|
|
||||||
{
|
|
||||||
char *ptr;
|
|
||||||
int time;
|
|
||||||
|
|
||||||
if (cmdArgs[0] == '\0') {
|
|
||||||
sendMessage(cPtr, _("Missing parameter for command GET." " Use HELP for a list of commands.\n"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr = cmdArgs;
|
|
||||||
while (*ptr && *ptr != ' ' && *ptr != '\t')
|
|
||||||
ptr++;
|
|
||||||
*ptr = '\0';
|
|
||||||
|
|
||||||
if (WMGetUDObjectForKey(timeDB, cmdArgs) != NULL)
|
|
||||||
time = WMGetUDIntegerForKey(timeDB, cmdArgs);
|
|
||||||
else
|
|
||||||
time = -1;
|
|
||||||
|
|
||||||
sendUpdateMessage(cPtr, cmdArgs, time);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handleConnection(WMConnection * cPtr)
|
|
||||||
{
|
|
||||||
char *command, *ptr, *cmdArgs, *buffer;
|
|
||||||
WMArray *commands;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
commands = getAvailableMessages(cPtr);
|
|
||||||
if (!commands)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (i = 0; i < WMGetArrayItemCount(commands); i++) {
|
|
||||||
command = WMGetFromArray(commands, i);
|
|
||||||
while (*command && (*command == ' ' || *command == '\t'))
|
|
||||||
command++;
|
|
||||||
ptr = command;
|
|
||||||
while (*ptr && *ptr != ' ' && *ptr != '\t')
|
|
||||||
ptr++;
|
|
||||||
if (*ptr) {
|
|
||||||
*ptr = '\0';
|
|
||||||
ptr++;
|
|
||||||
}
|
|
||||||
while (*ptr && (*ptr == ' ' || *ptr == '\t'))
|
|
||||||
ptr++;
|
|
||||||
|
|
||||||
cmdArgs = ptr;
|
|
||||||
|
|
||||||
fprintf(stderr, "Command: '%s', args: '%s'\n", command, cmdArgs);
|
|
||||||
|
|
||||||
if (strcasecmp(command, "quit") == 0 || strcasecmp(command, "exit") == 0) {
|
|
||||||
sendMessage(cPtr, "Bye\n");
|
|
||||||
WMCloseConnection(cPtr);
|
|
||||||
enqueueConnectionForRemoval(cPtr);
|
|
||||||
WMFreeArray(commands);
|
|
||||||
return;
|
|
||||||
} else if (strcasecmp(command, "id") == 0) {
|
|
||||||
showId(cPtr);
|
|
||||||
} else if (strcasecmp(command, "help") == 0) {
|
|
||||||
showHelp(cPtr);
|
|
||||||
} else if (strcasecmp(command, "list") == 0) {
|
|
||||||
listUsers(cPtr);
|
|
||||||
} else if (strcasecmp(command, "set") == 0) {
|
|
||||||
setTimeForUser(cPtr, cmdArgs);
|
|
||||||
} else if (strcasecmp(command, "add") == 0) {
|
|
||||||
addTimeToUser(cPtr, cmdArgs);
|
|
||||||
} else if (strcasecmp(command, "sub") == 0) {
|
|
||||||
subTimeFromUser(cPtr, cmdArgs);
|
|
||||||
} else if (strcasecmp(command, "remove") == 0) {
|
|
||||||
removeTimeForUser(cPtr, cmdArgs);
|
|
||||||
} else if (strcasecmp(command, "get") == 0) {
|
|
||||||
getTimeForUser(cPtr, cmdArgs);
|
|
||||||
} else {
|
|
||||||
buffer = wmalloc(strlen(command) + 100);
|
|
||||||
sprintf(buffer, _("Unknown command '%s'. Try HELP for" " a list of commands.\n"), command);
|
|
||||||
sendMessage(cPtr, buffer);
|
|
||||||
wfree(buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WMFreeArray(commands);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Bool isAllowedToConnect(WMConnection * cPtr)
|
|
||||||
{
|
|
||||||
WMHost *hPtr;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (allowedHostList == NULL)
|
|
||||||
return True; /* No list. Allow all by default */
|
|
||||||
|
|
||||||
hPtr = WMGetHostWithAddress(WMGetConnectionAddress(cPtr));
|
|
||||||
for (i = 0; i < WMGetArrayItemCount(allowedHostList); i++) {
|
|
||||||
if (WMIsHostEqualToHost(hPtr, WMGetFromArray(allowedHostList, i))) {
|
|
||||||
WMReleaseHost(hPtr);
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WMReleaseHost(hPtr);
|
|
||||||
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void didReceiveInput(ConnectionDelegate * self, WMConnection * cPtr)
|
|
||||||
{
|
|
||||||
if (cPtr == serverPtr) {
|
|
||||||
WMConnection *newPtr = WMAcceptConnection(cPtr);
|
|
||||||
|
|
||||||
if (newPtr) {
|
|
||||||
if (isAllowedToConnect(newPtr)) {
|
|
||||||
WMSetConnectionDelegate(newPtr, &socketDelegate);
|
|
||||||
WMSetConnectionSendTimeout(newPtr, 120);
|
|
||||||
WMAddToArray(clientConnections, newPtr);
|
|
||||||
} else {
|
|
||||||
sendMessage(newPtr, "Sorry, you are not allowed to connect.\n");
|
|
||||||
WMDestroyConnection(newPtr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* Data arriving on an already-connected socket */
|
|
||||||
handleConnection(cPtr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void connectionDidTimeout(ConnectionDelegate * self, WMConnection * cPtr)
|
|
||||||
{
|
|
||||||
WMHost *hPtr;
|
|
||||||
|
|
||||||
if (cPtr == serverPtr) {
|
|
||||||
wfatal(_("The server listening socket did timeout. Exiting."));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
hPtr = WMGetHostWithAddress(WMGetConnectionAddress(cPtr));
|
|
||||||
wwarning(_("Connection with %s did timeout. Closing connection."), WMGetHostName(hPtr));
|
|
||||||
WMReleaseHost(hPtr);
|
|
||||||
|
|
||||||
enqueueConnectionForRemoval(cPtr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void connectionDidDie(ConnectionDelegate * self, WMConnection * cPtr)
|
|
||||||
{
|
|
||||||
if (cPtr == serverPtr) {
|
|
||||||
/* trouble. server listening port itself died!!! */
|
|
||||||
wfatal(_("The server listening socket died. Exiting."));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
enqueueConnectionForRemoval(cPtr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void removeConnection(void *observer, WMNotification * notification)
|
|
||||||
{
|
|
||||||
WMConnection *cPtr = (WMConnection *) WMGetNotificationObject(notification);
|
|
||||||
WMData *data;
|
|
||||||
|
|
||||||
WMRemoveFromArray(clientConnections, cPtr);
|
|
||||||
if ((data = (WMData *) WMGetConnectionClientData(cPtr)) != NULL)
|
|
||||||
WMReleaseData(data);
|
|
||||||
WMDestroyConnection(cPtr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void updatedDomain(void *observer, WMNotification * notification)
|
|
||||||
{
|
|
||||||
wmessage("defaults domain file changed on disk. synchronizing.");
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static Bool isDifferent(char *str1, char *str2)
|
|
||||||
{
|
|
||||||
if ((!str1 && !str2) || (str1 && str2 && strcmp(str1, str2) == 0))
|
|
||||||
return False;
|
|
||||||
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
wsetabort(wAbort);
|
|
||||||
|
|
||||||
WMInitializeApplication("server", &argc, argv);
|
|
||||||
|
|
||||||
if (argc > 1) {
|
|
||||||
for (i = 1; i < argc; i++) {
|
|
||||||
if (strcmp(argv[i], "--help") == 0) {
|
|
||||||
printHelp(argv[0]);
|
|
||||||
exit(0);
|
|
||||||
} else if (strcmp(argv[i], "--listen") == 0) {
|
|
||||||
char *p;
|
|
||||||
|
|
||||||
if ((p = strchr(argv[++i], ':')) != NULL) {
|
|
||||||
*p = 0;
|
|
||||||
ServerAddress = wstrdup(argv[i]);
|
|
||||||
ServerPort = wstrdup(p + 1);
|
|
||||||
*p = ':';
|
|
||||||
if (ServerAddress[0] == 0) {
|
|
||||||
wfree(ServerAddress);
|
|
||||||
ServerAddress = NULL;
|
|
||||||
}
|
|
||||||
if (ServerPort[0] == 0) {
|
|
||||||
wfree(ServerPort);
|
|
||||||
ServerPort = "34567";
|
|
||||||
}
|
|
||||||
} else if (argv[i][0] != 0) {
|
|
||||||
ServerPort = argv[i];
|
|
||||||
}
|
|
||||||
} else if (strcmp(argv[i], "--allow") == 0) {
|
|
||||||
char *p, *ptr;
|
|
||||||
int done;
|
|
||||||
WMHost *hPtr;
|
|
||||||
|
|
||||||
ptr = argv[++i];
|
|
||||||
done = 0;
|
|
||||||
while (!done) {
|
|
||||||
if ((p = strchr(ptr, ',')) != NULL) {
|
|
||||||
*p = 0;
|
|
||||||
}
|
|
||||||
if (*ptr != 0) {
|
|
||||||
hPtr = WMGetHostWithName(ptr);
|
|
||||||
if (hPtr) {
|
|
||||||
if (!allowedHostList)
|
|
||||||
allowedHostList = WMCreateArray(4);
|
|
||||||
WMAddToArray(allowedHostList, hPtr);
|
|
||||||
} else {
|
|
||||||
wwarning(_("Unknown host '%s'. Ignored."), ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p != NULL) {
|
|
||||||
*p = ',';
|
|
||||||
ptr = p + 1;
|
|
||||||
} else {
|
|
||||||
done = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
printf(_("%s: invalid argument '%s'\n"), argv[0], argv[i]);
|
|
||||||
printf(_("Try '%s --help' for more information\n"), argv[0]);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
timeDB = WMGetDefaultsFromPath("./UserTime.plist");
|
|
||||||
WMAddNotificationObserver(updatedDomain, NULL, WMUserDefaultsDidChangeNotification, NULL);
|
|
||||||
|
|
||||||
clientConnections = WMCreateArray(4);
|
|
||||||
|
|
||||||
/* A NULL ServerAddress means to listen on any address the host has.
|
|
||||||
* Else if ServerAddress points to a specific address (like "localhost",
|
|
||||||
* "host.domain.com" or "192.168.1.1"), then it will only listen on that
|
|
||||||
* interface and ignore incoming connections on the others. */
|
|
||||||
if (ServerAddress && strcasecmp(ServerAddress, "Any") == 0)
|
|
||||||
ServerAddress = NULL;
|
|
||||||
if (ServerPort == NULL)
|
|
||||||
ServerPort = "34567";
|
|
||||||
|
|
||||||
printf("Server will listen on '%s:%s'\n", ServerAddress ? ServerAddress : "Any", ServerPort);
|
|
||||||
printf("This server will allow connections from:");
|
|
||||||
if (allowedHostList) {
|
|
||||||
int i;
|
|
||||||
char *hName;
|
|
||||||
|
|
||||||
for (i = 0; i < WMGetArrayItemCount(allowedHostList); i++) {
|
|
||||||
hName = WMGetHostName(WMGetFromArray(allowedHostList, i));
|
|
||||||
printf("%s'%s'", i == 0 ? " " : ", ", hName);
|
|
||||||
}
|
|
||||||
printf(".\n");
|
|
||||||
} else {
|
|
||||||
printf(" any host.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
serverPtr = WMCreateConnectionAsServerAtAddress(ServerAddress, ServerPort, NULL);
|
|
||||||
|
|
||||||
if (!serverPtr) {
|
|
||||||
wfatal("could not create server on `%s:%s`. Exiting.",
|
|
||||||
ServerAddress ? ServerAddress : "localhost", ServerPort);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
WMSetConnectionDelegate(serverPtr, &socketDelegate);
|
|
||||||
|
|
||||||
WMAddNotificationObserver(removeConnection, NULL, SEConnectionShouldBeRemovedNotification, NULL);
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
/* The ASAP notification queue is called at the end of WHandleEvents()
|
|
||||||
* There's where died connections we get while running through
|
|
||||||
* WHandleEvents() get removed. */
|
|
||||||
WHandleEvents();
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -69,13 +69,11 @@ libWINGs_la_SOURCES = \
|
|||||||
libWUtil_la_SOURCES = \
|
libWUtil_la_SOURCES = \
|
||||||
array.c \
|
array.c \
|
||||||
bagtree.c \
|
bagtree.c \
|
||||||
connection.c \
|
|
||||||
data.c \
|
data.c \
|
||||||
error.c \
|
error.c \
|
||||||
findfile.c \
|
findfile.c \
|
||||||
handlers.c \
|
handlers.c \
|
||||||
hashtable.c \
|
hashtable.c \
|
||||||
host.c \
|
|
||||||
memory.c \
|
memory.c \
|
||||||
misc.c \
|
misc.c \
|
||||||
notification.c \
|
notification.c \
|
||||||
|
|||||||
@@ -86,27 +86,6 @@ typedef enum {
|
|||||||
} WMNotificationCoalescing;
|
} WMNotificationCoalescing;
|
||||||
|
|
||||||
|
|
||||||
/* The possible states for connections */
|
|
||||||
typedef enum {
|
|
||||||
WCNotConnected=0,
|
|
||||||
WCListening,
|
|
||||||
WCInProgress,
|
|
||||||
WCFailed,
|
|
||||||
WCConnected,
|
|
||||||
WCTimedOut,
|
|
||||||
WCDied,
|
|
||||||
WCClosed
|
|
||||||
} WMConnectionState;
|
|
||||||
|
|
||||||
|
|
||||||
/* The possible states for connection timeouts */
|
|
||||||
typedef enum {
|
|
||||||
WCTNone=0,
|
|
||||||
WCTWhileOpening,
|
|
||||||
WCTWhileSending
|
|
||||||
} WMConnectionTimeoutState;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
WBNotFound = INT_MIN, /* element was not found in WMBag */
|
WBNotFound = INT_MIN, /* element was not found in WMBag */
|
||||||
@@ -185,24 +164,6 @@ typedef struct {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* The connection callbacks */
|
|
||||||
typedef struct ConnectionDelegate {
|
|
||||||
void *data;
|
|
||||||
|
|
||||||
void (*canResumeSending)(struct ConnectionDelegate *self, WMConnection *cPtr);
|
|
||||||
|
|
||||||
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);
|
||||||
@@ -907,135 +868,6 @@ extern char *WMUserDefaultsDidChangeNotification;
|
|||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
/* 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 WMArray with all the names of the host.
|
|
||||||
*/
|
|
||||||
char* WMGetHostName(WMHost* hPtr);
|
|
||||||
|
|
||||||
/* The returned array is R/O. Do not modify it, and do not free it! */
|
|
||||||
WMArray* 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 WMArray with all addresses of the host.
|
|
||||||
*/
|
|
||||||
char* WMGetHostAddress(WMHost* hPtr);
|
|
||||||
|
|
||||||
/* The returned array is R/O. Do not modify it, and do not free it! */
|
|
||||||
WMArray* 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);
|
|
||||||
|
|
||||||
Bool WMSetConnectionNonBlocking(WMConnection *cPtr, Bool flag);
|
|
||||||
|
|
||||||
Bool WMSetConnectionCloseOnExec(WMConnection *cPtr, Bool flag);
|
|
||||||
|
|
||||||
void WMSetConnectionShutdownOnClose(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);
|
|
||||||
|
|
||||||
WMConnectionTimeoutState WMGetConnectionTimeoutState(WMConnection *cPtr);
|
|
||||||
|
|
||||||
WMArray* WMGetConnectionUnsentData(WMConnection *cPtr);
|
|
||||||
|
|
||||||
#define WMGetConnectionQueuedData(cPtr) WMGetConnectionUnsentData(cPtr)
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Passing timeout==0 in the SetTimeout functions below, will reset that
|
|
||||||
* timeout to its default value.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* The default timeout inherited by all WMConnection operations, if none set */
|
|
||||||
void WMSetConnectionDefaultTimeout(unsigned int timeout);
|
|
||||||
|
|
||||||
/* Global timeout for all WMConnection objects, for opening a new connection */
|
|
||||||
void WMSetConnectionOpenTimeout(unsigned int timeout);
|
|
||||||
|
|
||||||
/* Connection specific timeout for sending out data */
|
|
||||||
void WMSetConnectionSendTimeout(WMConnection *cPtr, unsigned int timeout);
|
|
||||||
|
|
||||||
|
|
||||||
/* Global variables */
|
/* Global variables */
|
||||||
|
|
||||||
extern int WCErrorCode;
|
extern int WCErrorCode;
|
||||||
|
|||||||
@@ -1,958 +0,0 @@
|
|||||||
/*
|
|
||||||
* WINGs WMConnection function library
|
|
||||||
*
|
|
||||||
* Copyright (c) 1999-2003 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.
|
|
||||||
* - decide what to do with all wwarning() calls that are still there.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "wconfig.h"
|
|
||||||
|
|
||||||
#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
|
|
||||||
|
|
||||||
/* For Solaris */
|
|
||||||
#ifndef INADDR_NONE
|
|
||||||
# define INADDR_NONE -1
|
|
||||||
#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 NONBLOCK_OPT O_NONBLOCK
|
|
||||||
|
|
||||||
#define NETBUF_SIZE 4096
|
|
||||||
|
|
||||||
#define DEF_TIMEOUT 600 /* 600 seconds == 10 minutes */
|
|
||||||
|
|
||||||
int WCErrorCode = 0;
|
|
||||||
|
|
||||||
static Bool SigInitialized = False;
|
|
||||||
|
|
||||||
static unsigned int DefaultTimeout = DEF_TIMEOUT;
|
|
||||||
static unsigned int OpenTimeout = DEF_TIMEOUT;
|
|
||||||
|
|
||||||
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 */
|
|
||||||
|
|
||||||
WMArray *outputQueue;
|
|
||||||
unsigned bufPos;
|
|
||||||
|
|
||||||
TimeoutData sendTimeout;
|
|
||||||
TimeoutData openTimeout;
|
|
||||||
|
|
||||||
WMConnectionState state;
|
|
||||||
WMConnectionTimeoutState timeoutState;
|
|
||||||
|
|
||||||
char *address;
|
|
||||||
char *service;
|
|
||||||
char *protocol;
|
|
||||||
|
|
||||||
Bool closeOnRelease;
|
|
||||||
Bool shutdownOnClose;
|
|
||||||
Bool wasNonBlocking;
|
|
||||||
Bool isNonBlocking;
|
|
||||||
|
|
||||||
} W_Connection;
|
|
||||||
|
|
||||||
static void clearOutputQueue(WMConnection * cPtr)
|
|
||||||
{
|
|
||||||
cPtr->bufPos = 0;
|
|
||||||
WMEmptyArray(cPtr->outputQueue);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void openTimeout(void *cdata)
|
|
||||||
{
|
|
||||||
WMConnection *cPtr = (WMConnection *) cdata;
|
|
||||||
|
|
||||||
cPtr->openTimeout.handler = NULL;
|
|
||||||
if (cPtr->handler.write) {
|
|
||||||
WMDeleteInputHandler(cPtr->handler.write);
|
|
||||||
cPtr->handler.write = NULL;
|
|
||||||
}
|
|
||||||
if (cPtr->state != WCConnected) {
|
|
||||||
cPtr->state = WCTimedOut;
|
|
||||||
cPtr->timeoutState = WCTWhileOpening;
|
|
||||||
if (cPtr->delegate && cPtr->delegate->didTimeout) {
|
|
||||||
(*cPtr->delegate->didTimeout) (cPtr->delegate, cPtr);
|
|
||||||
} else {
|
|
||||||
WMCloseConnection(cPtr);
|
|
||||||
cPtr->state = WCTimedOut; /* the above set state to WCClosed */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sendTimeout(void *cdata)
|
|
||||||
{
|
|
||||||
WMConnection *cPtr = (WMConnection *) cdata;
|
|
||||||
|
|
||||||
cPtr->sendTimeout.handler = NULL;
|
|
||||||
if (cPtr->handler.write) {
|
|
||||||
WMDeleteInputHandler(cPtr->handler.write);
|
|
||||||
cPtr->handler.write = NULL;
|
|
||||||
}
|
|
||||||
if (WMGetArrayItemCount(cPtr->outputQueue) > 0) {
|
|
||||||
clearOutputQueue(cPtr);
|
|
||||||
cPtr->state = WCTimedOut;
|
|
||||||
cPtr->timeoutState = WCTWhileSending;
|
|
||||||
/* // should we close it no matter what (after calling the didTimeout
|
|
||||||
// delegate)? -Dan */
|
|
||||||
if (cPtr->delegate && cPtr->delegate->didTimeout) {
|
|
||||||
(*cPtr->delegate->didTimeout) (cPtr->delegate, cPtr);
|
|
||||||
} else {
|
|
||||||
WMCloseConnection(cPtr);
|
|
||||||
cPtr->state = WCTimedOut; /* the above set state to WCClosed */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void inputHandler(int fd, int mask, void *clientData)
|
|
||||||
{
|
|
||||||
WMConnection *cPtr = (WMConnection *) clientData;
|
|
||||||
|
|
||||||
if (cPtr->state == WCClosed || cPtr->state == WCDied)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if ((mask & WIWriteMask)) {
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if (cPtr->state == WCInProgress) {
|
|
||||||
Bool failed;
|
|
||||||
socklen_t len = sizeof(result);
|
|
||||||
|
|
||||||
WCErrorCode = 0;
|
|
||||||
if (getsockopt(cPtr->sock, SOL_SOCKET, SO_ERROR,
|
|
||||||
(void *)&result, &len) == 0 && result != 0) {
|
|
||||||
cPtr->state = WCFailed;
|
|
||||||
WCErrorCode = result;
|
|
||||||
failed = True;
|
|
||||||
/* should call wsyserrorwithcode(result, ...) here? */
|
|
||||||
} else {
|
|
||||||
cPtr->state = WCConnected;
|
|
||||||
failed = False;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cPtr->handler.write) {
|
|
||||||
WMDeleteInputHandler(cPtr->handler.write);
|
|
||||||
cPtr->handler.write = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cPtr->openTimeout.handler) {
|
|
||||||
WMDeleteTimerHandler(cPtr->openTimeout.handler);
|
|
||||||
cPtr->openTimeout.handler = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cPtr->delegate && cPtr->delegate->didInitialize)
|
|
||||||
(*cPtr->delegate->didInitialize) (cPtr->delegate, cPtr);
|
|
||||||
|
|
||||||
/* we use failed and not cPtr->state here, because cPtr may be
|
|
||||||
* destroyed by the delegate called above if the connection failed
|
|
||||||
*/
|
|
||||||
if (failed)
|
|
||||||
return;
|
|
||||||
} else if (cPtr->state == WCConnected) {
|
|
||||||
result = WMFlushConnection(cPtr);
|
|
||||||
if (result > 0 && cPtr->delegate && cPtr->delegate->canResumeSending) {
|
|
||||||
(*cPtr->delegate->canResumeSending) (cPtr->delegate, 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)
|
|
||||||
{
|
|
||||||
int state;
|
|
||||||
Bool isNonBlock;
|
|
||||||
|
|
||||||
state = fcntl(sock, F_GETFL, 0);
|
|
||||||
|
|
||||||
if (state < 0) {
|
|
||||||
/* set WCErrorCode here? -Dan */
|
|
||||||
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) {
|
|
||||||
/* set WCErrorCode here? -Dan */
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setConnectionAddress(WMConnection * cPtr, struct sockaddr_in *socketaddr)
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
#ifndef HAVE_INET_ATON
|
|
||||||
if ((socketaddr.sin_addr.s_addr = inet_addr(name)) == INADDR_NONE) {
|
|
||||||
#else
|
|
||||||
if (inet_aton(name, &socketaddr.sin_addr) == 0) {
|
|
||||||
#endif
|
|
||||||
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 void dummyHandler(int signum)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static WMConnection *createConnectionWithSocket(int sock, Bool closeOnRelease)
|
|
||||||
{
|
|
||||||
WMConnection *cPtr;
|
|
||||||
struct sigaction sig_action;
|
|
||||||
|
|
||||||
cPtr = wmalloc(sizeof(WMConnection));
|
|
||||||
wretain(cPtr);
|
|
||||||
memset(cPtr, 0, sizeof(WMConnection));
|
|
||||||
|
|
||||||
fcntl(sock, F_SETFD, FD_CLOEXEC); /* by default close on exec */
|
|
||||||
|
|
||||||
cPtr->sock = sock;
|
|
||||||
cPtr->openTimeout.timeout = OpenTimeout;
|
|
||||||
cPtr->openTimeout.handler = NULL;
|
|
||||||
cPtr->sendTimeout.timeout = DefaultTimeout;
|
|
||||||
cPtr->sendTimeout.handler = NULL;
|
|
||||||
cPtr->closeOnRelease = closeOnRelease;
|
|
||||||
cPtr->shutdownOnClose = 1;
|
|
||||||
cPtr->outputQueue = WMCreateArrayWithDestructor(16, (WMFreeDataProc *) WMReleaseData);
|
|
||||||
cPtr->state = WCNotConnected;
|
|
||||||
cPtr->timeoutState = WCTNone;
|
|
||||||
|
|
||||||
/* ignore dead pipe */
|
|
||||||
if (!SigInitialized) {
|
|
||||||
/* Because POSIX mandates that only signal with handlers are reset
|
|
||||||
* accross an exec*(), we do not want to propagate ignoring SIGPIPEs
|
|
||||||
* to children. Hence the dummy handler. Philippe Troin <phil@fifi.org>
|
|
||||||
*/
|
|
||||||
sig_action.sa_handler = &dummyHandler;
|
|
||||||
sig_action.sa_flags = SA_RESTART;
|
|
||||||
sigaction(SIGPIPE, &sig_action, NULL);
|
|
||||||
SigInitialized = True;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cPtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
WMConnection *WMCreateConnectionWithSocket(int sock, Bool closeOnRelease)
|
|
||||||
{
|
|
||||||
WMConnection *cPtr;
|
|
||||||
struct sockaddr_in clientname;
|
|
||||||
int size;
|
|
||||||
int 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)
|
|
||||||
{
|
|
||||||
WMConnection *cPtr;
|
|
||||||
struct sockaddr_in *socketaddr;
|
|
||||||
socklen_t size;
|
|
||||||
int sock, on;
|
|
||||||
|
|
||||||
WCErrorCode = 0;
|
|
||||||
|
|
||||||
if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
|
|
||||||
wwarning(_("Bad address-service-protocol combination"));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create the actual socket */
|
|
||||||
sock = socket(PF_INET, SOCK_STREAM, 0);
|
|
||||||
if (sock < 0) {
|
|
||||||
WCErrorCode = errno;
|
|
||||||
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;
|
|
||||||
close(sock);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (listen(sock, 10) < 0) {
|
|
||||||
WCErrorCode = errno;
|
|
||||||
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;
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
WMConnection *cPtr;
|
|
||||||
struct sockaddr_in *socketaddr;
|
|
||||||
int sock;
|
|
||||||
|
|
||||||
WCErrorCode = 0;
|
|
||||||
|
|
||||||
wassertrv(service != NULL && service[0] != 0, NULL);
|
|
||||||
|
|
||||||
if (host == NULL || host[0] == 0)
|
|
||||||
host = "localhost";
|
|
||||||
|
|
||||||
if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
|
|
||||||
wwarning(_("Bad address-service-protocol combination"));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create the actual socket */
|
|
||||||
sock = socket(PF_INET, SOCK_STREAM, 0);
|
|
||||||
if (sock < 0) {
|
|
||||||
WCErrorCode = errno;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
/* make socket blocking while we connect. */
|
|
||||||
setSocketNonBlocking(sock, False);
|
|
||||||
if (connect(sock, (struct sockaddr *)socketaddr, sizeof(*socketaddr)) < 0) {
|
|
||||||
WCErrorCode = errno;
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
WMConnection *cPtr;
|
|
||||||
struct sockaddr_in *socketaddr;
|
|
||||||
int sock;
|
|
||||||
Bool isNonBlocking;
|
|
||||||
|
|
||||||
WCErrorCode = 0;
|
|
||||||
|
|
||||||
wassertrv(service != NULL && service[0] != 0, NULL);
|
|
||||||
|
|
||||||
if (host == NULL || host[0] == 0)
|
|
||||||
host = "localhost";
|
|
||||||
|
|
||||||
if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
|
|
||||||
wwarning(_("Bad address-service-protocol combination"));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create the actual socket */
|
|
||||||
sock = socket(PF_INET, SOCK_STREAM, 0);
|
|
||||||
if (sock < 0) {
|
|
||||||
WCErrorCode = errno;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
isNonBlocking = setSocketNonBlocking(sock, True);
|
|
||||||
if (connect(sock, (struct sockaddr *)socketaddr, sizeof(*socketaddr)) < 0) {
|
|
||||||
if (errno != EINPROGRESS) {
|
|
||||||
WCErrorCode = errno;
|
|
||||||
close(sock);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cPtr = createConnectionWithSocket(sock, True);
|
|
||||||
cPtr->state = WCInProgress;
|
|
||||||
cPtr->isNonBlocking = isNonBlocking;
|
|
||||||
|
|
||||||
cPtr->handler.write = WMAddInputHandler(cPtr->sock, WIWriteMask, inputHandler, cPtr);
|
|
||||||
|
|
||||||
cPtr->openTimeout.handler = WMAddTimerHandler(cPtr->openTimeout.timeout * 1000, openTimeout, cPtr);
|
|
||||||
|
|
||||||
setConnectionAddress(cPtr, socketaddr);
|
|
||||||
|
|
||||||
return cPtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void removeAllHandlers(WMConnection * cPtr)
|
|
||||||
{
|
|
||||||
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->openTimeout.handler)
|
|
||||||
WMDeleteTimerHandler(cPtr->openTimeout.handler);
|
|
||||||
if (cPtr->sendTimeout.handler)
|
|
||||||
WMDeleteTimerHandler(cPtr->sendTimeout.handler);
|
|
||||||
|
|
||||||
cPtr->handler.read = NULL;
|
|
||||||
cPtr->handler.write = NULL;
|
|
||||||
cPtr->handler.exception = NULL;
|
|
||||||
cPtr->openTimeout.handler = NULL;
|
|
||||||
cPtr->sendTimeout.handler = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WMDestroyConnection(WMConnection * cPtr)
|
|
||||||
{
|
|
||||||
if (cPtr->closeOnRelease && cPtr->sock >= 0) {
|
|
||||||
if (cPtr->shutdownOnClose) {
|
|
||||||
shutdown(cPtr->sock, SHUT_RDWR);
|
|
||||||
}
|
|
||||||
close(cPtr->sock);
|
|
||||||
}
|
|
||||||
|
|
||||||
removeAllHandlers(cPtr);
|
|
||||||
WMFreeArray(cPtr->outputQueue); /* will also free the items with the destructor */
|
|
||||||
|
|
||||||
if (cPtr->address) {
|
|
||||||
wfree(cPtr->address);
|
|
||||||
wfree(cPtr->service);
|
|
||||||
wfree(cPtr->protocol);
|
|
||||||
}
|
|
||||||
|
|
||||||
wrelease(cPtr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WMCloseConnection(WMConnection * cPtr)
|
|
||||||
{
|
|
||||||
if (cPtr->sock >= 0) {
|
|
||||||
if (cPtr->shutdownOnClose) {
|
|
||||||
shutdown(cPtr->sock, SHUT_RDWR);
|
|
||||||
}
|
|
||||||
close(cPtr->sock);
|
|
||||||
cPtr->sock = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
removeAllHandlers(cPtr);
|
|
||||||
clearOutputQueue(cPtr);
|
|
||||||
|
|
||||||
cPtr->state = WCClosed;
|
|
||||||
}
|
|
||||||
|
|
||||||
WMConnection *WMAcceptConnection(WMConnection * listener)
|
|
||||||
{
|
|
||||||
struct sockaddr_in clientname;
|
|
||||||
socklen_t size;
|
|
||||||
int newSock;
|
|
||||||
WMConnection *newConnection;
|
|
||||||
|
|
||||||
WCErrorCode = 0;
|
|
||||||
wassertrv(listener && listener->state == WCListening, NULL);
|
|
||||||
|
|
||||||
size = sizeof(clientname);
|
|
||||||
newSock = accept(listener->sock, (struct sockaddr *)&clientname, &size);
|
|
||||||
if (newSock < 0) {
|
|
||||||
WCErrorCode = ((errno != EAGAIN && errno != EWOULDBLOCK) ? errno : 0);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
newConnection = createConnectionWithSocket(newSock, True);
|
|
||||||
WMSetConnectionNonBlocking(newConnection, True);
|
|
||||||
newConnection->state = WCConnected;
|
|
||||||
setConnectionAddress(newConnection, &clientname);
|
|
||||||
|
|
||||||
return newConnection;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *WMGetConnectionAddress(WMConnection * cPtr)
|
|
||||||
{
|
|
||||||
return cPtr->address;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *WMGetConnectionService(WMConnection * cPtr)
|
|
||||||
{
|
|
||||||
return cPtr->service;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *WMGetConnectionProtocol(WMConnection * cPtr)
|
|
||||||
{
|
|
||||||
return cPtr->protocol;
|
|
||||||
}
|
|
||||||
|
|
||||||
int WMGetConnectionSocket(WMConnection * cPtr)
|
|
||||||
{
|
|
||||||
return cPtr->sock;
|
|
||||||
}
|
|
||||||
|
|
||||||
WMConnectionState WMGetConnectionState(WMConnection * cPtr)
|
|
||||||
{
|
|
||||||
return cPtr->state;
|
|
||||||
}
|
|
||||||
|
|
||||||
WMConnectionTimeoutState WMGetConnectionTimeoutState(WMConnection * cPtr)
|
|
||||||
{
|
|
||||||
return cPtr->timeoutState;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool WMEnqueueConnectionData(WMConnection * cPtr, WMData * data)
|
|
||||||
{
|
|
||||||
wassertrv(cPtr->state != WCNotConnected && cPtr->state != WCListening, False);
|
|
||||||
wassertrv(cPtr->state != WCInProgress && cPtr->state != WCFailed, False);
|
|
||||||
|
|
||||||
if (cPtr->state != WCConnected)
|
|
||||||
return False;
|
|
||||||
|
|
||||||
WMAddToArray(cPtr->outputQueue, WMRetainData(data));
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Return value:
|
|
||||||
* -1 - not connected or connection died while sending
|
|
||||||
* 0 - couldn't send the data (or part of it). data is saved in a queue
|
|
||||||
* and will be sent when possible. after it is sent the canResumeSending
|
|
||||||
* callback will be called.
|
|
||||||
* 1 - data was succesfully sent
|
|
||||||
*/
|
|
||||||
int WMSendConnectionData(WMConnection * cPtr, WMData * data)
|
|
||||||
{
|
|
||||||
int bytes, pos, len;
|
|
||||||
TimeoutData *tPtr = &cPtr->sendTimeout;
|
|
||||||
const unsigned char *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) {
|
|
||||||
WMAddToArray(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 (WMGetArrayItemCount(cPtr->outputQueue) > 1 && cPtr->handler.write)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (WMGetArrayItemCount(cPtr->outputQueue) > 0) {
|
|
||||||
data = WMGetFromArray(cPtr->outputQueue, 0);
|
|
||||||
dataBytes = (const unsigned char *)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 0;
|
|
||||||
default:
|
|
||||||
WCErrorCode = errno;
|
|
||||||
cPtr->state = WCDied;
|
|
||||||
removeAllHandlers(cPtr);
|
|
||||||
if (cPtr->delegate && cPtr->delegate->didDie)
|
|
||||||
(*cPtr->delegate->didDie) (cPtr->delegate, cPtr);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pos += bytes;
|
|
||||||
}
|
|
||||||
WMDeleteFromArray(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;
|
|
||||||
} */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cPtr->handler.write) {
|
|
||||||
WMDeleteInputHandler(cPtr->handler.write);
|
|
||||||
cPtr->handler.write = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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)
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
#if 1
|
|
||||||
int state;
|
|
||||||
|
|
||||||
state = fcntl(cPtr->sock, F_GETFL, 0);
|
|
||||||
|
|
||||||
if (state < 0) {
|
|
||||||
/* 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
|
|
||||||
|
|
||||||
Bool WMSetConnectionNonBlocking(WMConnection * cPtr, Bool flag)
|
|
||||||
{
|
|
||||||
wassertrv(cPtr != NULL && cPtr->sock >= 0, False);
|
|
||||||
|
|
||||||
flag = ((flag == 0) ? 0 : 1);
|
|
||||||
|
|
||||||
if (cPtr->isNonBlocking == flag)
|
|
||||||
return True;
|
|
||||||
|
|
||||||
if (setSocketNonBlocking(cPtr->sock, flag) == True) {
|
|
||||||
cPtr->isNonBlocking = flag;
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool WMSetConnectionCloseOnExec(WMConnection * cPtr, Bool flag)
|
|
||||||
{
|
|
||||||
wassertrv(cPtr != NULL && cPtr->sock >= 0, False);
|
|
||||||
|
|
||||||
if (fcntl(cPtr->sock, F_SETFD, ((flag == 0) ? 0 : FD_CLOEXEC)) < 0) {
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WMSetConnectionShutdownOnClose(WMConnection * cPtr, Bool flag)
|
|
||||||
{
|
|
||||||
cPtr->shutdownOnClose = ((flag == 0) ? 0 : 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *WMGetConnectionClientData(WMConnection * cPtr)
|
|
||||||
{
|
|
||||||
return cPtr->clientData;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WMSetConnectionClientData(WMConnection * cPtr, void *data)
|
|
||||||
{
|
|
||||||
cPtr->clientData = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int WMGetConnectionFlags(WMConnection * cPtr)
|
|
||||||
{
|
|
||||||
return cPtr->uflags;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WMSetConnectionFlags(WMConnection * cPtr, unsigned int flags)
|
|
||||||
{
|
|
||||||
cPtr->uflags = flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
WMArray *WMGetConnectionUnsentData(WMConnection * cPtr)
|
|
||||||
{
|
|
||||||
return cPtr->outputQueue;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WMSetConnectionDefaultTimeout(unsigned int timeout)
|
|
||||||
{
|
|
||||||
if (timeout == 0) {
|
|
||||||
DefaultTimeout = DEF_TIMEOUT;
|
|
||||||
} else {
|
|
||||||
DefaultTimeout = timeout;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WMSetConnectionOpenTimeout(unsigned int timeout)
|
|
||||||
{
|
|
||||||
if (timeout == 0) {
|
|
||||||
OpenTimeout = DefaultTimeout;
|
|
||||||
} else {
|
|
||||||
OpenTimeout = timeout;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WMSetConnectionSendTimeout(WMConnection * cPtr, unsigned int timeout)
|
|
||||||
{
|
|
||||||
if (timeout == 0) {
|
|
||||||
cPtr->sendTimeout.timeout = DefaultTimeout;
|
|
||||||
} else {
|
|
||||||
cPtr->sendTimeout.timeout = timeout;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
265
WINGs/host.c
265
WINGs/host.c
@@ -1,265 +0,0 @@
|
|||||||
/*
|
|
||||||
* WINGs WMHost function library
|
|
||||||
*
|
|
||||||
* Copyright (c) 1999-2003 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 "wconfig.h"
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <netdb.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
|
|
||||||
#include "WUtil.h"
|
|
||||||
|
|
||||||
/* For Solaris */
|
|
||||||
#ifndef INADDR_NONE
|
|
||||||
# define INADDR_NONE (-1)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Max hostname length (RFC 1123) */
|
|
||||||
#define W_MAXHOSTNAMELEN 255
|
|
||||||
|
|
||||||
typedef struct W_Host {
|
|
||||||
char *name;
|
|
||||||
|
|
||||||
WMArray *names;
|
|
||||||
WMArray *addresses;
|
|
||||||
|
|
||||||
int refCount;
|
|
||||||
} W_Host;
|
|
||||||
|
|
||||||
static WMHashTable *hostCache = NULL;
|
|
||||||
|
|
||||||
static Bool hostCacheEnabled = True;
|
|
||||||
|
|
||||||
static WMHost *getHostFromCache(char *name)
|
|
||||||
{
|
|
||||||
if (!hostCache)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return WMHashGet(hostCache, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static WMHost *getHostWithHostEntry(struct hostent *host, char *name)
|
|
||||||
{
|
|
||||||
WMHost *hPtr;
|
|
||||||
struct in_addr in;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
hPtr = (WMHost *) wmalloc(sizeof(WMHost));
|
|
||||||
memset(hPtr, 0, sizeof(WMHost));
|
|
||||||
|
|
||||||
hPtr->names = WMCreateArrayWithDestructor(1, wfree);
|
|
||||||
hPtr->addresses = WMCreateArrayWithDestructor(1, wfree);
|
|
||||||
|
|
||||||
WMAddToArray(hPtr->names, wstrdup(host->h_name));
|
|
||||||
|
|
||||||
for (i = 0; host->h_aliases[i] != NULL; i++) {
|
|
||||||
WMAddToArray(hPtr->names, wstrdup(host->h_aliases[i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
WMAddToArray(hPtr->addresses, wstrdup(inet_ntoa(in)));
|
|
||||||
}
|
|
||||||
|
|
||||||
hPtr->refCount = 1;
|
|
||||||
|
|
||||||
if (hostCacheEnabled) {
|
|
||||||
if (!hostCache)
|
|
||||||
hostCache = WMCreateHashTable(WMStringPointerHashCallbacks);
|
|
||||||
hPtr->name = wstrdup(name);
|
|
||||||
wassertr(WMHashInsert(hostCache, hPtr->name, hPtr) == NULL);
|
|
||||||
hPtr->refCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return hPtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
WMHost *hPtr;
|
|
||||||
|
|
||||||
wassertrv(name != NULL, NULL);
|
|
||||||
|
|
||||||
if (hostCacheEnabled) {
|
|
||||||
if ((hPtr = getHostFromCache(name)) != NULL) {
|
|
||||||
WMRetainHost(hPtr);
|
|
||||||
return hPtr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
host = gethostbyname(name);
|
|
||||||
if (host == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
hPtr = getHostWithHostEntry(host, name);
|
|
||||||
|
|
||||||
return hPtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
WMHost *WMGetHostWithAddress(char *address)
|
|
||||||
{
|
|
||||||
struct hostent *host;
|
|
||||||
struct in_addr in;
|
|
||||||
WMHost *hPtr;
|
|
||||||
|
|
||||||
wassertrv(address != NULL, NULL);
|
|
||||||
|
|
||||||
if (hostCacheEnabled) {
|
|
||||||
if ((hPtr = getHostFromCache(address)) != NULL) {
|
|
||||||
WMRetainHost(hPtr);
|
|
||||||
return hPtr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifndef HAVE_INET_ATON
|
|
||||||
if ((in.s_addr = inet_addr(address)) == INADDR_NONE)
|
|
||||||
return NULL;
|
|
||||||
#else
|
|
||||||
if (inet_aton(address, &in) == 0)
|
|
||||||
return NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
host = gethostbyaddr((char *)&in, sizeof(in), AF_INET);
|
|
||||||
if (host == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
hPtr = getHostWithHostEntry(host, address);
|
|
||||||
|
|
||||||
return hPtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
WMHost *WMRetainHost(WMHost * hPtr)
|
|
||||||
{
|
|
||||||
hPtr->refCount++;
|
|
||||||
return hPtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WMReleaseHost(WMHost * hPtr)
|
|
||||||
{
|
|
||||||
hPtr->refCount--;
|
|
||||||
|
|
||||||
if (hPtr->refCount > 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
WMFreeArray(hPtr->names);
|
|
||||||
WMFreeArray(hPtr->addresses);
|
|
||||||
|
|
||||||
if (hPtr->name) {
|
|
||||||
WMHashRemove(hostCache, hPtr->name);
|
|
||||||
wfree(hPtr->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
wfree(hPtr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WMSetHostCacheEnabled(Bool flag)
|
|
||||||
{
|
|
||||||
hostCacheEnabled = ((flag == 0) ? 0 : 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool WMIsHostCacheEnabled()
|
|
||||||
{
|
|
||||||
return hostCacheEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WMFlushHostCache()
|
|
||||||
{
|
|
||||||
if (hostCache && WMCountHashTable(hostCache) > 0) {
|
|
||||||
WMArray *hostArray = WMCreateArray(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. */
|
|
||||||
WMAddToArray(hostArray, hPtr);
|
|
||||||
}
|
|
||||||
for (i = 0; i < WMGetArrayItemCount(hostArray); i++)
|
|
||||||
WMReleaseHost(WMGetFromArray(hostArray, i));
|
|
||||||
WMFreeArray(hostArray);
|
|
||||||
WMResetHashTable(hostCache);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int matchAddress(const void *item, const void *cdata)
|
|
||||||
{
|
|
||||||
return (strcmp((char *)item, (char *)cdata) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool WMIsHostEqualToHost(WMHost * hPtr, WMHost * aPtr)
|
|
||||||
{
|
|
||||||
char *adr;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
wassertrv(hPtr != NULL && aPtr != NULL, False);
|
|
||||||
|
|
||||||
if (hPtr == aPtr)
|
|
||||||
return True;
|
|
||||||
|
|
||||||
for (i = 0; i < WMGetArrayItemCount(aPtr->addresses); i++) {
|
|
||||||
adr = WMGetFromArray(aPtr->addresses, i);
|
|
||||||
if (WMFindInArray(hPtr->addresses, matchAddress, adr) != WANotFound) {
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *WMGetHostName(WMHost * hPtr)
|
|
||||||
{
|
|
||||||
return (WMGetArrayItemCount(hPtr->names) > 0 ? WMGetFromArray(hPtr->names, 0) : NULL);
|
|
||||||
/*return WMGetFromArray(hPtr->names, 0); */
|
|
||||||
}
|
|
||||||
|
|
||||||
WMArray *WMGetHostNames(WMHost * hPtr)
|
|
||||||
{
|
|
||||||
return hPtr->names;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *WMGetHostAddress(WMHost * hPtr)
|
|
||||||
{
|
|
||||||
return (WMGetArrayItemCount(hPtr->addresses) > 0 ? WMGetFromArray(hPtr->addresses, 0) : NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
WMArray *WMGetHostAddresses(WMHost * hPtr)
|
|
||||||
{
|
|
||||||
return hPtr->addresses;
|
|
||||||
}
|
|
||||||
@@ -7,10 +7,8 @@ CLEANFILES = $(CATALOGS) WINGs.pot
|
|||||||
EXTRA_DIST = bg.po ca.po cs.po de.po fr.po sk.po
|
EXTRA_DIST = bg.po ca.po cs.po de.po fr.po sk.po
|
||||||
|
|
||||||
POTFILES = \
|
POTFILES = \
|
||||||
$(top_builddir)/WINGs/connection.c \
|
|
||||||
$(top_builddir)/WINGs/error.c \
|
$(top_builddir)/WINGs/error.c \
|
||||||
$(top_builddir)/WINGs/findfile.c \
|
$(top_builddir)/WINGs/findfile.c \
|
||||||
$(top_builddir)/WINGs/host.c \
|
|
||||||
$(top_builddir)/WINGs/proplist.c \
|
$(top_builddir)/WINGs/proplist.c \
|
||||||
$(top_builddir)/WINGs/userdefaults.c \
|
$(top_builddir)/WINGs/userdefaults.c \
|
||||||
$(top_builddir)/WINGs/wcolor.c \
|
$(top_builddir)/WINGs/wcolor.c \
|
||||||
|
|||||||
28
configure.ac
28
configure.ac
@@ -420,28 +420,6 @@ AC_ARG_ENABLE(verbose-compile, AS_HELP_STRING([--disable-verbose-compile],
|
|||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
dnl
|
|
||||||
dnl Networking stuff
|
|
||||||
dnl
|
|
||||||
|
|
||||||
NETLIBS=""
|
|
||||||
|
|
||||||
AC_CHECK_FUNC(connect,,
|
|
||||||
AC_CHECK_LIB(socket, connect, NETLIBS="$NETLIBS -lsocket"))
|
|
||||||
|
|
||||||
AC_CHECK_FUNC(gethostbyname,,
|
|
||||||
AC_CHECK_LIB(nsl, gethostbyname, NETLIBS="$NETLIBS -lnsl"))
|
|
||||||
|
|
||||||
AC_CHECK_FUNC(inet_aton, AC_DEFINE(HAVE_INET_ATON, 1, [define if you have then inet_aton function (set by configure)]),
|
|
||||||
for lib in resolv socket inet bsd; do
|
|
||||||
AC_CHECK_LIB($lib, inet_aton, [AC_DEFINE(HAVE_INET_ATON)
|
|
||||||
NETLIBS="$NETLIBS -l$lib"; break],, $NETLIBS)
|
|
||||||
done)
|
|
||||||
|
|
||||||
AC_SUBST(NETLIBS)
|
|
||||||
|
|
||||||
|
|
||||||
dnl ===========================================
|
dnl ===========================================
|
||||||
dnl Stuff that uses X
|
dnl Stuff that uses X
|
||||||
dnl ===========================================
|
dnl ===========================================
|
||||||
@@ -977,7 +955,7 @@ cat <<EOF >get-wings-flags
|
|||||||
|
|
||||||
WCFLAGS="$inc_search_path"
|
WCFLAGS="$inc_search_path"
|
||||||
WLFLAGS="$lib_search_path"
|
WLFLAGS="$lib_search_path"
|
||||||
WLIBS="-lWINGs -lWUtil -lwraster $GFXLIBS $XFTLIBS $XLIBS -lm $NETLIBS $INTLIBS"
|
WLIBS="-lWINGs -lWUtil -lwraster $GFXLIBS $XFTLIBS $XLIBS -lm $INTLIBS"
|
||||||
|
|
||||||
usage="Usage: get-wings-flags #lp#--cflags#rp# #lp#--ldflags#rp# #lp#--libs#rp#"
|
usage="Usage: get-wings-flags #lp#--cflags#rp# #lp#--ldflags#rp# #lp#--libs#rp#"
|
||||||
|
|
||||||
@@ -1013,7 +991,7 @@ Name: WINGs
|
|||||||
Description: Small widget set with the NeXTStep(TM) look and feel
|
Description: Small widget set with the NeXTStep(TM) look and feel
|
||||||
Version: $VERSION
|
Version: $VERSION
|
||||||
Requires: wrlib
|
Requires: wrlib
|
||||||
Libs: $lib_search_path -lWINGs $XFTLIBS $XLIBS -lm $NETLIBS $INTLIBS
|
Libs: $lib_search_path -lWINGs $XFTLIBS $XLIBS -lm $INTLIBS
|
||||||
Cflags: $inc_search_path
|
Cflags: $inc_search_path
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
@@ -1022,7 +1000,7 @@ cat <<EOF >get-wutil-flags
|
|||||||
|
|
||||||
WCFLAGS="-I`eval echo ${includedir}`"
|
WCFLAGS="-I`eval echo ${includedir}`"
|
||||||
WLFLAGS="-L${_libdir}"
|
WLFLAGS="-L${_libdir}"
|
||||||
WLIBS="-lWUtil $NETLIBS $INTLIBS"
|
WLIBS="-lWUtil $INTLIBS"
|
||||||
|
|
||||||
usage="Usage: get-wutil-flags #lp#--cflags#rp# #lp#--ldflags#rp# #lp#--libs#rp#"
|
usage="Usage: get-wutil-flags #lp#--cflags#rp# #lp#--ldflags#rp# #lp#--libs#rp#"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user