summaryrefslogtreecommitdiffstats
path: root/unix/tclUnixSock.c
diff options
context:
space:
mode:
authorjan.nijtmans <nijtmans@users.sourceforge.net>2022-10-12 10:50:38 (GMT)
committerjan.nijtmans <nijtmans@users.sourceforge.net>2022-10-12 10:50:38 (GMT)
commit24b2e0513de4414441b150d418d36be759bc5b7e (patch)
treeeffc1ff591d5ab64c76f64e6e452443b6c66d46d /unix/tclUnixSock.c
parenta1b8aa387d4a652edccfe66fa0ecf0b8e338bcd0 (diff)
parent6552a88de10ad8275d8b26c7fde04754348c8677 (diff)
downloadtcl-24b2e0513de4414441b150d418d36be759bc5b7e.zip
tcl-24b2e0513de4414441b150d418d36be759bc5b7e.tar.gz
tcl-24b2e0513de4414441b150d418d36be759bc5b7e.tar.bz2
Merge 8.7
Diffstat (limited to 'unix/tclUnixSock.c')
-rw-r--r--unix/tclUnixSock.c133
1 files changed, 128 insertions, 5 deletions
diff --git a/unix/tclUnixSock.c b/unix/tclUnixSock.c
index da26e52..af1782d 100644
--- a/unix/tclUnixSock.c
+++ b/unix/tclUnixSock.c
@@ -9,6 +9,7 @@
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
+#include <netinet/tcp.h>
#include "tclInt.h"
/*
@@ -139,6 +140,9 @@ static int TcpInputProc(void *instanceData, char *buf,
int toRead, int *errorCode);
static int TcpOutputProc(void *instanceData,
const char *buf, int toWrite, int *errorCode);
+static int TcpSetOptionProc(void *instanceData,
+ Tcl_Interp *interp, const char *optionName,
+ const char *value);
static void TcpThreadActionProc(void *instanceData, int action);
static void TcpWatchProc(void *instanceData, int mask);
static int WaitForConnect(TcpState *statePtr, int *errorCodePtr);
@@ -156,7 +160,7 @@ static const Tcl_ChannelType tcpChannelType = {
TcpInputProc, /* Input proc. */
TcpOutputProc, /* Output proc. */
NULL, /* Seek proc. */
- NULL, /* Set option proc. */
+ TcpSetOptionProc, /* Set option proc. */
TcpGetOptionProc, /* Get option proc. */
TcpWatchProc, /* Initialize notifier. */
TcpGetHandleProc, /* Get OS handles out of channel. */
@@ -805,6 +809,87 @@ TcpHostPortList(
/*
*----------------------------------------------------------------------
*
+ * TcpSetOptionProc --
+ *
+ * Sets TCP channel specific options.
+ *
+ * Results:
+ * None, unless an error happens.
+ *
+ * Side effects:
+ * Changes attributes of the socket at the system level.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+TcpSetOptionProc(
+ void *instanceData, /* Socket state. */
+ Tcl_Interp *interp, /* For error reporting - can be NULL. */
+ const char *optionName, /* Name of the option to set. */
+ const char *value) /* New value for option. */
+{
+ TcpState *statePtr = (TcpState *)instanceData;
+ size_t len = 0;
+
+ if (optionName != NULL) {
+ len = strlen(optionName);
+ }
+
+ if ((len > 1) && (optionName[1] == 'k') &&
+ (strncmp(optionName, "-keepalive", len) == 0)) {
+ int val = 0, ret;
+
+ if (Tcl_GetBoolean(interp, value, &val) != TCL_OK) {
+ return TCL_ERROR;
+ }
+#if defined(SO_KEEPALIVE)
+ ret = setsockopt(statePtr->fds.fd, SOL_SOCKET, SO_KEEPALIVE,
+ (const char *) &val, sizeof(int));
+#else
+ ret = -1;
+ Tcl_SetErrno(ENOTSUP);
+#endif
+ if (ret < 0) {
+ if (interp) {
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "couldn't set socket option: %s",
+ Tcl_PosixError(interp)));
+ }
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+ }
+ if ((len > 1) && (optionName[1] == 'n') &&
+ (strncmp(optionName, "-nodelay", len) == 0)) {
+ int val = 0, ret;
+
+ if (Tcl_GetBoolean(interp, value, &val) != TCL_OK) {
+ return TCL_ERROR;
+ }
+#if defined(SOL_TCP) && defined(TCP_NODELAY)
+ ret = setsockopt(statePtr->fds.fd, SOL_TCP, TCP_NODELAY,
+ (const char *) &val, sizeof(int));
+#else
+ ret = -1;
+ Tcl_SetErrno(ENOTSUP);
+#endif
+ if (ret < 0) {
+ if (interp) {
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "couldn't set socket option: %s",
+ Tcl_PosixError(interp)));
+ }
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+ }
+ return Tcl_BadChannelOption(interp, optionName, "keepalive nodelay");
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* TcpGetOptionProc --
*
* Computes an option value for a TCP socket based channel, or a list of
@@ -825,7 +910,7 @@ TcpHostPortList(
static int
TcpGetOptionProc(
- void *instanceData, /* Socket state. */
+ void *instanceData, /* Socket state. */
Tcl_Interp *interp, /* For error reporting - can be NULL. */
const char *optionName, /* Name of the option to retrieve the value
* for, or NULL to get all options and their
@@ -836,8 +921,6 @@ TcpGetOptionProc(
TcpState *statePtr = (TcpState *)instanceData;
size_t len = 0;
- WaitForConnect(statePtr, NULL);
-
if (optionName != NULL) {
len = strlen(optionName);
}
@@ -846,6 +929,7 @@ TcpGetOptionProc(
(strncmp(optionName, "-error", len) == 0)) {
socklen_t optlen = sizeof(int);
+ WaitForConnect(statePtr, NULL);
if (GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT)) {
/*
* Suppress errors as long as we are not done.
@@ -870,6 +954,7 @@ TcpGetOptionProc(
if ((len > 1) && (optionName[1] == 'c') &&
(strncmp(optionName, "-connecting", len) == 0)) {
+ WaitForConnect(statePtr, NULL);
Tcl_DStringAppend(dsPtr,
GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT) ? "1" : "0", TCL_INDEX_NONE);
return TCL_OK;
@@ -880,6 +965,7 @@ TcpGetOptionProc(
address peername;
socklen_t size = sizeof(peername);
+ WaitForConnect(statePtr, NULL);
if (GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT)) {
/*
* In async connect output an empty string
@@ -931,6 +1017,7 @@ TcpGetOptionProc(
socklen_t size;
int found = 0;
+ WaitForConnect(statePtr, NULL);
if (len == 0) {
Tcl_DStringAppendElement(dsPtr, "-sockname");
Tcl_DStringStartSublist(dsPtr);
@@ -964,9 +1051,45 @@ TcpGetOptionProc(
}
}
+ if ((len == 0) || ((len > 1) && (optionName[1] == 'k') &&
+ (strncmp(optionName, "-keepalive", len) == 0))) {
+ socklen_t size;
+ int opt = 0;
+
+ if (len == 0) {
+ Tcl_DStringAppendElement(dsPtr, "-keepalive");
+ }
+#if defined(SO_KEEPALIVE)
+ getsockopt(statePtr->fds.fd, SOL_SOCKET, SO_KEEPALIVE,
+ (char *) &opt, &size);
+#endif
+ Tcl_DStringAppendElement(dsPtr, opt ? "1" : "0");
+ if (len > 0) {
+ return TCL_OK;
+ }
+ }
+
+ if ((len == 0) || ((len > 1) && (optionName[1] == 'n') &&
+ (strncmp(optionName, "-nodelay", len) == 0))) {
+ socklen_t size;
+ int opt = 0;
+
+ if (len == 0) {
+ Tcl_DStringAppendElement(dsPtr, "-nodelay");
+ }
+#if defined(SOL_TCP) && defined(TCP_NODELAY)
+ getsockopt(statePtr->fds.fd, SOL_TCP, TCP_NODELAY,
+ (char *) &opt, &size);
+#endif
+ Tcl_DStringAppendElement(dsPtr, opt ? "1" : "0");
+ if (len > 0) {
+ return TCL_OK;
+ }
+ }
+
if (len > 0) {
return Tcl_BadChannelOption(interp, optionName,
- "connecting peername sockname");
+ "connecting keepalive nodelay peername sockname");
}
return TCL_OK;