1
0
mirror of https://github.com/gryf/wmaker.git synced 2025-12-19 12:28:22 +01:00
Files
wmaker/WINGs/connection.c
2004-10-12 21:28:27 +00:00

1054 lines
26 KiB
C

/*
* 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;
int 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;
int sock, on;
int size;
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;
int 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;
}
}