1
0
mirror of https://github.com/gryf/wmaker.git synced 2025-12-28 17:32:29 +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:
Tamas TEVESZ
2010-03-24 01:51:07 +01:00
committed by Carlos R. Mafra
parent 55959b4f7e
commit 1f2b9999b9
10 changed files with 5 additions and 2308 deletions

View File

@@ -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.

View File

@@ -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 \

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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 \

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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 \

View File

@@ -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#"