Change to the linux kernel coding style
[wmaker-crm.git] / WINGs / Examples / server.c
Commit [+]AuthorDateLineData
a1fb870f dan2001-02-09 03:12:16 +00001/*
2 * WINGs server.c: example how to create a network server using WMConnection
3 *
4153e2fd dan2003-01-16 23:30:45 +00004 * Copyright (c) 2001-2003 Dan Pascu
a1fb870f dan2001-02-09 03:12:16 +00005 *
6 */
7
a1fb870f dan2001-02-09 03:12:16 +00008#include <stdio.h>
c2ec1cfe dan2002-11-13 15:13:48 +00009#include <stdlib.h>
a1fb870f dan2001-02-09 03:12:16 +000010#include <unistd.h>
11#include <string.h>
12
13#include <WINGs/WINGs.h>
14
a1fb870f dan2001-02-09 03:12:16 +000015#define _(P) P
16#define MAXCMD_SIZE 512
17
a1fb870f dan2001-02-09 03:12:16 +000018char *SEConnectionShouldBeRemovedNotification = "SEConnectionShouldBeRemovedNotification";
19
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020020static void didReceiveInput(ConnectionDelegate * self, WMConnection * cPtr);
a1fb870f dan2001-02-09 03:12:16 +000021
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020022static void connectionDidDie(ConnectionDelegate * self, WMConnection * cPtr);
a1fb870f dan2001-02-09 03:12:16 +000023
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020024static void connectionDidTimeout(ConnectionDelegate * self, WMConnection * cPtr);
a1fb870f dan2001-02-09 03:12:16 +000025
26extern char *SEConnectionShouldBeRemovedNotification;
27
28static WMUserDefaults *timeDB = NULL;
29static char *ServerAddress = NULL;
30static char *ServerPort = NULL;
31static WMArray *allowedHostList = NULL;
32static WMArray *clientConnections = NULL;
33static WMConnection *serverPtr = NULL;
34
a1fb870f dan2001-02-09 03:12:16 +000035static ConnectionDelegate socketDelegate = {
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020036 NULL, /* client data */
37 NULL, /* canResumeSending */
38 NULL, /* didCatchException */
39 connectionDidDie, /* didDie */
40 NULL, /* didInitialize */
41 didReceiveInput, /* didReceiveInput */
42 connectionDidTimeout /* didTimeout */
a1fb870f dan2001-02-09 03:12:16 +000043};
44
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020045void wAbort(Bool foo)
a1fb870f dan2001-02-09 03:12:16 +000046{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020047 exit(1);
a1fb870f dan2001-02-09 03:12:16 +000048}
49
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020050static void printHelp(char *progname)
a1fb870f dan2001-02-09 03:12:16 +000051{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020052 printf(_("usage: %s [options]\n\n"), progname);
53 puts(_(" --help print this message"));
54 puts(_(" --listen [address:]port only listen on the specified address/port"));
55 puts(_(" --allow host1[,host2...] only allow connections from listed hosts\n"));
56 puts(_(" By default server listens on all interfaces and port 34567, unless"
57 " something\nelse is specified with the --listen option. If address is"
58 " omitted or the keyword\n'Any' is used, it will listen on all interfaces else"
59 " only on the specified one.\n\nFor example --listen localhost: will"
60 " listen on the default port 34567, but only\non connections comming"
61 " in through the loopback interface.\n\n Also by default the server"
62 " listens to incoming connections from any host,\nunless a list of"
63 " hosts is given with the --allow option, in which case it will\nreject"
64 " connections not comming from those hosts.\nThe list of hosts is comma"
65 " separated and should NOT contain ANY spaces."));
a1fb870f dan2001-02-09 03:12:16 +000066}
67
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020068static void enqueueConnectionForRemoval(WMConnection * cPtr)
a1fb870f dan2001-02-09 03:12:16 +000069{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020070 WMNotification *notif;
a1fb870f dan2001-02-09 03:12:16 +000071
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020072 /*don't release notif here. it will be released by queue after processing */
73 notif = WMCreateNotification(SEConnectionShouldBeRemovedNotification, cPtr, NULL);
74 WMEnqueueNotification(WMGetDefaultNotificationQueue(), notif, WMPostASAP);
a1fb870f dan2001-02-09 03:12:16 +000075}
76
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020077static int sendMessage(WMConnection * cPtr, char *message)
a1fb870f dan2001-02-09 03:12:16 +000078{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020079 WMData *aData;
80 int res;
a1fb870f dan2001-02-09 03:12:16 +000081
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020082 if (WMGetConnectionState(cPtr) != WCConnected)
83 return -1;
a1fb870f dan2001-02-09 03:12:16 +000084
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020085 aData = WMCreateDataWithBytes(message, strlen(message));
86 res = WMSendConnectionData(cPtr, aData);
87 WMReleaseData(aData);
a1fb870f dan2001-02-09 03:12:16 +000088
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020089 return res;
a1fb870f dan2001-02-09 03:12:16 +000090}
91
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020092static Bool enqueueMessage(WMConnection * cPtr, char *message)
a1fb870f dan2001-02-09 03:12:16 +000093{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020094 WMData *aData;
95 Bool res;
a1fb870f dan2001-02-09 03:12:16 +000096
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020097 if (WMGetConnectionState(cPtr) != WCConnected)
98 return False;
a1fb870f dan2001-02-09 03:12:16 +000099
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200100 aData = WMCreateDataWithBytes(message, strlen(message));
101 res = WMEnqueueConnectionData(cPtr, aData);
102 WMReleaseData(aData);
a1fb870f dan2001-02-09 03:12:16 +0000103
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200104 return res;
a1fb870f dan2001-02-09 03:12:16 +0000105}
106
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200107static char *findDelimiter(char *data, const char *endPtr)
a1fb870f dan2001-02-09 03:12:16 +0000108{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200109 wassertrv(data < endPtr, NULL);
a1fb870f dan2001-02-09 03:12:16 +0000110
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200111 while (data < endPtr && *data != '\n' && *data != '\r' && *data != ';' && *data != '\0')
112 data++;
a1fb870f dan2001-02-09 03:12:16 +0000113
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200114 if (data < endPtr)
115 return data;
a1fb870f dan2001-02-09 03:12:16 +0000116
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200117 return NULL;
a1fb870f dan2001-02-09 03:12:16 +0000118}
119
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200120static WMArray *getAvailableMessages(WMConnection * cPtr)
a1fb870f dan2001-02-09 03:12:16 +0000121{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200122 char *ptr, *crtPos, *buffer;
123 const char *bytes, *endPtr;
124 WMData *aData, *receivedData, *holdData;
125 WMRange range;
126 WMArray *messages;
127 int length;
128
129 receivedData = WMGetConnectionAvailableData(cPtr);
130 if (!receivedData)
131 return NULL;
132 if ((length = WMGetDataLength(receivedData)) == 0) {
133 WMReleaseData(receivedData);
134 return NULL;
135 }
136
137 holdData = (WMData *) WMGetConnectionClientData(cPtr);
138 if (holdData) {
139 WMAppendData(holdData, receivedData);
140 WMReleaseData(receivedData);
141 WMSetConnectionClientData(cPtr, NULL);
142 aData = holdData;
143 } else {
144 aData = receivedData;
145 }
146
147 length = WMGetDataLength(aData);
148 bytes = (char *)WMDataBytes(aData);
149 endPtr = bytes + length;
150
151 messages = WMCreateArrayWithDestructor(1, wfree);
152 crtPos = (char *)bytes;
153 while (crtPos < endPtr && (ptr = findDelimiter(crtPos, endPtr)) != NULL) {
154 range.position = (crtPos - bytes);
155 range.count = (ptr - crtPos);
156 if (range.count > MAXCMD_SIZE) {
157 /* Hmmm... The message is too long. Possibly that someone is
158 * flooding us, or there is a dumb client which do not know
159 * who is talking to. */
160 sendMessage(cPtr, "Command too long\n\r");
161 WMFreeArray(messages);
162 WMReleaseData(aData);
163 WMCloseConnection(cPtr);
164 enqueueConnectionForRemoval(cPtr);
165 return NULL;
166 }
167 buffer = wmalloc(range.count + 1);
168 WMGetDataBytesWithRange(aData, buffer, range);
169 buffer[range.count] = '\0';
170 WMAddToArray(messages, buffer);
171 crtPos = ptr;
172 while (crtPos < endPtr && (*crtPos == '\n' || *crtPos == '\r' ||
173 *crtPos == '\t' || *crtPos == '\0' ||
174 *crtPos == ';' || *crtPos == ' ')) {
175 crtPos++;
176 }
177 }
178
179 if (crtPos < endPtr) {
180 range.position = (crtPos - bytes);
181 range.count = (endPtr - crtPos);
182 if (range.count > MAXCMD_SIZE) {
183 /* Flooooooding!!!! */
184 sendMessage(cPtr, "Message too long\n\r");
185 WMFreeArray(messages);
186 WMReleaseData(aData);
187 WMCloseConnection(cPtr);
188 enqueueConnectionForRemoval(cPtr);
189 return NULL;
190 }
191 holdData = WMGetSubdataWithRange(aData, range);
192 WMSetConnectionClientData(cPtr, holdData);
193 }
194 WMReleaseData(aData);
195
196 if (WMGetArrayItemCount(messages) == 0) {
197 WMFreeArray(messages);
198 messages = NULL;
199 }
200 return messages;
a1fb870f dan2001-02-09 03:12:16 +0000201}
202
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200203static void complainAboutBadArgs(WMConnection * cPtr, char *cmdName, char *badArgs)
a1fb870f dan2001-02-09 03:12:16 +0000204{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200205 char *buf = wmalloc(strlen(cmdName) + strlen(badArgs) + 100);
a1fb870f dan2001-02-09 03:12:16 +0000206
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200207 sprintf(buf, _("Invalid parameters '%s' for command %s. Use HELP for"
208 " a list of commands.\n"), badArgs, cmdName);
209 sendMessage(cPtr, buf);
210 wfree(buf);
a1fb870f dan2001-02-09 03:12:16 +0000211}
212
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200213static void sendUpdateMessage(WMConnection * cPtr, char *id, int time)
a1fb870f dan2001-02-09 03:12:16 +0000214{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200215 char *buf = wmalloc(strlen(id) + 100);
a1fb870f dan2001-02-09 03:12:16 +0000216
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200217 sprintf(buf, "%s has %i minutes left\n", id, time);
218 sendMessage(cPtr, buf);
219 wfree(buf);
a1fb870f dan2001-02-09 03:12:16 +0000220}
221
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200222static void showId(WMConnection * cPtr)
a1fb870f dan2001-02-09 03:12:16 +0000223{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200224 sendMessage(cPtr, "Server example based on WMConnection\n");
a1fb870f dan2001-02-09 03:12:16 +0000225}
226
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200227static void showHelp(WMConnection * cPtr)
a1fb870f dan2001-02-09 03:12:16 +0000228{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200229 char *buf = wmalloc(strlen(WMGetApplicationName()) + 16);
230
231 sprintf(buf, _("%s commands:\n\n"), WMGetApplicationName());
232
233 enqueueMessage(cPtr, _("\n"));
234 enqueueMessage(cPtr, buf);
235 enqueueMessage(cPtr, _("GET <id>\t- return time left (in minutes) " "for user with id <id>\n"));
236 enqueueMessage(cPtr, _("SET <id> <time>\t- set time limit to <time> " "minutes for user with id <id>\n"));
237 enqueueMessage(cPtr, _("ADD <id> <time>\t- add <time> minutes " "for user with id <id>\n"));
238 enqueueMessage(cPtr, _("SUB <id> <time>\t- subtract <time> minutes " "for user with id <id>\n"));
239 enqueueMessage(cPtr, _("REMOVE <id>\t- remove time limitations for " "user with id <id>\n"));
240 enqueueMessage(cPtr, _("LIST\t\t- list all users and their " "corresponding time limit\n"));
241 enqueueMessage(cPtr, _("ID\t\t- returns the Time Manager " "identification string\n"));
242 enqueueMessage(cPtr, _("EXIT\t\t- exits session\n"));
243 enqueueMessage(cPtr, _("QUIT\t\t- exits session\n"));
244 enqueueMessage(cPtr, _("HELP\t\t- show this message\n\n"));
245 /* Just flush the queue we made before */
246 WMFlushConnection(cPtr);
247 wfree(buf);
a1fb870f dan2001-02-09 03:12:16 +0000248}
249
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200250static void listUsers(WMConnection * cPtr)
a1fb870f dan2001-02-09 03:12:16 +0000251{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200252 WMPropList *userList;
253 char *id;
254 int i, time;
a1fb870f dan2001-02-09 03:12:16 +0000255
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200256 userList = WMGetUDKeys(timeDB);
a1fb870f dan2001-02-09 03:12:16 +0000257
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200258 for (i = 0; i < WMGetPropListItemCount(userList); i++) {
259 id = WMGetFromPLString(WMGetFromPLArray(userList, i));
260 time = WMGetUDIntegerForKey(timeDB, id);
261 sendUpdateMessage(cPtr, id, time);
262 }
a1fb870f dan2001-02-09 03:12:16 +0000263
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200264 WMReleasePropList(userList);
a1fb870f dan2001-02-09 03:12:16 +0000265}
266
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200267static void setTimeForUser(WMConnection * cPtr, char *cmdArgs)
a1fb870f dan2001-02-09 03:12:16 +0000268{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200269 char *id;
270 int i, time;
271
272 id = wmalloc(strlen(cmdArgs));
273 if (sscanf(cmdArgs, "%s %d", id, &time) != 2) {
274 complainAboutBadArgs(cPtr, "SET", cmdArgs);
275 wfree(id);
276 return;
277 }
278 if (time < 0)
279 time = 0;
280
281 WMSetUDIntegerForKey(timeDB, time, id);
282
283 for (i = 0; i < WMGetArrayItemCount(clientConnections); i++) {
284 cPtr = WMGetFromArray(clientConnections, i);
285 sendUpdateMessage(cPtr, id, time);
286 }
287 wfree(id);
a1fb870f dan2001-02-09 03:12:16 +0000288}
289
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200290static void addTimeToUser(WMConnection * cPtr, char *cmdArgs)
a1fb870f dan2001-02-09 03:12:16 +0000291{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200292 char *id;
293 int i, time, newTime;
294
295 id = wmalloc(strlen(cmdArgs));
296 if (sscanf(cmdArgs, "%s %d", id, &time) != 2) {
297 complainAboutBadArgs(cPtr, "ADD", cmdArgs);
298 wfree(id);
299 return;
300 }
301
302 newTime = WMGetUDIntegerForKey(timeDB, id) + time;
303 if (newTime < 0)
304 newTime = 0;
305
306 WMSetUDIntegerForKey(timeDB, newTime, id);
307
308 for (i = 0; i < WMGetArrayItemCount(clientConnections); i++) {
309 cPtr = WMGetFromArray(clientConnections, i);
310 sendUpdateMessage(cPtr, id, newTime);
311 }
312 wfree(id);
a1fb870f dan2001-02-09 03:12:16 +0000313}
314
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200315static void subTimeFromUser(WMConnection * cPtr, char *cmdArgs)
a1fb870f dan2001-02-09 03:12:16 +0000316{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200317 char *id;
318 int i, time, newTime;
319
320 id = wmalloc(strlen(cmdArgs));
321 if (sscanf(cmdArgs, "%s %d", id, &time) != 2) {
322 complainAboutBadArgs(cPtr, "SUB", cmdArgs);
323 wfree(id);
324 return;
325 }
326
327 newTime = WMGetUDIntegerForKey(timeDB, id) - time;
328 if (newTime < 0)
329 newTime = 0;
330
331 WMSetUDIntegerForKey(timeDB, newTime, id);
332
333 for (i = 0; i < WMGetArrayItemCount(clientConnections); i++) {
334 cPtr = WMGetFromArray(clientConnections, i);
335 sendUpdateMessage(cPtr, id, newTime);
336 }
337 wfree(id);
a1fb870f dan2001-02-09 03:12:16 +0000338}
339
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200340static void removeTimeForUser(WMConnection * cPtr, char *cmdArgs)
a1fb870f dan2001-02-09 03:12:16 +0000341{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200342 char *ptr;
343 int i;
344
345 if (cmdArgs[0] == '\0') {
346 sendMessage(cPtr, _("Missing parameter for command REMOVE."
347 " Use HELP for a list of commands.\n"));
348 return;
349 }
350
351 ptr = cmdArgs;
352 while (*ptr && *ptr != ' ' && *ptr != '\t')
353 ptr++;
354 *ptr = '\0';
355
356 WMRemoveUDObjectForKey(timeDB, cmdArgs);
357
358 for (i = 0; i < WMGetArrayItemCount(clientConnections); i++) {
359 cPtr = WMGetFromArray(clientConnections, i);
360 sendUpdateMessage(cPtr, cmdArgs, -1);
361 }
a1fb870f dan2001-02-09 03:12:16 +0000362}
363
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200364static void getTimeForUser(WMConnection * cPtr, char *cmdArgs)
a1fb870f dan2001-02-09 03:12:16 +0000365{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200366 char *ptr;
367 int time;
a1fb870f dan2001-02-09 03:12:16 +0000368
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200369 if (cmdArgs[0] == '\0') {
370 sendMessage(cPtr, _("Missing parameter for command GET." " Use HELP for a list of commands.\n"));
371 return;
372 }
a1fb870f dan2001-02-09 03:12:16 +0000373
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200374 ptr = cmdArgs;
375 while (*ptr && *ptr != ' ' && *ptr != '\t')
376 ptr++;
377 *ptr = '\0';
378
379 if (WMGetUDObjectForKey(timeDB, cmdArgs) != NULL)
380 time = WMGetUDIntegerForKey(timeDB, cmdArgs);
381 else
382 time = -1;
383
384 sendUpdateMessage(cPtr, cmdArgs, time);
a1fb870f dan2001-02-09 03:12:16 +0000385}
386
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200387static void handleConnection(WMConnection * cPtr)
388{
389 char *command, *ptr, *cmdArgs, *buffer;
390 WMArray *commands;
391 int i;
392
393 commands = getAvailableMessages(cPtr);
394 if (!commands)
395 return;
396
397 for (i = 0; i < WMGetArrayItemCount(commands); i++) {
398 command = WMGetFromArray(commands, i);
399 while (*command && (*command == ' ' || *command == '\t'))
400 command++;
401 ptr = command;
402 while (*ptr && *ptr != ' ' && *ptr != '\t')
403 ptr++;
404 if (*ptr) {
405 *ptr = '\0';
406 ptr++;
407 }
408 while (*ptr && (*ptr == ' ' || *ptr == '\t'))
409 ptr++;
410
411 cmdArgs = ptr;
412
413 fprintf(stderr, "Command: '%s', args: '%s'\n", command, cmdArgs);
414
415 if (strcasecmp(command, "quit") == 0 || strcasecmp(command, "exit") == 0) {
416 sendMessage(cPtr, "Bye\n");
417 WMCloseConnection(cPtr);
418 enqueueConnectionForRemoval(cPtr);
419 WMFreeArray(commands);
420 return;
421 } else if (strcasecmp(command, "id") == 0) {
422 showId(cPtr);
423 } else if (strcasecmp(command, "help") == 0) {
424 showHelp(cPtr);
425 } else if (strcasecmp(command, "list") == 0) {
426 listUsers(cPtr);
427 } else if (strcasecmp(command, "set") == 0) {
428 setTimeForUser(cPtr, cmdArgs);
429 } else if (strcasecmp(command, "add") == 0) {
430 addTimeToUser(cPtr, cmdArgs);
431 } else if (strcasecmp(command, "sub") == 0) {
432 subTimeFromUser(cPtr, cmdArgs);
433 } else if (strcasecmp(command, "remove") == 0) {
434 removeTimeForUser(cPtr, cmdArgs);
435 } else if (strcasecmp(command, "get") == 0) {
436 getTimeForUser(cPtr, cmdArgs);
437 } else {
438 buffer = wmalloc(strlen(command) + 100);
439 sprintf(buffer, _("Unknown command '%s'. Try HELP for" " a list of commands.\n"), command);
440 sendMessage(cPtr, buffer);
441 wfree(buffer);
442 }
443 }
444
445 WMFreeArray(commands);
446}
a1fb870f dan2001-02-09 03:12:16 +0000447
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200448static Bool isAllowedToConnect(WMConnection * cPtr)
a1fb870f dan2001-02-09 03:12:16 +0000449{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200450 WMHost *hPtr;
451 int i;
a1fb870f dan2001-02-09 03:12:16 +0000452
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200453 if (allowedHostList == NULL)
454 return True; /* No list. Allow all by default */
a1fb870f dan2001-02-09 03:12:16 +0000455
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200456 hPtr = WMGetHostWithAddress(WMGetConnectionAddress(cPtr));
457 for (i = 0; i < WMGetArrayItemCount(allowedHostList); i++) {
458 if (WMIsHostEqualToHost(hPtr, WMGetFromArray(allowedHostList, i))) {
459 WMReleaseHost(hPtr);
460 return True;
461 }
462 }
a1fb870f dan2001-02-09 03:12:16 +0000463
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200464 WMReleaseHost(hPtr);
a1fb870f dan2001-02-09 03:12:16 +0000465
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200466 return False;
a1fb870f dan2001-02-09 03:12:16 +0000467}
468
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200469static void didReceiveInput(ConnectionDelegate * self, WMConnection * cPtr)
a1fb870f dan2001-02-09 03:12:16 +0000470{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200471 if (cPtr == serverPtr) {
472 WMConnection *newPtr = WMAcceptConnection(cPtr);
473
474 if (newPtr) {
475 if (isAllowedToConnect(newPtr)) {
476 WMSetConnectionDelegate(newPtr, &socketDelegate);
477 WMSetConnectionSendTimeout(newPtr, 120);
478 WMAddToArray(clientConnections, newPtr);
479 } else {
480 sendMessage(newPtr, "Sorry, you are not allowed to connect.\n");
481 WMDestroyConnection(newPtr);
482 }
483 }
484 } else {
485 /* Data arriving on an already-connected socket */
486 handleConnection(cPtr);
487 }
a1fb870f dan2001-02-09 03:12:16 +0000488}
489
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200490static void connectionDidTimeout(ConnectionDelegate * self, WMConnection * cPtr)
a1fb870f dan2001-02-09 03:12:16 +0000491{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200492 WMHost *hPtr;
a1fb870f dan2001-02-09 03:12:16 +0000493
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200494 if (cPtr == serverPtr) {
495 wfatal(_("The server listening socket did timeout. Exiting."));
496 exit(1);
497 }
a1fb870f dan2001-02-09 03:12:16 +0000498
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200499 hPtr = WMGetHostWithAddress(WMGetConnectionAddress(cPtr));
500 wwarning(_("Connection with %s did timeout. Closing connection."), WMGetHostName(hPtr));
501 WMReleaseHost(hPtr);
a1fb870f dan2001-02-09 03:12:16 +0000502
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200503 enqueueConnectionForRemoval(cPtr);
a1fb870f dan2001-02-09 03:12:16 +0000504}
505
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200506static void connectionDidDie(ConnectionDelegate * self, WMConnection * cPtr)
a1fb870f dan2001-02-09 03:12:16 +0000507{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200508 if (cPtr == serverPtr) {
509 /* trouble. server listening port itself died!!! */
510 wfatal(_("The server listening socket died. Exiting."));
511 exit(1);
512 }
a1fb870f dan2001-02-09 03:12:16 +0000513
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200514 enqueueConnectionForRemoval(cPtr);
a1fb870f dan2001-02-09 03:12:16 +0000515}
516
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200517static void removeConnection(void *observer, WMNotification * notification)
a1fb870f dan2001-02-09 03:12:16 +0000518{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200519 WMConnection *cPtr = (WMConnection *) WMGetNotificationObject(notification);
520 WMData *data;
a1fb870f dan2001-02-09 03:12:16 +0000521
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200522 WMRemoveFromArray(clientConnections, cPtr);
523 if ((data = (WMData *) WMGetConnectionClientData(cPtr)) != NULL)
524 WMReleaseData(data);
525 WMDestroyConnection(cPtr);
a1fb870f dan2001-02-09 03:12:16 +0000526}
527
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200528static void updatedDomain(void *observer, WMNotification * notification)
33cc542e dan2001-10-04 03:07:34 +0000529{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200530 wmessage("defaults domain file changed on disk. synchronizing.");
33cc542e dan2001-10-04 03:07:34 +0000531}
532
648d75c2 dan2001-04-19 01:04:48 +0000533#if 0
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200534static Bool isDifferent(char *str1, char *str2)
a1fb870f dan2001-02-09 03:12:16 +0000535{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200536 if ((!str1 && !str2) || (str1 && str2 && strcmp(str1, str2) == 0))
537 return False;
a1fb870f dan2001-02-09 03:12:16 +0000538
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200539 return True;
a1fb870f dan2001-02-09 03:12:16 +0000540}
648d75c2 dan2001-04-19 01:04:48 +0000541#endif
a1fb870f dan2001-02-09 03:12:16 +0000542
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200543int main(int argc, char **argv)
a1fb870f dan2001-02-09 03:12:16 +0000544{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200545 int i;
546
547 wsetabort(wAbort);
548
549 WMInitializeApplication("server", &argc, argv);
550
551 if (argc > 1) {
552 for (i = 1; i < argc; i++) {
553 if (strcmp(argv[i], "--help") == 0) {
554 printHelp(argv[0]);
555 exit(0);
556 } else if (strcmp(argv[i], "--listen") == 0) {
557 char *p;
558
559 if ((p = strchr(argv[++i], ':')) != NULL) {
560 *p = 0;
561 ServerAddress = wstrdup(argv[i]);
562 ServerPort = wstrdup(p + 1);
563 *p = ':';
564 if (ServerAddress[0] == 0) {
565 wfree(ServerAddress);
566 ServerAddress = NULL;
567 }
568 if (ServerPort[0] == 0) {
569 wfree(ServerPort);
570 ServerPort = "34567";
571 }
572 } else if (argv[i][0] != 0) {
573 ServerPort = argv[i];
574 }
575 } else if (strcmp(argv[i], "--allow") == 0) {
576 char *p, *ptr;
577 int done;
578 WMHost *hPtr;
579
580 ptr = argv[++i];
581 done = 0;
582 while (!done) {
583 if ((p = strchr(ptr, ',')) != NULL) {
584 *p = 0;
585 }
586 if (*ptr != 0) {
587 hPtr = WMGetHostWithName(ptr);
588 if (hPtr) {
589 if (!allowedHostList)
590 allowedHostList = WMCreateArray(4);
591 WMAddToArray(allowedHostList, hPtr);
592 } else {
593 wwarning(_("Unknown host '%s'. Ignored."), ptr);
594 }
595 }
596
597 if (p != NULL) {
598 *p = ',';
599 ptr = p + 1;
600 } else {
601 done = 1;
602 }
603 }
604 } else {
605 printf(_("%s: invalid argument '%s'\n"), argv[0], argv[i]);
606 printf(_("Try '%s --help' for more information\n"), argv[0]);
607 exit(1);
608 }
609 }
610 }
611
612 timeDB = WMGetDefaultsFromPath("./UserTime.plist");
613 WMAddNotificationObserver(updatedDomain, NULL, WMUserDefaultsDidChangeNotification, NULL);
614
615 clientConnections = WMCreateArray(4);
616
617 /* A NULL ServerAddress means to listen on any address the host has.
618 * Else if ServerAddress points to a specific address (like "localhost",
619 * "host.domain.com" or "192.168.1.1"), then it will only listen on that
620 * interface and ignore incoming connections on the others. */
621 if (ServerAddress && strcasecmp(ServerAddress, "Any") == 0)
622 ServerAddress = NULL;
623 if (ServerPort == NULL)
624 ServerPort = "34567";
625
626 printf("Server will listen on '%s:%s'\n", ServerAddress ? ServerAddress : "Any", ServerPort);
627 printf("This server will allow connections from:");
628 if (allowedHostList) {
629 int i;
630 char *hName;
631
632 for (i = 0; i < WMGetArrayItemCount(allowedHostList); i++) {
633 hName = WMGetHostName(WMGetFromArray(allowedHostList, i));
634 printf("%s'%s'", i == 0 ? " " : ", ", hName);
635 }
636 printf(".\n");
637 } else {
638 printf(" any host.\n");
639 }
640
641 serverPtr = WMCreateConnectionAsServerAtAddress(ServerAddress, ServerPort, NULL);
642
643 if (!serverPtr) {
644 wfatal("could not create server on `%s:%s`. Exiting.",
645 ServerAddress ? ServerAddress : "localhost", ServerPort);
646 exit(1);
647 }
648
649 WMSetConnectionDelegate(serverPtr, &socketDelegate);
650
651 WMAddNotificationObserver(removeConnection, NULL, SEConnectionShouldBeRemovedNotification, NULL);
652
653 while (1) {
654 /* The ASAP notification queue is called at the end of WHandleEvents()
655 * There's where died connections we get while running through
656 * WHandleEvents() get removed. */
657 WHandleEvents();
658 }
659
660 return 0;
a1fb870f dan2001-02-09 03:12:16 +0000661}