--- sa.c 2002/10/26 15:45:32 1.62
+++ sa.c 2002/10/30 08:42:16 1.63
@@ -206,6 +206,12 @@
SA_SC_DECLARE_6(ssize_t, sendto, int, const void *, size_t, int, const struct sockaddr *, socklen_t)
} sa_syscall_tab_t;
+/* socket option information */
+typedef struct {
+ int todo;
+ int value;
+} sa_optinfo_t;
+
/* socket abstraction object */
struct sa_st {
sa_type_t eType; /* socket type (stream or datagram) */
@@ -218,6 +224,7 @@
int nWriteSize; /* write buffer current size */
char *cpWriteBuf; /* write buffer memory chunk */
sa_syscall_tab_t scSysCall; /* table of system calls */
+ sa_optinfo_t optInfo[5]; /* option storage */
};
/* socket address abstraction object */
@@ -866,25 +873,120 @@
/* set timeouts if timeouts or done in kernel */
static sa_rc_t sa_socket_settimeouts(sa_t *sa)
{
+ /* stop processing if socket is still not allocated */
+ if (sa->fdSocket == -1)
+ return SA_OK;
+
#if defined(SO_RCVTIMEO) && defined(SO_SNDTIMEO)
- if (sa->fdSocket != -1) {
- if (SA_TVISZERO(sa->tvTimeout[SA_TIMEOUT_READ])) {
- if (setsockopt(sa->fdSocket, SOL_SOCKET, SO_RCVTIMEO,
- (const void *)(&sa->tvTimeout[SA_TIMEOUT_READ]),
- (socklen_t)(sizeof(sa->tvTimeout[SA_TIMEOUT_READ]))) < 0)
- return SA_RC(SA_ERR_SYS);
- }
- if (SA_TVISZERO(sa->tvTimeout[SA_TIMEOUT_WRITE])) {
- if (setsockopt(sa->fdSocket, SOL_SOCKET, SO_SNDTIMEO,
- (const void *)(&sa->tvTimeout[SA_TIMEOUT_WRITE]),
- (socklen_t)(sizeof(sa->tvTimeout[SA_TIMEOUT_WRITE]))) < 0)
- return SA_RC(SA_ERR_SYS);
- }
+ if (SA_TVISZERO(sa->tvTimeout[SA_TIMEOUT_READ])) {
+ if (setsockopt(sa->fdSocket, SOL_SOCKET, SO_RCVTIMEO,
+ (const void *)(&sa->tvTimeout[SA_TIMEOUT_READ]),
+ (socklen_t)(sizeof(sa->tvTimeout[SA_TIMEOUT_READ]))) < 0)
+ return SA_RC(SA_ERR_SYS);
+ }
+ if (SA_TVISZERO(sa->tvTimeout[SA_TIMEOUT_WRITE])) {
+ if (setsockopt(sa->fdSocket, SOL_SOCKET, SO_SNDTIMEO,
+ (const void *)(&sa->tvTimeout[SA_TIMEOUT_WRITE]),
+ (socklen_t)(sizeof(sa->tvTimeout[SA_TIMEOUT_WRITE]))) < 0)
+ return SA_RC(SA_ERR_SYS);
}
#endif
return SA_OK;
}
+/* set socket options */
+static sa_rc_t sa_socket_setoptions(sa_t *sa)
+{
+ int i;
+ sa_rc_t rv;
+
+ /* stop processing if socket is still not allocated */
+ if (sa->fdSocket == -1)
+ return SA_OK;
+
+ /* check for pending options */
+ rv = SA_OK;
+ for (i = 0; i < (sizeof(sa->optInfo)/sizeof(sa->optInfo[0])); i++) {
+ if (sa->optInfo[i].todo) {
+ switch (i) {
+ /* enable/disable Nagle's Algorithm (see RFC898) */
+ case SA_OPTION_NAGLE: {
+#if defined(IPPROTO_TCP) && defined(TCP_NODELAY)
+ int mode = sa->optInfo[i].value;
+ if (setsockopt(sa->fdSocket, IPPROTO_TCP, TCP_NODELAY,
+ (const void *)&mode,
+ (socklen_t)sizeof(mode)) < 0)
+ rv = SA_ERR_SYS;
+ else
+ sa->optInfo[i].todo = FALSE;
+#endif
+ break;
+ }
+ /* enable/disable linger close semantics */
+ case SA_OPTION_LINGER: {
+#if defined(SO_LINGER)
+ struct linger linger;
+ linger.l_onoff = (sa->optInfo[i].value == 0 ? 0 : 1);
+ linger.l_linger = sa->optInfo[i].value;
+ if (setsockopt(sa->fdSocket, SOL_SOCKET, SO_LINGER,
+ (const void *)&linger,
+ (socklen_t)sizeof(struct linger)) < 0)
+ rv = SA_ERR_SYS;
+ else
+ sa->optInfo[i].todo = FALSE;
+#endif
+ break;
+ }
+ /* enable/disable reusability of binding to address */
+ case SA_OPTION_REUSEADDR: {
+#if defined(SO_REUSEADDR)
+ int mode = sa->optInfo[i].value;
+ if (setsockopt(sa->fdSocket, SOL_SOCKET, SO_REUSEADDR,
+ (const void *)&mode, (socklen_t)sizeof(mode)) < 0)
+ rv = SA_ERR_SYS;
+ else
+ sa->optInfo[i].todo = FALSE;
+#endif
+ break;
+ }
+ /* enable/disable reusability of binding to port */
+ case SA_OPTION_REUSEPORT: {
+#if defined(SO_REUSEPORT)
+ int mode = sa->optInfo[i].value;
+ if (setsockopt(sa->fdSocket, SOL_SOCKET, SO_REUSEPORT,
+ (const void *)&mode, (socklen_t)sizeof(mode)) < 0)
+ rv = SA_ERR_SYS;
+ else
+ sa->optInfo[i].todo = FALSE;
+#endif
+ break;
+ }
+ /* enable/disable non-blocking I/O mode */
+ case SA_OPTION_NONBLOCK: {
+ int mode = sa->optInfo[i].value;
+ int flags;
+ if ((flags = fcntl(sa->fdSocket, F_GETFL, 0)) < 0) {
+ rv = SA_ERR_SYS;
+ break;
+ }
+ if (mode == 0)
+ flags &= ~(O_NONBLOCK);
+ else
+ flags |= O_NONBLOCK;
+ if (fcntl(sa->fdSocket, F_SETFL, flags) < 0)
+ rv = SA_ERR_SYS;
+ else
+ sa->optInfo[i].todo = FALSE;
+ break;
+ }
+ default: /* NOTREACHED */ break;
+ }
+ }
+ }
+
+ return SA_RC(rv);
+}
+
/* internal lazy/delayed initialization of underlying socket */
static sa_rc_t sa_socket_init(sa_t *sa, int nFamily)
{
@@ -893,6 +995,7 @@
#if !(defined(IPPROTO_TCP) && defined(IPPROTO_UDP))
struct protoent *pe;
#endif
+ sa_rc_t rv;
/* argument sanity check(s) */
if (sa == NULL)
@@ -945,7 +1048,12 @@
return SA_RC(SA_ERR_SYS);
/* optionally set kernel timeouts */
- sa_socket_settimeouts(sa);
+ if ((rv = sa_socket_settimeouts(sa)) != SA_OK)
+ return SA_RC(rv);
+
+ /* optionally configure changed options */
+ if ((rv = sa_socket_setoptions(sa)) != SA_OK)
+ return SA_RC(rv);
return SA_OK;
}
@@ -998,6 +1106,12 @@
sa->tvTimeout[i].tv_usec = 0;
}
+ /* init options object attributes */
+ for (i = 0; i < (sizeof(sa->optInfo)/sizeof(sa->optInfo[0])); i++) {
+ sa->optInfo[i].todo = FALSE;
+ sa->optInfo[i].value = 0;
+ }
+
/* init syscall object attributes */
SA_SC_ASSIGN(sa, connect, connect, NULL);
SA_SC_ASSIGN(sa, accept, accept, NULL);
@@ -1056,6 +1170,7 @@
sa_rc_t sa_timeout(sa_t *sa, sa_timeout_t id, long sec, long usec)
{
int i;
+ sa_rc_t rv;
/* argument sanity check(s) */
if (sa == NULL)
@@ -1072,8 +1187,9 @@
sa->tvTimeout[id].tv_usec = usec;
}
- /* optionally set kernel timeouts */
- sa_socket_settimeouts(sa);
+ /* try to already set timeouts */
+ if ((rv = sa_socket_settimeouts(sa)) != SA_OK)
+ return SA_RC(rv);
return SA_OK;
}
@@ -1150,16 +1266,10 @@
va_start(ap, id);
switch (id) {
case SA_OPTION_NAGLE: {
- /* enable/disable Nagle's Algorithm (see RFC898) */
#if defined(IPPROTO_TCP) && defined(TCP_NODELAY)
int mode = ((int)va_arg(ap, int) ? 1 : 0);
- if (sa->fdSocket == -1) {
- rv = SA_ERR_USE;
- break;
- }
- if (setsockopt(sa->fdSocket, IPPROTO_TCP, TCP_NODELAY,
- (const void *)&mode, (socklen_t)sizeof(mode)) < 0)
- rv = SA_ERR_SYS;
+ sa->optInfo[SA_OPTION_NAGLE].value = mode;
+ sa->optInfo[SA_OPTION_NAGLE].todo = TRUE;
#else
rv = SA_ERR_IMP;
#endif
@@ -1167,61 +1277,40 @@
}
case SA_OPTION_LINGER: {
#if defined(SO_LINGER)
- struct linger *linger = (struct linger *)va_arg(ap, void *);
- if (sa->fdSocket == -1) {
- rv = SA_ERR_USE;
- break;
- }
- if (setsockopt(sa->fdSocket, SOL_SOCKET, SO_LINGER,
- (const void *)linger, (socklen_t)sizeof(struct linger)) < 0)
- rv = SA_ERR_SYS;
+ int amount = ((int)va_arg(ap, int) ? 1 : 0);
+ sa->optInfo[SA_OPTION_LINGER].value = amount;
+ sa->optInfo[SA_OPTION_LINGER].todo = TRUE;
#else
rv = SA_ERR_IMP;
#endif
break;
}
case SA_OPTION_REUSEADDR:
-#ifdef SA_OPTION_REUSEPORT
- case SA_OPTION_REUSEPORT:
+ {
+#if defined(SO_REUSEADDR)
+ int mode = ((int)va_arg(ap, int) ? 1 : 0);
+ sa->optInfo[SA_OPTION_REUSEADDR].value = mode;
+ sa->optInfo[SA_OPTION_REUSEADDR].todo = TRUE;
+#else
+ rv = SA_ERR_IMP;
#endif
+ break;
+ }
+ case SA_OPTION_REUSEPORT:
{
- /* enable/disable reusability of binding to address or port */
+#if defined(SO_REUSEPORT)
int mode = ((int)va_arg(ap, int) ? 1 : 0);
- int flag;
- if (sa->fdSocket == -1) {
- rv = SA_ERR_USE;
- break;
- }
- switch (id) {
- case SA_OPTION_REUSEADDR: flag = SO_REUSEADDR; break;
-#ifdef SA_OPTION_REUSEPORT
- case SA_OPTION_REUSEPORT: flag = SO_REUSEPORT; break;
+ sa->optInfo[SA_OPTION_REUSEPORT].value = mode;
+ sa->optInfo[SA_OPTION_REUSEPORT].todo = TRUE;
+#else
+ rv = SA_ERR_IMP;
#endif
- default: flag = 0; break;
- }
- if (setsockopt(sa->fdSocket, SOL_SOCKET, flag,
- (const void *)&mode, (socklen_t)sizeof(mode)) < 0)
- rv = SA_ERR_SYS;
break;
}
case SA_OPTION_NONBLOCK: {
- /* enable/disable non-blocking I/O mode */
- int flags;
int mode = (int)va_arg(ap, int);
- if (sa->fdSocket == -1) {
- rv = SA_ERR_USE;
- break;
- }
- if ((flags = fcntl(sa->fdSocket, F_GETFL, 0)) < 0) {
- rv = SA_ERR_SYS;
- break;
- }
- if (mode == 0)
- flags &= ~(O_NONBLOCK);
- else
- flags |= O_NONBLOCK;
- if (fcntl(sa->fdSocket, F_SETFL, flags) < 0)
- rv = SA_ERR_SYS;
+ sa->optInfo[SA_OPTION_NONBLOCK].value = mode;
+ sa->optInfo[SA_OPTION_NONBLOCK].todo = TRUE;
break;
}
default: {
@@ -1230,7 +1319,15 @@
}
va_end(ap);
- return SA_RC(rv);
+ /* if an error already occured, stop here */
+ if (rv != SA_OK)
+ return SA_RC(rv);
+
+ /* else already (re)set) options (if possible) */
+ if ((rv = sa_socket_setoptions(sa)) != SA_OK)
+ return SA_RC(rv);
+
+ return SA_OK;
}
/* override system call */
|