diff --git a/WINGs/ChangeLog b/WINGs/ChangeLog index d6ef10c8..a08f7f51 100644 --- a/WINGs/ChangeLog +++ b/WINGs/ChangeLog @@ -8,7 +8,8 @@ changes since wmaker 0.63.1: Also updated get-{wings|wutil}-flags. - Fixed a mem leak in WMList. - Fixed a bug that caused sigsegv for a WMList with more than 32767 items. - +- Added an example of how to create a server type program with WMConnection. + changes since wmaker 0.62.1: ............................ diff --git a/WINGs/Examples/.cvsignore b/WINGs/Examples/.cvsignore index 6953780c..6358b0e3 100644 --- a/WINGs/Examples/.cvsignore +++ b/WINGs/Examples/.cvsignore @@ -1,5 +1,5 @@ Makefile Makefile.in -connect fontl puzzle +connect server fontl puzzle UserTime.plist .libs .psrc .inslog2 tca.map tca.log *.rpt diff --git a/WINGs/Examples/Makefile.am b/WINGs/Examples/Makefile.am index 3bd064f8..c19de96b 100644 --- a/WINGs/Examples/Makefile.am +++ b/WINGs/Examples/Makefile.am @@ -3,7 +3,7 @@ AUTOMAKE_OPTIONS = no-dependencies -noinst_PROGRAMS = connect fontl puzzle +noinst_PROGRAMS = connect server fontl puzzle LDADD= $(top_builddir)/WINGs/libWINGs.a $(top_builddir)/wrlib/libwraster.la \ @@ -19,6 +19,11 @@ connect_DEPENDENCIES = $(top_builddir)/WINGs/libWUtil.a connect_LDADD = $(top_builddir)/WINGs/libWUtil.a @LIBRARY_SEARCH_PATH@ \ @NETLIBS@ @LIBPL@ +server_DEPENDENCIES = $(top_builddir)/WINGs/libWUtil.a + +server_LDADD = $(top_builddir)/WINGs/libWUtil.a @LIBRARY_SEARCH_PATH@ \ + @NETLIBS@ @LIBPL@ + INCLUDES = -I$(top_srcdir)/WINGs -I$(top_srcdir)/wrlib -I$(top_srcdir)/src \ -DRESOURCE_PATH=\"$(datadir)/WINGs\" @HEADER_SEARCH_PATH@ -DDEBUG diff --git a/WINGs/Examples/README b/WINGs/Examples/README new file mode 100644 index 00000000..ab8aa3fe --- /dev/null +++ b/WINGs/Examples/README @@ -0,0 +1,19 @@ + + +Files: +----- + +server - server example of using WMConnection. It keeps a database of + timeouts for a group of users, allowing one to add/remove + users and update the timeouts associated with them. + +connect - client example of using WMConnection. Works with the server + program above. Just start both without any parameter and + type help in the client to find out how to operate them. + Rest is self explanatory. + +puzzle - a nice zuPzel =) + +fontl - a map of all characters with their corresponding ascii, + hex, decimal and octal representations. + diff --git a/WINGs/Examples/connect.c b/WINGs/Examples/connect.c index 9317273a..6a0063e1 100644 --- a/WINGs/Examples/connect.c +++ b/WINGs/Examples/connect.c @@ -1,21 +1,8 @@ /* * WINGs connect.c: example how to create a network client using WMConnection * - * Copyright (c) 1999 Dan Pascu + * Copyright (c) 1999-2001 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. */ @@ -168,7 +155,7 @@ main(int argc, char **argv) /*FOLD00*/ ProgName++; host = NULL; - port = "7000"; + port = "34567"; if (argc>1) { for (i=1; i +#include +#include + +#include + + +#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, /* didCatchException */ + connectionDidDie, /* didDie */ + NULL, /* didInitialize */ + didReceiveInput, /* didReceiveInput */ + connectionDidTimeout /* didTimeout */ +}; + + + +void +wAbort(Bool foo) /*FOLD00*/ +{ + exit(1); +} + + +static void +printHelp(char *progname) /*FOLD00*/ +{ + 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 unsigned char* +findDelimiter(unsigned char *data, unsigned const char *endPtr) +{ + wassertrv(data < endPtr, NULL); + + while (data 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 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) /*FOLD00*/ +{ + 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) /*FOLD00*/ +{ + 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) /*FOLD00*/ +{ + char *buf = wmalloc(strlen(WMGetApplicationName()) + 16); + + sprintf(buf, _("%s commands:\n\n"), WMGetApplicationName()); + + enqueueMessage(cPtr, _("\n")); + enqueueMessage(cPtr, buf); + enqueueMessage(cPtr, _("GET \t- return time left (in minutes) " + "for user with id \n")); + enqueueMessage(cPtr, _("SET