/* * WINGs server.c: example how to create a network server using WMConnection * * Copyright (c) 2001-2003 Dan Pascu * */ #include #include #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, /* 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 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) { 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 \t- return time left (in minutes) " "for user with id \n")); enqueueMessage(cPtr, _("SET