summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--generic/tcl.h13
-rw-r--r--generic/tclBasic.c2
-rw-r--r--generic/tclClock.c2
-rw-r--r--generic/tclEvent.c2
-rw-r--r--generic/tclIO.c731
-rw-r--r--generic/tclIOCmd.c45
-rw-r--r--generic/tclIORChan.c67
-rw-r--r--generic/tclIORTrans.c2
-rw-r--r--generic/tclIOSock.c29
-rw-r--r--generic/tclIOUtil.c53
-rw-r--r--generic/tclInt.h2
-rw-r--r--generic/tclNamesp.c2
-rw-r--r--generic/tclObj.c2
-rw-r--r--generic/tclRegexp.c4
-rw-r--r--generic/tclStubInit.c10
-rw-r--r--generic/tclTest.c85
-rw-r--r--generic/tclTimer.c12
-rw-r--r--generic/tclUtil.c4
-rw-r--r--tests/socket.test24
-rw-r--r--unix/tclUnixSock.c328
-rw-r--r--unix/tclUnixThrd.c2
-rw-r--r--win/tclWinSock.c717
22 files changed, 1311 insertions, 827 deletions
diff --git a/generic/tcl.h b/generic/tcl.h
index b1ddd72..5ff0742 100644
--- a/generic/tcl.h
+++ b/generic/tcl.h
@@ -419,10 +419,6 @@ typedef TCL_WIDE_INT_TYPE Tcl_WideInt;
typedef unsigned TCL_WIDE_INT_TYPE Tcl_WideUInt;
#ifdef TCL_WIDE_INT_IS_LONG
-# define Tcl_WideAsLong(val) ((long)(val))
-# define Tcl_LongAsWide(val) ((long)(val))
-# define Tcl_WideAsDouble(val) ((double)((long)(val)))
-# define Tcl_DoubleAsWide(val) ((long)((double)(val)))
# ifndef TCL_LL_MODIFIER
# define TCL_LL_MODIFIER "l"
# endif /* !TCL_LL_MODIFIER */
@@ -434,12 +430,13 @@ typedef unsigned TCL_WIDE_INT_TYPE Tcl_WideUInt;
# ifndef TCL_LL_MODIFIER
# define TCL_LL_MODIFIER "ll"
# endif /* !TCL_LL_MODIFIER */
-# define Tcl_WideAsLong(val) ((long)((Tcl_WideInt)(val)))
-# define Tcl_LongAsWide(val) ((Tcl_WideInt)((long)(val)))
-# define Tcl_WideAsDouble(val) ((double)((Tcl_WideInt)(val)))
-# define Tcl_DoubleAsWide(val) ((Tcl_WideInt)((double)(val)))
#endif /* TCL_WIDE_INT_IS_LONG */
+#define Tcl_WideAsLong(val) ((long)((Tcl_WideInt)(val)))
+#define Tcl_LongAsWide(val) ((Tcl_WideInt)((long)(val)))
+#define Tcl_WideAsDouble(val) ((double)((Tcl_WideInt)(val)))
+#define Tcl_DoubleAsWide(val) ((Tcl_WideInt)((double)(val)))
+
#if defined(_WIN32)
# ifdef __BORLANDC__
typedef struct stati64 Tcl_StatBuf;
diff --git a/generic/tclBasic.c b/generic/tclBasic.c
index b29e19e..aae7ab6 100644
--- a/generic/tclBasic.c
+++ b/generic/tclBasic.c
@@ -1071,7 +1071,7 @@ Tcl_CallWhenDeleted(
Interp *iPtr = (Interp *) interp;
static Tcl_ThreadDataKey assocDataCounterKey;
int *assocDataCounterPtr =
- Tcl_GetThreadData(&assocDataCounterKey, (int)sizeof(int));
+ Tcl_GetThreadData(&assocDataCounterKey, sizeof(int));
int isNew;
char buffer[32 + TCL_INTEGER_SPACE];
AssocData *dPtr = ckalloc(sizeof(AssocData));
diff --git a/generic/tclClock.c b/generic/tclClock.c
index ac4a4d6..d44e9dc 100644
--- a/generic/tclClock.c
+++ b/generic/tclClock.c
@@ -1694,7 +1694,7 @@ ThreadSafeLocalTime(
* Get a thread-local buffer to hold the returned time.
*/
- struct tm *tmPtr = Tcl_GetThreadData(&tmKey, (int) sizeof(struct tm));
+ struct tm *tmPtr = Tcl_GetThreadData(&tmKey, sizeof(struct tm));
#ifdef HAVE_LOCALTIME_R
localtime_r(timePtr, tmPtr);
#else
diff --git a/generic/tclEvent.c b/generic/tclEvent.c
index 436db7a..49fd2ae 100644
--- a/generic/tclEvent.c
+++ b/generic/tclEvent.c
@@ -37,7 +37,7 @@ typedef struct BgError {
* pending background errors for the interpreter.
*/
-typedef struct ErrAssocData {
+typedef struct {
Tcl_Interp *interp; /* Interpreter in which error occurred. */
Tcl_Obj *cmdPrefix; /* First word(s) of the handler command */
BgError *firstBgPtr; /* First in list of all background errors
diff --git a/generic/tclIO.c b/generic/tclIO.c
index a509ebf..1460392 100644
--- a/generic/tclIO.c
+++ b/generic/tclIO.c
@@ -116,7 +116,7 @@ typedef struct CopyState {
* The structure defined below is used in this file only.
*/
-typedef struct ThreadSpecificData {
+typedef struct {
NextChannelHandler *nestedHandlerPtr;
/* This variable holds the list of nested
* Tcl_NotifyChannel invocations. */
@@ -321,7 +321,7 @@ static int WillRead(Channel *chanPtr);
typedef struct ResolvedChanName {
ChannelState *statePtr; /* The saved lookup result */
Tcl_Interp *interp; /* The interp in which the lookup was done. */
- size_t epoch; /* The epoch of the channel when the lookup
+ size_t epoch; /* The epoch of the channel when the lookup
* was done. Use to verify validity. */
size_t refCount; /* Share this struct among many Tcl_Obj. */
} ResolvedChanName;
@@ -381,20 +381,20 @@ ChanCloseHalf(
*
* ChanRead --
*
- * Read up to dstSize bytes using the inputProc of chanPtr, store
- * them at dst, and return the number of bytes stored.
+ * Read up to dstSize bytes using the inputProc of chanPtr, store them at
+ * dst, and return the number of bytes stored.
*
* Results:
* The return value of the driver inputProc,
* - number of bytes stored at dst, ot
- * - -1 on error, with a Posix error code available to the
- * caller by calling Tcl_GetErrno().
+ * - -1 on error, with a Posix error code available to the caller by
+ * calling Tcl_GetErrno().
*
* Side effects:
- * The CHANNEL_BLOCKED and CHANNEL_EOF flags of the channel state are
- * set as appropriate.
- * On EOF, the inputEncodingFlags are set to perform ending operations
- * on decoding.
+ * The CHANNEL_BLOCKED and CHANNEL_EOF flags of the channel state are set
+ * as appropriate. On EOF, the inputEncodingFlags are set to perform
+ * ending operations on decoding.
+ *
* TODO - Is this really the right place for that?
*
*---------------------------------------------------------------------------
@@ -408,15 +408,17 @@ ChanRead(
int bytesRead, result;
/*
- * If the caller asked for zero bytes, we'd force the inputProc
- * to return zero bytes, and then misinterpret that as EOF.
+ * If the caller asked for zero bytes, we'd force the inputProc to return
+ * zero bytes, and then misinterpret that as EOF.
*/
+
assert(dstSize > 0);
/*
* Each read op must set the blocked and eof states anew, not let
* the effect of prior reads leak through.
*/
+
if (GotFlag(chanPtr->state, CHANNEL_EOF)) {
chanPtr->state->inputEncodingFlags |= TCL_ENCODING_START;
}
@@ -429,7 +431,10 @@ ChanRead(
bytesRead = chanPtr->typePtr->inputProc(chanPtr->instanceData,
dst, dstSize, &result);
- /* Stop any flag leakage through stacked channel levels */
+ /*
+ * Stop any flag leakage through stacked channel levels.
+ */
+
if (GotFlag(chanPtr->state, CHANNEL_EOF)) {
chanPtr->state->inputEncodingFlags |= TCL_ENCODING_START;
}
@@ -437,10 +442,10 @@ ChanRead(
chanPtr->state->inputEncodingFlags &= ~TCL_ENCODING_END;
if (bytesRead > 0) {
/*
- * If we get a short read, signal up that we may be BLOCKED.
- * We should avoid calling the driver because on some
- * platforms we will block in the low level reading code even
- * though the channel is set into nonblocking mode.
+ * If we get a short read, signal up that we may be BLOCKED. We should
+ * avoid calling the driver because on some platforms we will block in
+ * the low level reading code even though the channel is set into
+ * nonblocking mode.
*/
if (bytesRead < dstSize) {
@@ -574,7 +579,10 @@ TclFinalizeIOSubsystem(void)
int active = 1; /* Flag == 1 while there's still work to do */
int doflushnb;
- /* Fetch the pre-TIP#398 compatibility flag */
+ /*
+ * Fetch the pre-TIP#398 compatibility flag.
+ */
+
{
const char *s;
Tcl_DString ds;
@@ -619,18 +627,20 @@ TclFinalizeIOSubsystem(void)
*/
if (active) {
-
TclChannelPreserve((Tcl_Channel)chanPtr);
+
/*
- * TIP #398: by default, we no longer set the channel back into
- * blocking mode. To restore the old blocking behavior, the
- * environment variable TCL_FLUSH_NONBLOCKING_ON_EXIT must be set
+ * TIP #398: by default, we no longer set the channel back into
+ * blocking mode. To restore the old blocking behavior, the
+ * environment variable TCL_FLUSH_NONBLOCKING_ON_EXIT must be set
* and not be "0".
*/
+
if (doflushnb) {
- /* Set the channel back into blocking mode to ensure that we wait
- * for all data to flush out.
- */
+ /*
+ * Set the channel back into blocking mode to ensure that we
+ * wait for all data to flush out.
+ */
(void) Tcl_SetChannelOption(NULL, (Tcl_Channel) chanPtr,
"-blocking", "on");
@@ -1511,8 +1521,10 @@ TclGetChannelFromObj(
if ((resPtr->interp == interp) /* Same interp context */
/* No epoch change in channel since lookup */
&& (resPtr->epoch == statePtr->epoch)) {
+ /*
+ * Have a valid saved lookup. Jump to end to return it.
+ */
- /* Have a valid saved lookup. Jump to end to return it. */
goto valid;
}
}
@@ -1527,7 +1539,10 @@ TclGetChannelFromObj(
}
if (resPtr && resPtr->refCount == 1) {
- /* Re-use the ResolvedCmdName struct */
+ /*
+ * Re-use the ResolvedCmdName struct.
+ */
+
Tcl_Release((ClientData) resPtr->statePtr);
} else {
@@ -1671,7 +1686,7 @@ Tcl_CreateChannel(
* Set the channel up initially in AUTO input translation mode to accept
* "\n", "\r" and "\r\n". Output translation mode is set to a platform
* specific default value. The eofChar is set to 0 for both input and
- * output, so that Tcl does not look for an in-file EOF indicator (e.g.
+ * output, so that Tcl does not look for an in-file EOF indicator (e.g.,
* ^Z) and does not append an EOF indicator to files.
*/
@@ -1899,7 +1914,6 @@ Tcl_StackChannel(
*/
if (((mask & TCL_READABLE) != 0) && (statePtr->inQueueHead != NULL)) {
-
/*
* When statePtr->inQueueHead is not NULL, we know
* prevChanPtr->inQueueHead must be NULL.
@@ -2031,9 +2045,7 @@ Tcl_UnstackChannel(
* of registered channels we wind down the state of the
* transformation, and then restore the state of underlying channel
* into the old structure.
- */
-
- /*
+ *
* TODO: Figure out how to handle the situation where the chan
* operations called below by this unstacking operation cause
* another unstacking recursively. In that case the downChanPtr
@@ -2511,6 +2523,7 @@ RecycleBuffer(
/*
* Do we have to free the buffer to the OS?
*/
+
if (IsShared(bufPtr)) {
mustDiscard = 1;
}
@@ -2521,9 +2534,8 @@ RecycleBuffer(
}
/*
- * Only save buffers which have the requested buffersize for the
- * channel. This is to honor dynamic changes of the buffersize
- * made by the user.
+ * Only save buffers which have the requested buffersize for the channel.
+ * This is to honor dynamic changes of the buffersize made by the user.
*/
if ((bufPtr->bufLength - BUFFER_PADDING) != statePtr->bufSize) {
@@ -2693,14 +2705,18 @@ FlushChannel(
/*
* Should we shift the current output buffer over to the output queue?
* First check that there are bytes in it. If so then...
- * If the output queue is empty, then yes, trusting the caller called
- * us only when written bytes ought to be flushed.
- * If the current output buffer is full, then yes, so we can meet
- * the post-condition that on a successful return to caller we've
- * left space in the current output buffer for more writing (the flush
- * call was to make new room).
- * If the channel is blocking, then yes, so we guarantee that
- * blocking flushes actually flush all pending data.
+ *
+ * If the output queue is empty, then yes, trusting the caller called us
+ * only when written bytes ought to be flushed.
+ *
+ * If the current output buffer is full, then yes, so we can meet the
+ * post-condition that on a successful return to caller we've left space
+ * in the current output buffer for more writing (the flush call was to
+ * make new room).
+ *
+ * If the channel is blocking, then yes, so we guarantee that blocking
+ * flushes actually flush all pending data.
+ *
* Otherwise, no. Keep the current output buffer where it is so more
* can be written to it, possibly filling it, to promote more efficient
* buffer usage.
@@ -2794,8 +2810,8 @@ FlushChannel(
/*
* TIP #219, Tcl Channel Reflection API.
* When defering the error copy a message from the bypass into
- * the unreported area. Or discard it if the new error is to be
- * ignored in favor of an earlier defered error.
+ * the unreported area. Or discard it if the new error is to
+ * be ignored in favor of an earlier defered error.
*/
Tcl_Obj *msg = statePtr->chanMsg;
@@ -2847,8 +2863,11 @@ FlushChannel(
ReleaseChannelBuffer(bufPtr);
break;
} else {
- /* TODO: Consider detecting and reacting to short writes
- * on blocking channels. Ought not happen. See iocmd-24.2. */
+ /*
+ * TODO: Consider detecting and reacting to short writes on
+ * blocking channels. Ought not happen. See iocmd-24.2.
+ */
+
wroteSome = 1;
}
@@ -2882,7 +2901,6 @@ FlushChannel(
ResetFlag(statePtr, BG_FLUSH_SCHEDULED);
ChanWatch(chanPtr, statePtr->interestMask);
} else {
-
/*
* When we are calledFromAsyncFlush, that means a writable
* state on the channel triggered the call, so we should be
@@ -2927,7 +2945,8 @@ FlushChannel(
(statePtr->outQueueHead == NULL) &&
((statePtr->curOutPtr == NULL) ||
IsBufferEmpty(statePtr->curOutPtr))) {
- errorCode = CloseChannelPart(interp, chanPtr, errorCode, TCL_CLOSE_WRITE);
+ errorCode = CloseChannelPart(interp, chanPtr, errorCode,
+ TCL_CLOSE_WRITE);
goto done;
}
@@ -3398,7 +3417,6 @@ Tcl_Close(
if (GotFlag(statePtr, TCL_WRITABLE) && (statePtr->encoding != NULL)
&& !(statePtr->outputEncodingFlags & TCL_ENCODING_START)) {
-
int code = CheckChannelErrors(statePtr, TCL_WRITABLE);
if (code == 0) {
@@ -3488,12 +3506,14 @@ Tcl_Close(
}
return TCL_ERROR;
}
+
/*
* Bug 97069ea11a: set error message if a flush code is set and no error
* message set up to now.
*/
+
if (flushcode != 0 && interp != NULL
- && 0 == Tcl_GetCharLength(Tcl_GetObjResult(interp)) ) {
+ && 0 == Tcl_GetCharLength(Tcl_GetObjResult(interp))) {
Tcl_SetErrno(flushcode);
Tcl_SetObjResult(interp,
Tcl_NewStringObj(Tcl_PosixError(interp), -1));
@@ -3588,8 +3608,8 @@ Tcl_CloseEx(
}
/*
- * A user may try to call half-close from within a channel close
- * handler. That won't do.
+ * A user may try to call half-close from within a channel close handler.
+ * That won't do.
*/
if (statePtr->flags & CHANNEL_INCLOSE) {
@@ -3660,9 +3680,12 @@ CloseWrite(
* closed. May still be used by some
* interpreter */
{
- /* Notes: clear-channel-handlers - write side only ? or keep around, just
- * not called. */
- /* No close cllbacks are run - channel is still open (read side) */
+ /*
+ * Notes: clear-channel-handlers - write side only ? or keep around, just
+ * not called.
+ *
+ * No close callbacks are run - channel is still open (read side)
+ */
ChannelState *statePtr = chanPtr->state;
/* State of real IO channel. */
@@ -3687,9 +3710,9 @@ CloseWrite(
* Notes: Due to the assertion of CHANNEL_CLOSEDWRITE in the flags
* FlushChannel() has called CloseChannelPart(). While we can still access
* "chan" (no structures were freed), the only place which may still
- * contain a message is the interpreter itself, and "CloseChannelPart" made
- * sure to lift any channel message it generated into it. Hence the NULL
- * argument in the call below.
+ * contain a message is the interpreter itself, and "CloseChannelPart"
+ * made sure to lift any channel message it generated into it. Hence the
+ * NULL argument in the call below.
*/
if (TclChanCaughtErrorBypass(interp, NULL)) {
@@ -3913,10 +3936,10 @@ Tcl_ClearChannelHandlers(
StopCopy(statePtr->csPtrW);
/*
- * Must set the interest mask now to 0, otherwise infinite loops
- * will occur if Tcl_DoOneEvent is called before the channel is
- * finally deleted in FlushChannel. This can happen if the channel
- * has a background flush active.
+ * Must set the interest mask now to 0, otherwise infinite loops will
+ * occur if Tcl_DoOneEvent is called before the channel is finally deleted
+ * in FlushChannel. This can happen if the channel has a background flush
+ * active.
*/
statePtr->interestMask = 0;
@@ -4185,22 +4208,24 @@ WillRead(
Channel *chanPtr)
{
if (chanPtr->typePtr == NULL) {
- /* Prevent read attempts on a closed channel */
+ /*
+ * Prevent read attempts on a closed channel.
+ */
+
DiscardInputQueued(chanPtr->state, 0);
Tcl_SetErrno(EINVAL);
return -1;
}
if ((chanPtr->typePtr->seekProc != NULL)
&& (Tcl_OutputBuffered((Tcl_Channel) chanPtr) > 0)) {
-
/*
- * CAVEAT - The assumption here is that FlushChannel() will
- * push out the bytes of any writes that are in progress.
- * Since this is a seekable channel, we assume it is not one
- * that can block and force bg flushing. Channels we know that
- * can do that -- sockets, pipes -- are not seekable. If the
- * assumption is wrong, more drastic measures may be required here
- * like temporarily setting the channel into blocking mode.
+ * CAVEAT - The assumption here is that FlushChannel() will push out
+ * the bytes of any writes that are in progress. Since this is a
+ * seekable channel, we assume it is not one that can block and force
+ * bg flushing. Channels we know that can do that - sockets, pipes -
+ * are not seekable. If the assumption is wrong, more drastic measures
+ * may be required here like temporarily setting the channel into
+ * blocking mode.
*/
if (FlushChannel(NULL, chanPtr, 0) != 0) {
@@ -4292,11 +4317,17 @@ Write(
&statePtr->outputEncodingState, dst,
dstLen + BUFFER_PADDING, &srcRead, &dstWrote, NULL);
- /* See chan-io-1.[89]. Tcl Bug 506297. */
+ /*
+ * See chan-io-1.[89]. Tcl Bug 506297.
+ */
+
statePtr->outputEncodingFlags &= ~TCL_ENCODING_START;
if ((result != TCL_OK) && (srcRead + dstWrote == 0)) {
- /* We're reading from invalid/incomplete UTF-8 */
+ /*
+ * We're reading from invalid/incomplete UTF-8.
+ */
+
ReleaseChannelBuffer(bufPtr);
if (total == 0) {
Tcl_SetErrno(EINVAL);
@@ -4336,11 +4367,10 @@ Write(
}
result |= Tcl_UtfToExternal(NULL, encoding, nl, nlLen,
- statePtr->outputEncodingFlags,
- &statePtr->outputEncodingState, dst,
- dstLen + BUFFER_PADDING, &srcRead, &dstWrote, NULL);
-
- assert (srcRead == nlLen);
+ statePtr->outputEncodingFlags,
+ &statePtr->outputEncodingState, dst,
+ dstLen + BUFFER_PADDING, &srcRead, &dstWrote, NULL);
+ assert(srcRead == nlLen);
bufPtr->nextAdded += dstWrote;
src++;
@@ -4354,11 +4384,11 @@ Write(
if (IsBufferOverflowing(bufPtr)) {
/*
- * When translating from UTF-8 to external encoding, we
- * allowed the translation to produce a character that crossed
- * the end of the output buffer, so that we would get a
- * completely full buffer before flushing it. The extra bytes
- * will be moved to the beginning of the next buffer.
+ * When translating from UTF-8 to external encoding, we allowed
+ * the translation to produce a character that crossed the end of
+ * the output buffer, so that we would get a completely full
+ * buffer before flushing it. The extra bytes will be moved to the
+ * beginning of the next buffer.
*/
saved = -SpaceLeft(bufPtr);
@@ -4378,15 +4408,16 @@ Write(
flushed += statePtr->bufSize;
/*
- * We just flushed. So if we have needNlFlush set to record
- * that we need to flush because theres a (translated) newline
- * in the buffer, that's likely not true any more. But there
- * is a tricky exception. If we have saved bytes that did not
- * really get flushed and those bytes came from a translation
- * of a newline as the last thing taken from the src array,
- * then needNlFlush needs to remain set to flag that the
- * next buffer still needs a newline flush.
+ * We just flushed. So if we have needNlFlush set to record that
+ * we need to flush because theres a (translated) newline in the
+ * buffer, that's likely not true any more. But there is a tricky
+ * exception. If we have saved bytes that did not really get
+ * flushed and those bytes came from a translation of a newline as
+ * the last thing taken from the src array, then needNlFlush needs
+ * to remain set to flag that the next buffer still needs a
+ * newline flush.
*/
+
if (needNlFlush && (saved == 0 || src[-1] != '\n')) {
needNlFlush = 0;
}
@@ -4492,8 +4523,8 @@ Tcl_GetsObj(
if (GotFlag(statePtr, CHANNEL_STICKY_EOF)) {
SetFlag(statePtr, CHANNEL_EOF);
- assert( statePtr->inputEncodingFlags & TCL_ENCODING_END );
- assert( !GotFlag(statePtr, CHANNEL_BLOCKED|INPUT_SAW_CR) );
+ assert(statePtr->inputEncodingFlags & TCL_ENCODING_END);
+ assert(!GotFlag(statePtr, CHANNEL_BLOCKED|INPUT_SAW_CR));
/* TODO: Do we need this? */
UpdateInterest(chanPtr);
@@ -4833,17 +4864,17 @@ Tcl_GetsObj(
*/
done:
- assert(!GotFlag(statePtr, CHANNEL_EOF)
- || GotFlag(statePtr, CHANNEL_STICKY_EOF)
- || Tcl_InputBuffered((Tcl_Channel)chanPtr) == 0);
-
- assert( !(GotFlag(statePtr, CHANNEL_EOF|CHANNEL_BLOCKED)
- == (CHANNEL_EOF|CHANNEL_BLOCKED)) );
+ assert(!GotFlag(statePtr, CHANNEL_EOF)
+ || GotFlag(statePtr, CHANNEL_STICKY_EOF)
+ || Tcl_InputBuffered((Tcl_Channel)chanPtr) == 0);
+ assert(!(GotFlag(statePtr, CHANNEL_EOF|CHANNEL_BLOCKED)
+ == (CHANNEL_EOF|CHANNEL_BLOCKED)));
/*
* Regenerate the top channel, in case it was changed due to
* self-modifying reflected transforms.
*/
+
if (chanPtr != statePtr->topChanPtr) {
TclChannelRelease((Tcl_Channel)chanPtr);
chanPtr = statePtr->topChanPtr;
@@ -4863,10 +4894,9 @@ Tcl_GetsObj(
* end-of-line or end-of-file has been seen. Bytes read from the input
* channel return as a ByteArray obj.
*
- * WARNING! The notion of "binary" used here is different from
- * notions of "binary" used in other places. In particular, this
- * "binary" routine may be called when an -eofchar is set on the
- * channel.
+ * WARNING! The notion of "binary" used here is different from notions
+ * of "binary" used in other places. In particular, this "binary" routine
+ * may be called when an -eofchar is set on the channel.
*
* Results:
* Number of characters accumulated in the object or -1 if error,
@@ -4932,8 +4962,8 @@ TclGetsObjBinary(
ResetFlag(statePtr, CHANNEL_BLOCKED);
while (1) {
/*
- * Subtract the number of bytes that were removed from channel
- * buffer during last call.
+ * Subtract the number of bytes that were removed from channel buffer
+ * during last call.
*/
if (bufPtr != NULL) {
@@ -4945,10 +4975,11 @@ TclGetsObjBinary(
if ((bufPtr == NULL) || (bufPtr->nextAdded == BUFFER_PADDING)) {
/*
- * All channel buffers were exhausted and the caller still
- * hasn't seen EOL. Need to read more bytes from the channel
- * device. Side effect is to allocate another channel buffer.
+ * All channel buffers were exhausted and the caller still hasn't
+ * seen EOL. Need to read more bytes from the channel device. Side
+ * effect is to allocate another channel buffer.
*/
+
if (GetInput(chanPtr) != 0) {
goto restore;
}
@@ -4958,15 +4989,15 @@ TclGetsObjBinary(
}
} else {
/*
- * Incoming CHANNEL_STICKY_EOF is filtered out on entry.
- * A new CHANNEL_STICKY_EOF set in this routine leads to
- * return before coming back here. When we are not dealing
- * with CHANNEL_STICKY_EOF, a CHANNEL_EOF implies an
- * empty buffer. Here the buffer is non-empty so we know
- * we're a non-EOF */
+ * Incoming CHANNEL_STICKY_EOF is filtered out on entry. A new
+ * CHANNEL_STICKY_EOF set in this routine leads to return before
+ * coming back here. When we are not dealing with
+ * CHANNEL_STICKY_EOF, a CHANNEL_EOF implies an empty buffer.
+ * Here the buffer is non-empty so we know we're a non-EOF.
+ */
- assert ( !GotFlag(statePtr, CHANNEL_STICKY_EOF) );
- assert ( !GotFlag(statePtr, CHANNEL_EOF) );
+ assert(!GotFlag(statePtr, CHANNEL_STICKY_EOF));
+ assert(!GotFlag(statePtr, CHANNEL_EOF));
}
dst = (unsigned char *) RemovePoint(bufPtr);
@@ -5033,8 +5064,8 @@ TclGetsObjBinary(
}
/*
- * Copy bytes from the channel buffer to the ByteArray.
- * This may realloc space, so keep track of result.
+ * Copy bytes from the channel buffer to the ByteArray. This may
+ * realloc space, so keep track of result.
*/
rawLen = dstEnd - dst;
@@ -5118,11 +5149,11 @@ TclGetsObjBinary(
*/
done:
- assert(!GotFlag(statePtr, CHANNEL_EOF)
- || GotFlag(statePtr, CHANNEL_STICKY_EOF)
- || Tcl_InputBuffered((Tcl_Channel)chanPtr) == 0);
- assert( !(GotFlag(statePtr, CHANNEL_EOF|CHANNEL_BLOCKED)
- == (CHANNEL_EOF|CHANNEL_BLOCKED)) );
+ assert(!GotFlag(statePtr, CHANNEL_EOF)
+ || GotFlag(statePtr, CHANNEL_STICKY_EOF)
+ || Tcl_InputBuffered((Tcl_Channel)chanPtr) == 0);
+ assert(!(GotFlag(statePtr, CHANNEL_EOF|CHANNEL_BLOCKED)
+ == (CHANNEL_EOF|CHANNEL_BLOCKED)));
UpdateInterest(chanPtr);
TclChannelRelease((Tcl_Channel)chanPtr);
return copiedTotal;
@@ -5255,15 +5286,15 @@ FilterInputBytes(
}
} else {
/*
- * Incoming CHANNEL_STICKY_EOF is filtered out on entry.
- * A new CHANNEL_STICKY_EOF set in this routine leads to
- * return before coming back here. When we are not dealing
- * with CHANNEL_STICKY_EOF, a CHANNEL_EOF implies an
- * empty buffer. Here the buffer is non-empty so we know
- * we're a non-EOF */
+ * Incoming CHANNEL_STICKY_EOF is filtered out on entry. A new
+ * CHANNEL_STICKY_EOF set in this routine leads to return before
+ * coming back here. When we are not dealing with CHANNEL_STICKY_EOF,
+ * a CHANNEL_EOF implies an empty buffer. Here the buffer is
+ * non-empty so we know we're a non-EOF.
+ */
- assert ( !GotFlag(statePtr, CHANNEL_STICKY_EOF) );
- assert ( !GotFlag(statePtr, CHANNEL_EOF) );
+ assert(!GotFlag(statePtr, CHANNEL_STICKY_EOF));
+ assert(!GotFlag(statePtr, CHANNEL_EOF));
}
/*
@@ -5593,7 +5624,9 @@ Tcl_ReadRaw(
return -1;
}
- /* First read bytes from the push-back buffers. */
+ /*
+ * First read bytes from the push-back buffers.
+ */
while (chanPtr->inQueueHead && bytesToRead > 0) {
ChannelBuffer *bufPtr = chanPtr->inQueueHead;
@@ -5601,7 +5634,9 @@ Tcl_ReadRaw(
int toCopy = (bytesInBuffer < bytesToRead) ? bytesInBuffer
: bytesToRead;
- /* Copy the current chunk into the read buffer. */
+ /*
+ * Copy the current chunk into the read buffer.
+ */
memcpy(readBuf, RemovePoint(bufPtr), (size_t) toCopy);
bufPtr->nextRemoved += toCopy;
@@ -5609,7 +5644,9 @@ Tcl_ReadRaw(
readBuf += toCopy;
bytesToRead -= toCopy;
- /* If the current buffer is empty recycle it. */
+ /*
+ * If the current buffer is empty recycle it.
+ */
if (IsBufferEmpty(bufPtr)) {
chanPtr->inQueueHead = bufPtr->nextPtr;
@@ -5621,37 +5658,40 @@ Tcl_ReadRaw(
}
/*
- * Go to the driver only if we got nothing from pushback.
- * Have to do it this way to avoid EOF mis-timings when we
- * consider the ability that EOF may not be a permanent
- * condition in the driver, and in that case we have to
- * synchronize.
+ * Go to the driver only if we got nothing from pushback. Have to do it
+ * this way to avoid EOF mis-timings when we consider the ability that EOF
+ * may not be a permanent condition in the driver, and in that case we
+ * have to synchronize.
*/
if (copied) {
return copied;
}
- /* This test not needed. */
- if (bytesToRead > 0) {
+ /*
+ * This test not needed.
+ */
+ if (bytesToRead > 0) {
int nread = ChanRead(chanPtr, readBuf, bytesToRead);
if (nread > 0) {
- /* Successful read (short is OK) - add to bytes copied */
+ /*
+ * Successful read (short is OK) - add to bytes copied.
+ */
+
copied += nread;
} else if (nread < 0) {
/*
- * An error signaled. If CHANNEL_BLOCKED, then the error
- * is not real, but an indication of blocked state. In
- * that case, retain the flag and let caller receive the
- * short read of copied bytes from the pushback.
- * HOWEVER, if copied==0 bytes from pushback then repeat
- * signalling the blocked state as an error to caller so
- * there is no false report of an EOF.
- * When !CHANNEL_BLOCKED, the error is real and passes on
- * to caller.
+ * An error signaled. If CHANNEL_BLOCKED, then the error is not
+ * real, but an indication of blocked state. In that case, retain
+ * the flag and let caller receive the short read of copied bytes
+ * from the pushback. HOWEVER, if copied==0 bytes from pushback
+ * then repeat signalling the blocked state as an error to caller
+ * so there is no false report of an EOF. When !CHANNEL_BLOCKED,
+ * the error is real and passes on to caller.
*/
+
if (!GotFlag(statePtr, CHANNEL_BLOCKED) || copied == 0) {
copied = -1;
}
@@ -5788,21 +5828,23 @@ DoReadChars(
/*
* Early out when next read will see eofchar.
*
- * NOTE: See DoRead for argument that it's a bug (one we're keeping)
- * to have this escape before the one for zero-char read request.
+ * NOTE: See DoRead for argument that it's a bug (one we're keeping) to
+ * have this escape before the one for zero-char read request.
*/
if (GotFlag(statePtr, CHANNEL_STICKY_EOF)) {
SetFlag(statePtr, CHANNEL_EOF);
- assert( statePtr->inputEncodingFlags & TCL_ENCODING_END );
- assert( !GotFlag(statePtr, CHANNEL_BLOCKED|INPUT_SAW_CR) );
+ assert(statePtr->inputEncodingFlags & TCL_ENCODING_END);
+ assert(!GotFlag(statePtr, CHANNEL_BLOCKED|INPUT_SAW_CR));
/* TODO: We don't need this call? */
UpdateInterest(chanPtr);
return 0;
}
- /* Special handling for zero-char read request. */
+ /*
+ * Special handling for zero-char read request.
+ */
if (toRead == 0) {
if (GotFlag(statePtr, CHANNEL_EOF)) {
statePtr->inputEncodingFlags |= TCL_ENCODING_START;
@@ -5821,7 +5863,10 @@ DoReadChars(
chanPtr = statePtr->topChanPtr;
TclChannelPreserve((Tcl_Channel)chanPtr);
- /* Must clear the BLOCKED|EOF flags here since we check before reading */
+ /*
+ * Must clear the BLOCKED|EOF flags here since we check before reading.
+ */
+
if (GotFlag(statePtr, CHANNEL_EOF)) {
statePtr->inputEncodingFlags |= TCL_ENCODING_START;
}
@@ -5879,10 +5924,11 @@ DoReadChars(
}
/*
- * Failure to fill a channel buffer may have left channel reporting
- * a "blocked" state, but so long as we fulfilled the request here,
- * the caller does not consider us blocked.
+ * Failure to fill a channel buffer may have left channel reporting a
+ * "blocked" state, but so long as we fulfilled the request here, the
+ * caller does not consider us blocked.
*/
+
if (toRead == 0) {
ResetFlag(statePtr, CHANNEL_BLOCKED);
}
@@ -5891,6 +5937,7 @@ DoReadChars(
* Regenerate the top channel, in case it was changed due to
* self-modifying reflected transforms.
*/
+
if (chanPtr != statePtr->topChanPtr) {
TclChannelRelease((Tcl_Channel)chanPtr);
chanPtr = statePtr->topChanPtr;
@@ -5901,11 +5948,12 @@ DoReadChars(
* Update the notifier state so we don't block while there is still data
* in the buffers.
*/
- assert(!GotFlag(statePtr, CHANNEL_EOF)
- || GotFlag(statePtr, CHANNEL_STICKY_EOF)
- || Tcl_InputBuffered((Tcl_Channel)chanPtr) == 0);
- assert( !(GotFlag(statePtr, CHANNEL_EOF|CHANNEL_BLOCKED)
- == (CHANNEL_EOF|CHANNEL_BLOCKED)) );
+
+ assert(!GotFlag(statePtr, CHANNEL_EOF)
+ || GotFlag(statePtr, CHANNEL_STICKY_EOF)
+ || Tcl_InputBuffered((Tcl_Channel)chanPtr) == 0);
+ assert(!(GotFlag(statePtr, CHANNEL_EOF|CHANNEL_BLOCKED)
+ == (CHANNEL_EOF|CHANNEL_BLOCKED)));
UpdateInterest(chanPtr);
TclChannelRelease((Tcl_Channel)chanPtr);
return copied;
@@ -6022,11 +6070,10 @@ ReadChars(
int numBytes, srcLen = BytesLeft(bufPtr);
/*
- * One src byte can yield at most one character. So when the
- * number of src bytes we plan to read is less than the limit on
- * character count to be read, clearly we will remain within that
- * limit, and we can use the value of "srcLen" as a tighter limit
- * for sizing receiving buffers.
+ * One src byte can yield at most one character. So when the number of
+ * src bytes we plan to read is less than the limit on character count to
+ * be read, clearly we will remain within that limit, and we can use the
+ * value of "srcLen" as a tighter limit for sizing receiving buffers.
*/
int toRead = ((charsToRead<0)||(charsToRead > srcLen)) ? srcLen : charsToRead;
@@ -6044,6 +6091,7 @@ ReadChars(
Tcl_AppendToObj(objPtr, NULL, dstLimit);
if (toRead == srcLen) {
unsigned int size;
+
dst = TclGetStringStorage(objPtr, &size) + numBytes;
dstLimit = size - numBytes;
} else {
@@ -6051,19 +6099,18 @@ ReadChars(
}
/*
- * This routine is burdened with satisfying several constraints.
- * It cannot append more than 'charsToRead` chars onto objPtr.
- * This is measured after encoding and translation transformations
- * are completed. There is no precise number of src bytes that can
- * be associated with the limit. Yet, when we are done, we must know
- * precisely the number of src bytes that were consumed to produce
- * the appended chars, so that all subsequent bytes are left in
- * the buffers for future read operations.
+ * This routine is burdened with satisfying several constraints. It cannot
+ * append more than 'charsToRead` chars onto objPtr. This is measured
+ * after encoding and translation transformations are completed. There is
+ * no precise number of src bytes that can be associated with the limit.
+ * Yet, when we are done, we must know precisely the number of src bytes
+ * that were consumed to produce the appended chars, so that all
+ * subsequent bytes are left in the buffers for future read operations.
*
- * The consequence is that we have no choice but to implement a
- * "trial and error" approach, where in general we may need to
- * perform transformations and copies multiple times to achieve
- * a consistent set of results. This takes the shape of a loop.
+ * The consequence is that we have no choice but to implement a "trial and
+ * error" approach, where in general we may need to perform
+ * transformations and copies multiple times to achieve a consistent set
+ * of results. This takes the shape of a loop.
*/
while (1) {
@@ -6076,18 +6123,17 @@ ReadChars(
}
/*
- * Perform the encoding transformation. Read no more than
- * srcLen bytes, write no more than dstLimit bytes.
+ * Perform the encoding transformation. Read no more than srcLen
+ * bytes, write no more than dstLimit bytes.
*
- * Some trickiness with encoding flags here. We do not want
- * the end of a buffer to be treated as the end of all input
- * when the presence of bytes in a next buffer are already
- * known to exist. This is checked with an assert() because
- * so far no test case causing the assertion to be false has
- * been created. The normal operations of channel reading
- * appear to cause EOF and TCL_ENCODING_END setting to appear
- * only in situations where there are no further bytes in
- * any buffers.
+ * Some trickiness with encoding flags here. We do not want the end
+ * of a buffer to be treated as the end of all input when the presence
+ * of bytes in a next buffer are already known to exist. This is
+ * checked with an assert() because so far no test case causing the
+ * assertion to be false has been created. The normal operations of
+ * channel reading appear to cause EOF and TCL_ENCODING_END setting to
+ * appear only in situations where there are no further bytes in any
+ * buffers.
*/
assert(bufPtr->nextPtr == NULL || BytesLeft(bufPtr->nextPtr) == 0
@@ -6098,10 +6144,10 @@ ReadChars(
dst, dstLimit, &srcRead, &dstDecoded, &numChars);
/*
- * Perform the translation transformation in place. Read no more
- * than the dstDecoded bytes the encoding transformation actually
- * produced. Capture the number of bytes written in dstWrote.
- * Capture the number of bytes actually consumed in dstRead.
+ * Perform the translation transformation in place. Read no more than
+ * the dstDecoded bytes the encoding transformation actually produced.
+ * Capture the number of bytes written in dstWrote. Capture the number
+ * of bytes actually consumed in dstRead.
*/
dstWrote = dstLimit;
@@ -6109,11 +6155,9 @@ ReadChars(
TranslateInputEOL(statePtr, dst, dst, &dstWrote, &dstRead);
if (dstRead < dstDecoded) {
-
/*
- * The encoding transformation produced bytes that the
- * translation transformation did not consume. Why did
- * this happen?
+ * The encoding transformation produced bytes that the translation
+ * transformation did not consume. Why did this happen?
*/
if (statePtr->inEofChar && dst[dstRead] == statePtr->inEofChar) {
@@ -6122,40 +6166,38 @@ ReadChars(
* we saw it and stopped translating at that point.
*
* NOTE the bizarre spec of TranslateInputEOL in this case.
- * Clearly the eof char had to be read in order to account
- * for the stopping, but the value of dstRead does not
- * include it.
+ * Clearly the eof char had to be read in order to account for
+ * the stopping, but the value of dstRead does not include it.
*
- * Also rather bizarre, our caller can only notice an
- * EOF condition if we return the value -1 as the number
- * of chars read. This forces us to perform a 2-call
- * dance where the first call can read all the chars
- * up to the eof char, and the second call is solely
- * for consuming the encoded eof char then pointed at
- * by src so that we can return that magic -1 value.
- * This seems really wasteful, especially since
- * the first decoding pass of each call is likely to
- * decode many bytes beyond that eof char that's all we
- * care about.
+ * Also rather bizarre, our caller can only notice an EOF
+ * condition if we return the value -1 as the number of chars
+ * read. This forces us to perform a 2-call dance where the
+ * first call can read all the chars up to the eof char, and
+ * the second call is solely for consuming the encoded eof
+ * char then pointed at by src so that we can return that
+ * magic -1 value. This seems really wasteful, especially
+ * since the first decoding pass of each call is likely to
+ * decode many bytes beyond that eof char that's all we care
+ * about.
*/
if (dstRead == 0) {
/*
- * Curious choice in the eof char handling. We leave
- * the eof char in the buffer. So, no need to compute
- * a proper srcRead value. At this point, there
- * are no chars before the eof char in the buffer.
+ * Curious choice in the eof char handling. We leave the
+ * eof char in the buffer. So, no need to compute a proper
+ * srcRead value. At this point, there are no chars before
+ * the eof char in the buffer.
*/
+
Tcl_SetObjLength(objPtr, numBytes);
return -1;
}
{
/*
- * There are chars leading the buffer before the eof
- * char. Adjust the dstLimit so we go back and read
- * only those and do not encounter the eof char this
- * time.
+ * There are chars leading the buffer before the eof char.
+ * Adjust the dstLimit so we go back and read only those
+ * and do not encounter the eof char this time.
*/
dstLimit = dstRead - 1 + TCL_UTF_MAX;
@@ -6167,10 +6209,9 @@ ReadChars(
}
/*
- * 2) The other way to read fewer bytes than are decoded
- * is when the final byte is \r and we're in a CRLF
- * translation mode so we cannot decide whether to
- * record \r or \n yet.
+ * 2) The other way to read fewer bytes than are decoded is when
+ * the final byte is \r and we're in a CRLF translation mode so
+ * we cannot decide whether to record \r or \n yet.
*/
assert(dst[dstRead] == '\r');
@@ -6178,10 +6219,10 @@ ReadChars(
if (dstWrote > 0) {
/*
- * There are chars we can read before we hit the bare cr.
- * Go back with a smaller dstLimit so we get them in the
- * next pass, compute a matching srcRead, and don't end
- * up back here in this call.
+ * There are chars we can read before we hit the bare CR. Go
+ * back with a smaller dstLimit so we get them in the next
+ * pass, compute a matching srcRead, and don't end up back
+ * here in this call.
*/
dstLimit = dstRead - 1 + TCL_UTF_MAX;
@@ -6195,9 +6236,9 @@ ReadChars(
assert(dstRead == 0);
/*
- * We decoded only the bare cr, and we cannot read a
- * translated char from that alone. We have to know what's
- * next. So why do we only have the one decoded char?
+ * We decoded only the bare CR, and we cannot read a translated
+ * char from that alone. We have to know what's next. So why do
+ * we only have the one decoded char?
*/
if (code != TCL_OK) {
@@ -6238,10 +6279,9 @@ ReadChars(
}
} else if (statePtr->flags & CHANNEL_EOF) {
-
/*
- * The bare \r is the only char and we will never read
- * a subsequent char to make the determination.
+ * The bare \r is the only char and we will never read a
+ * subsequent char to make the determination.
*/
dst[0] = '\r';
@@ -6251,8 +6291,8 @@ ReadChars(
}
/*
- * Revise the dstRead value so that the numChars calc
- * below correctly computes zero characters read.
+ * Revise the dstRead value so that the numChars calc below
+ * correctly computes zero characters read.
*/
dstRead = numChars;
@@ -6261,9 +6301,9 @@ ReadChars(
}
/*
- * The translation transformation can only reduce the number
- * of chars when it converts \r\n into \n. The reduction in
- * the number of chars is the difference in bytes read and written.
+ * The translation transformation can only reduce the number of chars
+ * when it converts \r\n into \n. The reduction in the number of chars
+ * is the difference in bytes read and written.
*/
numChars -= (dstRead - dstWrote);
@@ -6273,10 +6313,9 @@ ReadChars(
/*
* TODO: This cannot happen anymore.
*
- * We read more chars than allowed. Reset limits to
- * prevent that and try again. Don't forget the extra
- * padding of TCL_UTF_MAX bytes demanded by the
- * Tcl_ExternalToUtf() call!
+ * We read more chars than allowed. Reset limits to prevent that
+ * and try again. Don't forget the extra padding of TCL_UTF_MAX
+ * bytes demanded by the Tcl_ExternalToUtf() call!
*/
dstLimit = Tcl_UtfAtIndex(dst, charsToRead) - 1 + TCL_UTF_MAX - dst;
@@ -6289,18 +6328,19 @@ ReadChars(
if (dstWrote == 0) {
ChannelBuffer *nextPtr;
- /* We were not able to read any chars. */
+ /*
+ * We were not able to read any chars.
+ */
- assert (numChars == 0);
+ assert(numChars == 0);
/*
- * There is one situation where this is the correct final
- * result. If the src buffer contains only a single \n
- * byte, and we are in TCL_TRANSLATE_AUTO mode, and
- * when the translation pass was made the INPUT_SAW_CR
- * flag was set on the channel. In that case, the
- * correct behavior is to consume that \n and produce the
- * empty string.
+ * There is one situation where this is the correct final result.
+ * If the src buffer contains only a single \n byte, and we are in
+ * TCL_TRANSLATE_AUTO mode, and when the translation pass was made
+ * the INPUT_SAW_CR flag was set on the channel. In that case, the
+ * correct behavior is to consume that \n and produce the empty
+ * string.
*/
if (dstRead == 1 && dst[0] == '\n') {
@@ -6309,12 +6349,13 @@ ReadChars(
goto consume;
}
- /* Otherwise, reading zero characters indicates there's
- * something incomplete at the end of the src buffer.
- * Maybe there were not enough src bytes to decode into
- * a char. Maybe a lone \r could not be translated (crlf
- * mode). Need to combine any unused src bytes we have
- * in the first buffer with subsequent bytes to try again.
+ /*
+ * Otherwise, reading zero characters indicates there's something
+ * incomplete at the end of the src buffer. Maybe there were not
+ * enough src bytes to decode into a char. Maybe a lone \r could
+ * not be translated (crlf mode). Need to combine any unused src
+ * bytes we have in the first buffer with subsequent bytes to try
+ * again.
*/
nextPtr = bufPtr->nextPtr;
@@ -6329,15 +6370,15 @@ ReadChars(
/*
* Space is made at the beginning of the buffer to copy the
- * previous unused bytes there. Check first if the buffer we
- * are using actually has enough space at its beginning for
- * the data we are copying. Because if not we will write over
- * the buffer management information, especially the 'nextPtr'.
+ * previous unused bytes there. Check first if the buffer we are
+ * using actually has enough space at its beginning for the data
+ * we are copying. Because if not we will write over the buffer
+ * management information, especially the 'nextPtr'.
*
- * Note that the BUFFER_PADDING (See AllocChannelBuffer) is
- * used to prevent exactly this situation. I.e. it should never
- * happen. Therefore it is ok to panic should it happen despite
- * the precautions.
+ * Note that the BUFFER_PADDING (See AllocChannelBuffer) is used
+ * to prevent exactly this situation. I.e. it should never happen.
+ * Therefore it is ok to panic should it happen despite the
+ * precautions.
*/
if (nextPtr->nextRemoved - srcLen < 0) {
@@ -6356,10 +6397,12 @@ ReadChars(
consume:
bufPtr->nextRemoved += srcRead;
+
/*
- * If this read contained multibyte characters, revise factorPtr
- * so the next read will allocate bigger buffers.
+ * If this read contained multibyte characters, revise factorPtr so
+ * the next read will allocate bigger buffers.
*/
+
if (numChars && numChars < srcRead) {
*factorPtr = srcRead * UTF_EXPANSION_FACTOR / numChars;
}
@@ -6407,22 +6450,27 @@ TranslateInputEOL(
int inEofChar = statePtr->inEofChar;
/*
- * Depending on the translation mode in use, there's no need
- * to scan more srcLen bytes at srcStart than can possibly transform
- * to dstLen bytes. This keeps the scan for eof char below from
- * being pointlessly long.
+ * Depending on the translation mode in use, there's no need to scan more
+ * srcLen bytes at srcStart than can possibly transform to dstLen bytes.
+ * This keeps the scan for eof char below from being pointlessly long.
*/
switch (statePtr->inputTranslation) {
case TCL_TRANSLATE_LF:
case TCL_TRANSLATE_CR:
if (srcLen > dstLen) {
- /* In these modes, each src byte become a dst byte. */
+ /*
+ * In these modes, each src byte become a dst byte.
+ */
+
srcLen = dstLen;
}
break;
default:
- /* In other modes, at most 2 src bytes become a dst byte. */
+ /*
+ * In other modes, at most 2 src bytes become a dst byte.
+ */
+
if (srcLen/2 > dstLen) {
srcLen = 2 * dstLen;
}
@@ -6755,7 +6803,7 @@ GetInput(
* eofchar.
*/
- assert( !GotFlag(statePtr, CHANNEL_STICKY_EOF) );
+ assert(!GotFlag(statePtr, CHANNEL_STICKY_EOF));
/*
* Prevent reading from a dead channel -- a channel that has been closed
@@ -6769,24 +6817,21 @@ GetInput(
}
/*
- * WARNING: There was once a comment here claiming that it was
- * a bad idea to make another call to the inputproc of a channel
- * driver when EOF has already been detected on the channel. Through
- * much of Tcl's history, this warning was then completely negated
- * by having all (most?) read paths clear the EOF setting before
- * reaching here. So we had a guard that was never triggered.
+ * WARNING: There was once a comment here claiming that it was a bad idea
+ * to make another call to the inputproc of a channel driver when EOF has
+ * already been detected on the channel. Through much of Tcl's history,
+ * this warning was then completely negated by having all (most?) read
+ * paths clear the EOF setting before reaching here. So we had a guard
+ * that was never triggered.
+ *
+ * Don't be tempted to restore the guard. Even if EOF is set on the
+ * channel, continue through and call the inputproc again. This is the
+ * way to enable the ability to [read] again beyond the EOF, which seems a
+ * strange thing to do, but for which use cases exist [Tcl Bug 5adc350683]
+ * and which may even be essential for channels representing things like
+ * ttys or other devices where the stream might take the logical form of a
+ * series of 'files' separated by an EOF condition.
*
- * Don't be tempted to restore the guard. Even if EOF is set on
- * the channel, continue through and call the inputproc again. This
- * is the way to enable the ability to [read] again beyond the EOF,
- * which seems a strange thing to do, but for which use cases exist
- * [Tcl Bug 5adc350683] and which may even be essential for channels
- * representing things like ttys or other devices where the stream
- * might take the logical form of a series of 'files' separated by
- * an EOF condition.
- */
-
- /*
* First check for more buffers in the pushback area of the topmost
* channel in the stack and use them. They can be the result of a
* transformation which went away without reading all the information
@@ -6794,7 +6839,6 @@ GetInput(
*/
if (chanPtr->inQueueHead != NULL) {
-
/* TODO: Tests to cover this. */
assert(statePtr->inQueueHead == NULL);
@@ -6824,8 +6868,9 @@ GetInput(
/*
* Check the actual buffersize against the requested buffersize.
- * Saved buffers of the wrong size are squashed. This is done
- * to honor dynamic changes of the buffersize made by the user.
+ * Saved buffers of the wrong size are squashed. This is done to honor
+ * dynamic changes of the buffersize made by the user.
+ *
* TODO: Tests to cover this.
*/
@@ -7132,7 +7177,7 @@ Tcl_Tell(
* Truncate a channel to the given length.
*
* Results:
- * TCL_OK on success, TCL_ERROR if the operation failed (e.g. is not
+ * TCL_OK on success, TCL_ERROR if the operation failed (e.g., is not
* supported by the type of channel, or the underlying OS operation
* failed in some way).
*
@@ -9492,7 +9537,10 @@ CopyData(
}
if (size == 0) {
if (!GotFlag(inStatePtr, CHANNEL_NONBLOCKING)) {
- /* We allowed a short read. Keep trying. */
+ /*
+ * We allowed a short read. Keep trying.
+ */
+
continue;
}
if (bufObj != NULL) {
@@ -9706,7 +9754,7 @@ DoRead(
ChannelState *statePtr = chanPtr->state;
char *p = dst;
- assert (bytesToRead >= 0);
+ assert(bytesToRead >= 0);
/*
* Early out when we know a read will get the eofchar.
@@ -9722,15 +9770,18 @@ DoRead(
if (GotFlag(statePtr, CHANNEL_STICKY_EOF)) {
SetFlag(statePtr, CHANNEL_EOF);
- assert( statePtr->inputEncodingFlags & TCL_ENCODING_END );
- assert( !GotFlag(statePtr, CHANNEL_BLOCKED|INPUT_SAW_CR) );
+ assert(statePtr->inputEncodingFlags & TCL_ENCODING_END);
+ assert(!GotFlag(statePtr, CHANNEL_BLOCKED|INPUT_SAW_CR));
/* TODO: Don't need this call */
UpdateInterest(chanPtr);
return 0;
}
- /* Special handling for zero-char read request. */
+ /*
+ * Special handling for zero-char read request.
+ */
+
if (bytesToRead == 0) {
if (GotFlag(statePtr, CHANNEL_EOF)) {
statePtr->inputEncodingFlags |= TCL_ENCODING_START;
@@ -9745,8 +9796,8 @@ DoRead(
TclChannelPreserve((Tcl_Channel)chanPtr);
while (bytesToRead) {
/*
- * Each pass through the loop is intended to process up to
- * one channel buffer.
+ * Each pass through the loop is intended to process up to one channel
+ * buffer.
*/
int bytesRead, bytesWritten;
@@ -9758,33 +9809,39 @@ DoRead(
while (!bufPtr || /* We got no buffer! OR */
(!IsBufferFull(bufPtr) && /* Our buffer has room AND */
- (BytesLeft(bufPtr) < bytesToRead) ) ) {
- /* Not enough bytes in it
- * yet to fill the dst */
+ (BytesLeft(bufPtr) < bytesToRead))) {
+ /* Not enough bytes in it yet
+ * to fill the dst */
int code;
moreData:
code = GetInput(chanPtr);
bufPtr = statePtr->inQueueHead;
- assert (bufPtr != NULL);
+ assert(bufPtr != NULL);
if (GotFlag(statePtr, CHANNEL_EOF|CHANNEL_BLOCKED)) {
- /* Further reads cannot do any more */
+ /*
+ * Further reads cannot do any more.
+ */
+
break;
}
if (code) {
- /* Read error */
+ /*
+ * Read error
+ */
+
UpdateInterest(chanPtr);
TclChannelRelease((Tcl_Channel)chanPtr);
return -1;
}
- assert (IsBufferFull(bufPtr));
+ assert(IsBufferFull(bufPtr));
}
- assert (bufPtr != NULL);
+ assert(bufPtr != NULL);
bytesRead = BytesLeft(bufPtr);
bytesWritten = bytesToRead;
@@ -9799,8 +9856,8 @@ DoRead(
/*
* Buffer is not empty. How can that be?
*
- * 0) We stopped early because we got all the bytes
- * we were seeking. That's fine.
+ * 0) We stopped early because we got all the bytes we were
+ * seeking. That's fine.
*/
if (bytesToRead == 0) {
@@ -9816,8 +9873,8 @@ DoRead(
}
/*
- * 2) The buffer holds a \r while in CRLF translation,
- * followed by the end of the buffer.
+ * 2) The buffer holds a \r while in CRLF translation, followed by
+ * the end of the buffer.
*/
assert(statePtr->inputTranslation == TCL_TRANSLATE_CRLF);
@@ -9825,26 +9882,38 @@ DoRead(
assert(BytesLeft(bufPtr) == 1);
if (bufPtr->nextPtr == NULL) {
- /* There's no more buffered data.... */
+ /*
+ * There's no more buffered data...
+ */
if (statePtr->flags & CHANNEL_EOF) {
- /* ...and there never will be. */
+ /*
+ * ...and there never will be.
+ */
*p++ = '\r';
bytesToRead--;
bufPtr->nextRemoved++;
} else if (statePtr->flags & CHANNEL_BLOCKED) {
- /* ...and we cannot get more now. */
+ /*
+ * ...and we cannot get more now.
+ */
+
SetFlag(statePtr, CHANNEL_NEED_MORE_DATA);
break;
} else {
- /* ... so we need to get some. */
+ /*
+ * ...so we need to get some.
+ */
+
goto moreData;
}
}
if (bufPtr->nextPtr) {
- /* There's a next buffer. Shift orphan \r to it. */
+ /*
+ * There's a next buffer. Shift orphan \r to it.
+ */
ChannelBuffer *nextPtr = bufPtr->nextPtr;
@@ -9869,8 +9938,8 @@ DoRead(
}
/*
- * When there's no buffered data to read, and we're at EOF,
- * escape to the caller.
+ * When there's no buffered data to read, and we're at EOF, escape to
+ * the caller.
*/
if (GotFlag(statePtr, CHANNEL_EOF)
@@ -9882,11 +9951,11 @@ DoRead(
ResetFlag(statePtr, CHANNEL_BLOCKED);
}
- assert(!GotFlag(statePtr, CHANNEL_EOF)
- || GotFlag(statePtr, CHANNEL_STICKY_EOF)
- || Tcl_InputBuffered((Tcl_Channel)chanPtr) == 0);
- assert( !(GotFlag(statePtr, CHANNEL_EOF|CHANNEL_BLOCKED)
- == (CHANNEL_EOF|CHANNEL_BLOCKED)) );
+ assert(!GotFlag(statePtr, CHANNEL_EOF)
+ || GotFlag(statePtr, CHANNEL_STICKY_EOF)
+ || Tcl_InputBuffered((Tcl_Channel)chanPtr) == 0);
+ assert(!(GotFlag(statePtr, CHANNEL_EOF|CHANNEL_BLOCKED)
+ == (CHANNEL_EOF|CHANNEL_BLOCKED)));
UpdateInterest(chanPtr);
TclChannelRelease((Tcl_Channel)chanPtr);
return (int)(p - dst);
diff --git a/generic/tclIOCmd.c b/generic/tclIOCmd.c
index 1bd3fe7..6e8bd09 100644
--- a/generic/tclIOCmd.c
+++ b/generic/tclIOCmd.c
@@ -25,7 +25,7 @@ typedef struct AcceptCallback {
* It must be per-thread because of std channel limitations.
*/
-typedef struct ThreadSpecificData {
+typedef struct {
int initialized; /* Set to 1 when the module is initialized. */
Tcl_Obj *stdoutObjPtr; /* Cached stdout channel Tcl_Obj */
} ThreadSpecificData;
@@ -113,7 +113,6 @@ Tcl_PutsObjCmd(
int newline; /* Add a newline at end? */
int result; /* Result of puts operation. */
int mode; /* Mode in which channel is opened. */
- ThreadSpecificData *tsdPtr;
switch (objc) {
case 2: /* [puts $x] */
@@ -160,7 +159,7 @@ Tcl_PutsObjCmd(
}
if (chanObjPtr == NULL) {
- tsdPtr = TCL_TSD_INIT(&dataKey);
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (!tsdPtr->initialized) {
tsdPtr->initialized = 1;
@@ -1618,19 +1617,34 @@ Tcl_SocketObjCmd(
return TCL_ERROR;
}
- // Set the options to their default value if the user didn't override their
- // value.
- if (reusep == -1) reusep = 0;
- if (reusea == -1) reusea = 1;
+ /*
+ * Set the options to their default value if the user didn't override
+ * their value.
+ */
- // Build the bitset with the flags values.
- if (reusea)
+ if (reusep == -1) {
+ reusep = 0;
+ }
+ if (reusea == -1) {
+ reusea = 1;
+ }
+
+ /*
+ * Build the bitset with the flags values.
+ */
+
+ if (reusea) {
flags |= TCL_TCPSERVER_REUSEADDR;
- if (reusep)
+ }
+ if (reusep) {
flags |= TCL_TCPSERVER_REUSEPORT;
+ }
+
+ /*
+ * All the arguments should have been parsed by now, 'a' points to the
+ * last one, the port number.
+ */
- // All the arguments should have been parsed by now, 'a' points to the last
- // one, the port number.
if (a != objc-1) {
goto wrongNumArgs;
}
@@ -1638,15 +1652,14 @@ Tcl_SocketObjCmd(
port = TclGetString(objv[a]);
if (server) {
- AcceptCallback *acceptCallbackPtr =
- ckalloc(sizeof(AcceptCallback));
+ AcceptCallback *acceptCallbackPtr = ckalloc(sizeof(AcceptCallback));
Tcl_IncrRefCount(script);
acceptCallbackPtr->script = script;
acceptCallbackPtr->interp = interp;
- chan = Tcl_OpenTcpServerEx(interp, port, host, flags, AcceptCallbackProc,
- acceptCallbackPtr);
+ chan = Tcl_OpenTcpServerEx(interp, port, host, flags,
+ AcceptCallbackProc, acceptCallbackPtr);
if (chan == NULL) {
Tcl_DecrRefCount(script);
ckfree(acceptCallbackPtr);
diff --git a/generic/tclIORChan.c b/generic/tclIORChan.c
index 2fed3f4..aefa104 100644
--- a/generic/tclIORChan.c
+++ b/generic/tclIORChan.c
@@ -234,7 +234,7 @@ typedef enum {
* sharing problems.
*/
-typedef struct ForwardParamBase {
+typedef struct {
int code; /* O: Ok/Fail of the cmd handler */
char *msgStr; /* O: Error message for handler failure */
int mustFree; /* O: True if msgStr is allocated, false if
@@ -309,7 +309,7 @@ typedef struct ForwardingResult ForwardingResult;
* General event structure, with reference to operation specific data.
*/
-typedef struct ForwardingEvent {
+typedef struct {
Tcl_Event event; /* Basic event data, has to be first item */
ForwardingResult *resultPtr;
ForwardedOperation op; /* Forwarded driver operation */
@@ -346,7 +346,7 @@ struct ForwardingResult {
* results. */
};
-typedef struct ThreadSpecificData {
+typedef struct {
/*
* Table of all reflected channels owned by this thread. This is the
* per-thread version of the per-interpreter map.
@@ -723,7 +723,7 @@ TclChanCreateObjCmd(
Tcl_DecrRefCount(rcPtr->name);
Tcl_DecrRefCount(rcPtr->methods);
Tcl_DecrRefCount(rcPtr->cmd);
- ckfree((char*) rcPtr);
+ ckfree(rcPtr);
return TCL_ERROR;
#undef MODE
@@ -748,7 +748,7 @@ TclChanCreateObjCmd(
*----------------------------------------------------------------------
*/
-typedef struct ReflectEvent {
+typedef struct {
Tcl_Event header;
ReflectedChannel *rcPtr;
int events;
@@ -851,11 +851,12 @@ TclChanPostEventObjCmd(
}
/*
- * Note that the search above subsumes several of the older checks, namely:
+ * Note that the search above subsumes several of the older checks,
+ * namely:
*
- * (1) Does the channel handle refer to a reflected channel ?
+ * (1) Does the channel handle refer to a reflected channel?
* (2) Is the post event issued from the interpreter holding the handler
- * of the reflected channel ?
+ * of the reflected channel?
*
* A successful search answers yes to both. Because the map holds only
* handles of reflected channels, and only of such whose handler is
@@ -939,7 +940,8 @@ TclChanPostEventObjCmd(
(void) GetThreadReflectedChannelMap();
- /* XXX Race condition !!
+ /*
+ * XXX Race condition !!
* XXX The destination thread may not exist anymore already.
* XXX (Delayed postevent executed after channel got removed).
* XXX Can we detect this ? (check the validity of the owner threadid ?)
@@ -1221,8 +1223,8 @@ ReflectClose(
#endif
tctPtr = ((Channel *)rcPtr->chan)->typePtr;
if (tctPtr && tctPtr != &tclRChannelType) {
- ckfree(tctPtr);
- ((Channel *)rcPtr->chan)->typePtr = NULL;
+ ckfree(tctPtr);
+ ((Channel *)rcPtr->chan)->typePtr = NULL;
}
Tcl_EventuallyFree(rcPtr, (Tcl_FreeProc *) FreeReflectedChannel);
return (result == TCL_OK) ? EOK : EINVAL;
@@ -1272,7 +1274,10 @@ ReflectInput(
if (p.base.code != TCL_OK) {
if (p.base.code < 0) {
- /* No error message, this is an errno signal. */
+ /*
+ * No error message, this is an errno signal.
+ */
+
*errorCodePtr = -p.base.code;
} else {
PassReceivedError(rcPtr->chan, &p);
@@ -1375,7 +1380,10 @@ ReflectOutput(
if (p.base.code != TCL_OK) {
if (p.base.code < 0) {
- /* No error message, this is an errno signal. */
+ /*
+ * No error message, this is an errno signal.
+ */
+
*errorCodePtr = -p.base.code;
} else {
PassReceivedError(rcPtr->chan, &p);
@@ -1426,8 +1434,8 @@ ReflectOutput(
if ((written == 0) && (toWrite > 0)) {
/*
- * The handler claims to have written nothing of what it was
- * given. That is bad.
+ * The handler claims to have written nothing of what it was given.
+ * That is bad.
*/
SetChannelErrorStr(rcPtr->chan, msg_write_nothing);
@@ -2373,8 +2381,8 @@ InvokeTclMethod(
* None.
*
* Users:
- * ReflectInput/Output(), to enable the signaling of EAGAIN
- * on 0-sized short reads/writes.
+ * ReflectInput/Output(), to enable the signaling of EAGAIN on 0-sized
+ * short reads/writes.
*
*----------------------------------------------------------------------
*/
@@ -2560,7 +2568,10 @@ DeleteReflectedChannelMap(
evPtr = resultPtr->evPtr;
- /* Basic crash safety until this routine can get revised [3411310] */
+ /*
+ * Basic crash safety until this routine can get revised [3411310]
+ */
+
if (evPtr == NULL) {
continue;
}
@@ -2675,8 +2686,8 @@ DeleteThreadReflectedChannelMap(
/*
* Go through the list of pending results and cancel all whose events were
- * destined for this thread. While this is in progress we block any
- * other access to the list of pending results.
+ * destined for this thread. While this is in progress we block any other
+ * access to the list of pending results.
*/
Tcl_MutexLock(&rcForwardMutex);
@@ -2707,7 +2718,10 @@ DeleteThreadReflectedChannelMap(
evPtr = resultPtr->evPtr;
- /* Basic crash safety until this routine can get revised [3411310] */
+ /*
+ * Basic crash safety until this routine can get revised [3411310]
+ */
+
if (evPtr == NULL ) {
continue;
}
@@ -2761,8 +2775,8 @@ ForwardOpToHandlerThread(
const void *param) /* Arguments */
{
/*
- * Core of the communication from OWNER to HANDLER thread.
- * The receiver is ForwardProc() below.
+ * Core of the communication from OWNER to HANDLER thread. The receiver is
+ * ForwardProc() below.
*/
Tcl_ThreadId dst = rcPtr->thread;
@@ -2812,7 +2826,10 @@ ForwardOpToHandlerThread(
*/
TclSpliceIn(resultPtr, forwardList);
- /* Do not unlock here. That is done by the ConditionWait */
+
+ /*
+ * Do not unlock here. That is done by the ConditionWait.
+ */
/*
* Ensure cleanup of the event if the origin thread exits while this event
@@ -2888,7 +2905,7 @@ ForwardProc(
* Notes regarding access to the referenced data.
*
* In principle the data belongs to the originating thread (see
- * evPtr->src), however this thread is currently blocked at (*), i.e.
+ * evPtr->src), however this thread is currently blocked at (*), i.e.,
* quiescent. Because of this we can treat the data as belonging to us,
* without fear of race conditions. I.e. we can read and write as we like.
*
diff --git a/generic/tclIORTrans.c b/generic/tclIORTrans.c
index 8375926..f198c69 100644
--- a/generic/tclIORTrans.c
+++ b/generic/tclIORTrans.c
@@ -329,7 +329,7 @@ struct ForwardingResult {
* results. */
};
-typedef struct ThreadSpecificData {
+typedef struct {
/*
* Table of all reflected transformations owned by this thread.
*/
diff --git a/generic/tclIOSock.c b/generic/tclIOSock.c
index 8ad268a..6abfa60 100644
--- a/generic/tclIOSock.c
+++ b/generic/tclIOSock.c
@@ -12,16 +12,21 @@
#include "tclInt.h"
#if defined(_WIN32) && defined(UNICODE)
-/* On Windows, we need to do proper Unicode->UTF-8 conversion. */
+/*
+ * On Windows, we need to do proper Unicode->UTF-8 conversion.
+ */
-typedef struct ThreadSpecificData {
+typedef struct {
int initialized;
Tcl_DString errorMsg; /* UTF-8 encoded error-message */
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
#undef gai_strerror
-static const char *gai_strerror(int code) {
+static const char *
+gai_strerror(
+ int code)
+{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (tsdPtr->initialized) {
@@ -126,7 +131,7 @@ TclSockMinimumBuffers(
}
len = sizeof(int);
getsockopt((SOCKET)(size_t) sock, SOL_SOCKET, SO_RCVBUF,
- (char *) &current, &len);
+ (char *) &current, &len);
if (current < size) {
len = sizeof(int);
setsockopt((SOCKET)(size_t) sock, SOL_SOCKET, SO_RCVBUF,
@@ -215,7 +220,7 @@ TclCreateSocketAddress(
* We found some problems when using AI_ADDRCONFIG, e.g. on systems that
* have no networking besides the loopback interface and want to resolve
* localhost. See [Bugs 3385024, 3382419, 3382431]. As the advantage of
- * using AI_ADDRCONFIG in situations where it works, is probably low,
+ * using AI_ADDRCONFIG is probably low even in situations where it works,
* we'll leave it out for now. After all, it is just an optimisation.
*
* Missing on: OpenBSD, NetBSD.
@@ -300,16 +305,20 @@ TclCreateSocketAddress(
*
*----------------------------------------------------------------------
*/
-Tcl_Channel Tcl_OpenTcpServer(Tcl_Interp *interp, int port,
- const char *host, Tcl_TcpAcceptProc *acceptProc,
- ClientData callbackData)
+
+Tcl_Channel
+Tcl_OpenTcpServer(
+ Tcl_Interp *interp,
+ int port,
+ const char *host,
+ Tcl_TcpAcceptProc *acceptProc,
+ ClientData callbackData)
{
char portbuf[TCL_INTEGER_SPACE];
TclFormatInt(portbuf, port);
-
return Tcl_OpenTcpServerEx(interp, portbuf, host, TCL_TCPSERVER_REUSEADDR,
- acceptProc, callbackData);
+ acceptProc, callbackData);
}
/*
diff --git a/generic/tclIOUtil.c b/generic/tclIOUtil.c
index de5d62d..ea407ab 100644
--- a/generic/tclIOUtil.c
+++ b/generic/tclIOUtil.c
@@ -57,7 +57,7 @@ typedef struct FilesystemRecord {
* this information each time the corresponding epoch counter changes.
*/
-typedef struct ThreadSpecificData {
+typedef struct {
int initialized;
size_t cwdPathEpoch;
size_t filesystemEpoch;
@@ -611,6 +611,7 @@ FsRecacheFilesystemList(void)
while (toFree) {
FilesystemRecord *next = toFree->nextPtr;
+
toFree->fsPtr = NULL;
ckfree(toFree);
toFree = next;
@@ -672,7 +673,6 @@ TclFSEpoch(void)
return tsdPtr->filesystemEpoch;
}
-
/*
* If non-NULL, clientData is owned by us and must be freed later.
@@ -784,7 +784,9 @@ TclFinalizeFilesystem(void)
while (fsRecPtr != NULL) {
FilesystemRecord *tmpFsRecPtr = fsRecPtr->nextPtr;
- /* The native filesystem is static, so we don't free it. */
+ /*
+ * The native filesystem is static, so we don't free it.
+ */
if (fsRecPtr != &nativeFilesystemRecord) {
ckfree(fsRecPtr);
@@ -947,7 +949,7 @@ Tcl_FSRegister(
int
Tcl_FSUnregister(
- const Tcl_Filesystem *fsPtr) /* The filesystem record to remove. */
+ const Tcl_Filesystem *fsPtr)/* The filesystem record to remove. */
{
int retVal = TCL_ERROR;
FilesystemRecord *fsRecPtr;
@@ -1233,7 +1235,7 @@ FsAddMountsToGlobResult(
len--;
}
- len++; /* account for '/' in the mElt [Bug 1602539] */
+ len++; /* account for '/' in the mElt [Bug 1602539] */
mElt = TclNewFSPathObj(pathPtr, mount + len, mlen - len);
Tcl_ListObjAppendElement(NULL, resultPtr, mElt);
}
@@ -1403,7 +1405,7 @@ TclFSNormalizeToUniquePath(
* Call each of the "normalise path" functions in succession. This is a
* special case, in which if we have a native filesystem handler, we call
* it first. This is because the root of Tcl's filesystem is always a
- * native filesystem (i.e. '/' on unix is native).
+ * native filesystem (i.e., '/' on unix is native).
*/
firstFsRecPtr = FsGetFirstFilesystem();
@@ -1525,7 +1527,7 @@ TclGetOpenModeEx(
#define RW_MODES (O_RDONLY|O_WRONLY|O_RDWR)
/*
- * Check for the simpler fopen-like access modes (e.g. "r"). They are
+ * Check for the simpler fopen-like access modes (e.g., "r"). They are
* distinguished from the POSIX access modes by the presence of a
* lower-case first letter.
*/
@@ -2671,6 +2673,7 @@ Tcl_FSGetCwd(
fsRecPtr = fsRecPtr->nextPtr) {
ClientData retCd;
TclFSGetCwdProc2 *proc2;
+
if (fsRecPtr->fsPtr->getCwdProc == NULL) {
continue;
}
@@ -3143,8 +3146,8 @@ Tcl_FSLoadFile(
* Workaround for issue with modern HPUX which do allow the unlink (no ETXTBSY
* error) yet somehow trash some internal data structures which prevents the
* second and further shared libraries from getting properly loaded. Only the
- * first is ok. We try to get around the issue by not unlinking,
- * i.e. emulating the behaviour of the older HPUX which denied removal.
+ * first is ok. We try to get around the issue by not unlinking, i.e.,
+ * emulating the behaviour of the older HPUX which denied removal.
*
* Doing the unlink is also an issue within docker containers, whose AUFS
* bungles this as well, see
@@ -3162,28 +3165,30 @@ Tcl_FSLoadFile(
*/
int
-TclSkipUnlink (Tcl_Obj* shlibFile)
+TclSkipUnlink(
+ Tcl_Obj *shlibFile)
{
- /* Order of testing:
+ /*
+ * Order of testing:
* 1. On hpux we generally want to skip unlink in general
*
* Outside of hpux then:
- * 2. For a general user request (TCL_TEMPLOAD_NO_UNLINK present, non-empty, => int)
+ * 2. For a general user request (TCL_TEMPLOAD_NO_UNLINK present,
+ * non-empty, => int)
* 3. For general AUFS environment (statfs, if available).
*
* Ad 2: This variable can disable/override the AUFS detection, i.e. for
- * testing if a newer AUFS does not have the bug any more.
+ * testing if a newer AUFS does not have the bug any more.
*
- * Ad 3: This is conditionally compiled in. Condition currently must be set manually.
- * This part needs proper tests in the configure(.in).
+ * Ad 3: This is conditionally compiled in. Condition currently must be
+ * set manually. This part needs proper tests in the configure(.in).
*/
#ifdef hpux
return 1;
#else
- char* skipstr;
+ char *skipstr = getenv("TCL_TEMPLOAD_NO_UNLINK");
- skipstr = getenv ("TCL_TEMPLOAD_NO_UNLINK");
if (skipstr && (skipstr[0] != '\0')) {
return atoi(skipstr);
}
@@ -3192,7 +3197,8 @@ TclSkipUnlink (Tcl_Obj* shlibFile)
#ifndef NO_FSTATFS
{
struct statfs fs;
- /* Have fstatfs. May not have the AUFS super magic ... Indeed our build
+ /*
+ * Have fstatfs. May not have the AUFS super magic ... Indeed our build
* box is too old to have it directly in the headers. Define taken from
* http://mooon.googlecode.com/svn/trunk/linux_include/linux/aufs_type.h
* http://aufs.sourceforge.net/
@@ -3209,8 +3215,10 @@ TclSkipUnlink (Tcl_Obj* shlibFile)
#endif /* ... NO_FSTATFS */
#endif /* ... TCL_TEMPLOAD_NO_UNLINK */
- /* Fallback: !hpux, no EV override, no AUFS (detection, nor detected):
- * Don't skip */
+ /*
+ * Fallback: !hpux, no EV override, no AUFS (detection, nor detected):
+ * Don't skip
+ */
return 0;
#endif /* hpux */
}
@@ -3415,9 +3423,8 @@ Tcl_LoadFile(
* avoids any worries about leaving the copy laying around on exit.
*/
- if (
- !TclSkipUnlink (copyToPtr) &&
- (Tcl_FSDeleteFile(copyToPtr) == TCL_OK)) {
+ if (!TclSkipUnlink(copyToPtr) &&
+ (Tcl_FSDeleteFile(copyToPtr) == TCL_OK)) {
Tcl_DecrRefCount(copyToPtr);
/*
diff --git a/generic/tclInt.h b/generic/tclInt.h
index 1fbc541..d725688 100644
--- a/generic/tclInt.h
+++ b/generic/tclInt.h
@@ -1357,7 +1357,7 @@ MODULE_SCOPE void TclThreadDataKeySet(Tcl_ThreadDataKey *keyPtr,
*/
#define TCL_TSD_INIT(keyPtr) \
- (ThreadSpecificData *)Tcl_GetThreadData((keyPtr), sizeof(ThreadSpecificData))
+ Tcl_GetThreadData((keyPtr), sizeof(ThreadSpecificData))
/*
*----------------------------------------------------------------
diff --git a/generic/tclNamesp.c b/generic/tclNamesp.c
index 1e360d1..e1bad0e 100644
--- a/generic/tclNamesp.c
+++ b/generic/tclNamesp.c
@@ -31,7 +31,7 @@
* limited to a single interpreter.
*/
-typedef struct ThreadSpecificData {
+typedef struct {
size_t numNsCreated; /* Count of the number of namespaces created
* within the thread. This value is used as a
* unique id for each namespace. Cannot be
diff --git a/generic/tclObj.c b/generic/tclObj.c
index dfcaff0..f4b81f2 100644
--- a/generic/tclObj.c
+++ b/generic/tclObj.c
@@ -75,7 +75,7 @@ typedef struct ObjData {
* The structure defined below is used in this file only.
*/
-typedef struct ThreadSpecificData {
+typedef struct {
Tcl_HashTable *lineCLPtr; /* This table remembers for each Tcl_Obj
* generated by a call to the function
* TclSubstTokens() from a literal text
diff --git a/generic/tclRegexp.c b/generic/tclRegexp.c
index eb23f72..5f8dc20 100644
--- a/generic/tclRegexp.c
+++ b/generic/tclRegexp.c
@@ -64,7 +64,7 @@
#define NUM_REGEXPS 30
-typedef struct ThreadSpecificData {
+typedef struct {
int initialized; /* Set to 1 when the module is initialized. */
char *patterns[NUM_REGEXPS];/* Strings corresponding to compiled regular
* expression patterns. NULL means that this
@@ -679,7 +679,7 @@ TclRegAbout(
resultObj = Tcl_NewObj();
Tcl_ListObjAppendElement(NULL, resultObj,
- Tcl_NewIntObj((int) regexpPtr->re.re_nsub));
+ Tcl_NewWideIntObj((Tcl_WideInt) regexpPtr->re.re_nsub));
/*
* Now append a list of all the bit-flags set for the RE.
diff --git a/generic/tclStubInit.c b/generic/tclStubInit.c
index abb28ac..de29d2d 100644
--- a/generic/tclStubInit.c
+++ b/generic/tclStubInit.c
@@ -41,12 +41,12 @@
#undef Tcl_FindExecutable
#undef TclpGetPid
#undef TclSockMinimumBuffers
-#define TclBackgroundException Tcl_BackgroundException
#undef Tcl_SetIntObj
#undef TclpInetNtoa
#undef TclWinGetServByName
#undef TclWinGetSockOpt
#undef TclWinSetSockOpt
+#undef TclWinNToHS
/* See bug 510001: TclSockMinimumBuffers needs plat imp */
#if defined(_WIN64) || defined(TCL_NO_DEPRECATED)
@@ -64,6 +64,10 @@ static int TclSockMinimumBuffersOld(int sock, int size)
# define TclGetStartupScriptPath 0
# define TclSetStartupScriptFileName 0
# define TclGetStartupScriptFileName 0
+# define TclpInetNtoa 0
+# define TclWinGetServByName 0
+# define TclWinGetSockOpt 0
+# define TclWinSetSockOpt 0
# define TclWinNToHS 0
#else
#define TclSetStartupScriptPath setStartupScriptPath
@@ -351,6 +355,9 @@ static int formatInt(char *buffer, int n){
# define Tcl_EvalObj 0
# undef Tcl_GlobalEvalObj
# define Tcl_GlobalEvalObj 0
+# define TclBackgroundException 0
+# undef TclpReaddir
+# define TclpReaddir 0
# define TclSetStartupScript 0
# define TclGetStartupScript 0
# define TclCreateNamespace 0
@@ -376,6 +383,7 @@ static int formatInt(char *buffer, int n){
#else /* TCL_NO_DEPRECATED */
# define Tcl_SeekOld seekOld
# define Tcl_TellOld tellOld
+# define TclBackgroundException Tcl_BackgroundException
# define TclSetStartupScript Tcl_SetStartupScript
# define TclGetStartupScript Tcl_GetStartupScript
# define TclCreateNamespace Tcl_CreateNamespace
diff --git a/generic/tclTest.c b/generic/tclTest.c
index 0f019bb..547dc9a 100644
--- a/generic/tclTest.c
+++ b/generic/tclTest.c
@@ -67,6 +67,18 @@ typedef struct TestAsyncHandler {
/* Next is list of handlers. */
} TestAsyncHandler;
+/*
+ * Start of the socket driver state structure to acces field testFlags
+ */
+
+typedef struct TcpState TcpState;
+
+struct TcpState {
+ Tcl_Channel channel; /* Channel associated with this socket. */
+ int testFlags; /* bit field for tests. Is set by testsocket
+ * test procedure */
+};
+
TCL_DECLARE_MUTEX(asyncTestMutex)
static TestAsyncHandler *firstHandler = NULL;
@@ -364,6 +376,8 @@ static int TestChannelCmd(ClientData clientData,
Tcl_Interp *interp, int argc, const char **argv);
static int TestChannelEventCmd(ClientData clientData,
Tcl_Interp *interp, int argc, const char **argv);
+static int TestSocketCmd(ClientData clientData,
+ Tcl_Interp *interp, int argc, const char **argv);
static int TestFilesystemObjCmd(ClientData dummy,
Tcl_Interp *interp, int objc,
Tcl_Obj *const objv[]);
@@ -676,6 +690,8 @@ Tcltest_Init(
TestNumUtfCharsCmd, NULL, NULL);
Tcl_CreateCommand(interp, "testsetplatform", TestsetplatformCmd,
NULL, NULL);
+ Tcl_CreateCommand(interp, "testsocket", TestSocketCmd,
+ NULL, NULL);
Tcl_CreateCommand(interp, "teststaticpkg", TeststaticpkgCmd,
NULL, NULL);
Tcl_CreateCommand(interp, "testtranslatefilename",
@@ -6081,6 +6097,75 @@ TestChannelEventCmd(
/*
*----------------------------------------------------------------------
*
+ * TestSocketCmd --
+ *
+ * Implements the Tcl "testsocket" debugging command and its
+ * subcommands. This is part of the testing environment.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+static int
+TestSocketCmd(
+ ClientData clientData, /* Not used. */
+ Tcl_Interp *interp, /* Interpreter for result. */
+ int argc, /* Count of additional args. */
+ const char **argv) /* Additional arg strings. */
+{
+ const char *cmdName; /* Sub command. */
+ size_t len; /* Length of subcommand string. */
+
+ if (argc < 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " subcommand ?additional args..?\"", NULL);
+ return TCL_ERROR;
+ }
+ cmdName = argv[1];
+ len = strlen(cmdName);
+
+ if ((cmdName[0] == 't') && (strncmp(cmdName, "testflags", len) == 0)) {
+ Tcl_Channel hChannel;
+ int modePtr;
+ TcpState *statePtr;
+ /* Set test value in the socket driver
+ */
+ /* Check for argument "channel name"
+ */
+ if (argc < 4) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " testflags channel flags\"", NULL);
+ return TCL_ERROR;
+ }
+ hChannel = Tcl_GetChannel(interp, argv[2], &modePtr);
+ if ( NULL == hChannel ) {
+ Tcl_AppendResult(interp, "unknown channel:", argv[2], NULL);
+ return TCL_ERROR;
+ }
+ statePtr = (TcpState *)Tcl_GetChannelInstanceData(hChannel);
+ if ( NULL == statePtr) {
+ Tcl_AppendResult(interp, "No channel instance data:", argv[2],
+ NULL);
+ return TCL_ERROR;
+ }
+ statePtr->testFlags = atoi(argv[3]);
+ return TCL_OK;
+ }
+
+ Tcl_AppendResult(interp, "bad option \"", cmdName, "\": should be "
+ "testflags", NULL);
+ return TCL_ERROR;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* TestWrongNumArgsObjCmd --
*
* Test the Tcl_WrongNumArgs function.
diff --git a/generic/tclTimer.c b/generic/tclTimer.c
index 6d3938b..3467305 100644
--- a/generic/tclTimer.c
+++ b/generic/tclTimer.c
@@ -1053,11 +1053,17 @@ AfterDelay(
if (diff > TCL_TIME_MAXIMUM_SLICE) {
diff = TCL_TIME_MAXIMUM_SLICE;
}
- if (diff == 0 && TCL_TIME_BEFORE(now, endTime)) diff = 1;
+ if (diff == 0 && TCL_TIME_BEFORE(now, endTime)) {
+ diff = 1;
+ }
if (diff > 0) {
Tcl_Sleep((long) diff);
- if (diff < SLEEP_OFFLOAD_GETTIMEOFDAY) break;
- } else break;
+ if (diff < SLEEP_OFFLOAD_GETTIMEOFDAY) {
+ break;
+ }
+ } else {
+ break;
+ }
} else {
diff = TCL_TIME_DIFF_MS(iPtr->limit.time, now);
#ifndef TCL_WIDE_INT_IS_LONG
diff --git a/generic/tclUtil.c b/generic/tclUtil.c
index a4d523a..91cc3b4 100644
--- a/generic/tclUtil.c
+++ b/generic/tclUtil.c
@@ -3153,7 +3153,7 @@ Tcl_PrintDouble(
int signum;
char *digits;
char *end;
- int *precisionPtr = Tcl_GetThreadData(&precisionKey, (int) sizeof(int));
+ int *precisionPtr = Tcl_GetThreadData(&precisionKey, sizeof(int));
/*
* Handle NaN.
@@ -3326,7 +3326,7 @@ TclPrecTraceProc(
{
Tcl_Obj *value;
int prec;
- int *precisionPtr = Tcl_GetThreadData(&precisionKey, (int) sizeof(int));
+ int *precisionPtr = Tcl_GetThreadData(&precisionKey, sizeof(int));
/*
* If the variable is unset, then recreate the trace.
diff --git a/tests/socket.test b/tests/socket.test
index 80b0251..9a09c0f 100644
--- a/tests/socket.test
+++ b/tests/socket.test
@@ -60,8 +60,13 @@
# listening at port 2048. If all fails, a message is printed and the tests
# using the remote server are not performed.
-package require tcltest 2
-namespace import -force ::tcltest::*
+if {[lsearch [namespace children] ::tcltest] == -1} {
+ package require tcltest
+ namespace import -force ::tcltest::*
+}
+
+::tcltest::loadTestedCommands
+catch [list package require -exact Tcltest [info patchlevel]]
# Some tests require the Thread package or exec command
testConstraint thread [expr {0 == [catch {package require Thread 2.7-}]}]
@@ -71,6 +76,14 @@ testConstraint exec [llength [info commands exec]]
# from 49152 through 65535.
proc randport {} { expr {int(rand()*16383+49152)} }
+# Check if testsocket testflags is available
+testConstraint testsocket_testflags [expr {![catch {
+ set h [socket -async localhost [randport]]
+ testsocket testflags $h 0
+ close $h
+ }]}]
+
+
# Test the latency of tcp connections over the loopback interface. Some OSes
# (e.g. NetBSD) seem to use the Nagle algorithm and delayed ACKs, so it takes
# up to 200ms for a packet sent to localhost to arrive. We're measuring this
@@ -2266,12 +2279,17 @@ test socket-14.11.0 {pending [socket -async] and nonblocking [puts], no listener
unset x
} -result {socket is not connected} -returnCodes 1
test socket-14.11.1 {pending [socket -async] and nonblocking [puts], no listener, flush} \
- -constraints {socket nonPortable} \
+ -constraints {socket testsocket_testflags} \
-body {
set sock [socket -async localhost [randport]]
+ # Set the socket in async test mode.
+ # The async connect will not be continued on the following fconfigure
+ # and puts/flush. Thus, the connect will fail after them.
+ testsocket testflags $sock 1
fconfigure $sock -blocking 0
puts $sock ok
flush $sock
+ testsocket testflags $sock 0
fileevent $sock writable {set x 1}
vwait x
close $sock
diff --git a/unix/tclUnixSock.c b/unix/tclUnixSock.c
index 9387d05..b404080 100644
--- a/unix/tclUnixSock.c
+++ b/unix/tclUnixSock.c
@@ -19,6 +19,7 @@
#define SET_BITS(var, bits) ((var) |= (bits))
#define CLEAR_BITS(var, bits) ((var) &= ~(bits))
+#define GOT_BITS(var, bits) (((var) & (bits)) != 0)
/* "sock" + a pointer in hex + \0 */
#define SOCK_CHAN_LENGTH (4 + sizeof(void *) * 2 + 1)
@@ -52,6 +53,8 @@ typedef struct TcpFdList {
struct TcpState {
Tcl_Channel channel; /* Channel associated with this file. */
+ int testFlags; /* bit field for tests. Is set by testsocket
+ * test procedure */
TcpFdList fds; /* The file descriptors of the sockets. */
int flags; /* ORed combination of the bitfields defined
* below. */
@@ -93,6 +96,15 @@ struct TcpState {
#define TCP_ASYNC_FAILED (1<<5) /* An async connect finally failed */
/*
+ * These bits may be ORed together into the "testFlags" field of a TcpState
+ * structure.
+ */
+
+#define TCP_ASYNC_TEST_MODE (1<<0) /* Async testing activated. Do not
+ * automatically continue connection
+ * process. */
+
+/*
* The following defines the maximum length of the listen queue. This is the
* number of outstanding yet-to-be-serviced requests for a connection on a
* server socket, more than this number of outstanding requests and the
@@ -117,8 +129,7 @@ struct TcpState {
* Static routines for this file:
*/
-static int TcpConnect(Tcl_Interp *interp,
- TcpState *state);
+static int TcpConnect(Tcl_Interp *interp, TcpState *state);
static void TcpAccept(ClientData data, int mask);
static int TcpBlockModeProc(ClientData data, int mode);
static int TcpCloseProc(ClientData instanceData,
@@ -173,21 +184,24 @@ static ProcessGlobalValue hostName =
#if 0
/* printf debugging */
-void printaddrinfo(struct addrinfo *addrlist, char *prefix)
+void
+printaddrinfo(
+ struct addrinfo *addrlist,
+ char *prefix)
{
char host[NI_MAXHOST], port[NI_MAXSERV];
struct addrinfo *ai;
+
for (ai = addrlist; ai != NULL; ai = ai->ai_next) {
getnameinfo(ai->ai_addr, ai->ai_addrlen,
- host, sizeof(host),
- port, sizeof(port),
- NI_NUMERICHOST|NI_NUMERICSERV);
+ host, sizeof(host), port, sizeof(port),
+ NI_NUMERICHOST|NI_NUMERICSERV);
fprintf(stderr,"%s: %s:%s\n", prefix, host, port);
}
}
#endif
/*
- *----------------------------------------------------------------------
+ * ----------------------------------------------------------------------
*
* InitializeHostName --
*
@@ -197,7 +211,7 @@ void printaddrinfo(struct addrinfo *addrlist, char *prefix)
* Results:
* None.
*
- *----------------------------------------------------------------------
+ * ----------------------------------------------------------------------
*/
static void
@@ -276,7 +290,7 @@ InitializeHostName(
}
/*
- *----------------------------------------------------------------------
+ * ----------------------------------------------------------------------
*
* Tcl_GetHostName --
*
@@ -290,7 +304,7 @@ InitializeHostName(
* Side effects:
* Caches the name to return for future calls.
*
- *----------------------------------------------------------------------
+ * ----------------------------------------------------------------------
*/
const char *
@@ -300,7 +314,7 @@ Tcl_GetHostName(void)
}
/*
- *----------------------------------------------------------------------
+ * ----------------------------------------------------------------------
*
* TclpHasSockets --
*
@@ -312,7 +326,7 @@ Tcl_GetHostName(void)
* Side effects:
* None.
*
- *----------------------------------------------------------------------
+ * ----------------------------------------------------------------------
*/
int
@@ -323,7 +337,7 @@ TclpHasSockets(
}
/*
- *----------------------------------------------------------------------
+ * ----------------------------------------------------------------------
*
* TclpFinalizeSockets --
*
@@ -335,7 +349,7 @@ TclpHasSockets(
* Side effects:
* None.
*
- *----------------------------------------------------------------------
+ * ----------------------------------------------------------------------
*/
void
@@ -345,7 +359,7 @@ TclpFinalizeSockets(void)
}
/*
- *----------------------------------------------------------------------
+ * ----------------------------------------------------------------------
*
* TcpBlockModeProc --
*
@@ -358,7 +372,7 @@ TclpFinalizeSockets(void)
* Side effects:
* Sets the device into blocking or nonblocking mode.
*
- *----------------------------------------------------------------------
+ * ----------------------------------------------------------------------
*/
/* ARGSUSED */
@@ -376,7 +390,7 @@ TcpBlockModeProc(
} else {
SET_BITS(statePtr->flags, TCP_NONBLOCKING);
}
- if (statePtr->flags & TCP_ASYNC_CONNECT) {
+ if (GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT)) {
statePtr->cachedBlocking = mode;
return 0;
}
@@ -387,33 +401,32 @@ TcpBlockModeProc(
}
/*
- *----------------------------------------------------------------------
+ * ----------------------------------------------------------------------
*
* WaitForConnect --
*
- * Check the state of an async connect process. If a connection
- * attempt terminated, process it, which may finalize it or may
- * start the next attempt. If a connect error occures, it is saved
- * in statePtr->connectError to be reported by 'fconfigure -error'.
+ * Check the state of an async connect process. If a connection attempt
+ * terminated, process it, which may finalize it or may start the next
+ * attempt. If a connect error occures, it is saved in
+ * statePtr->connectError to be reported by 'fconfigure -error'.
*
* There are two modes of operation, defined by errorCodePtr:
- * * non-NULL: Called by explicite read/write command. block if
+ * * non-NULL: Called by explicite read/write command. Blocks if the
* socket is blocking.
* May return two error codes:
* * EWOULDBLOCK: if connect is still in progress
- * * ENOTCONN: if connect failed. This would be the error
- * message of a rect or sendto syscall so this is
- * emulated here.
- * * NULL: Called by a backround operation. Do not block and
- * don't return any error code.
+ * * ENOTCONN: if connect failed. This would be the error message
+ * of a rect or sendto syscall so this is emulated here.
+ * * NULL: Called by a backround operation. Do not block and do not
+ * return any error code.
*
* Results:
- * 0 if the connection has completed, -1 if still in progress
- * or there is an error.
+ * 0 if the connection has completed, -1 if still in progress or there is
+ * an error.
*
* Side effects:
- * Processes socket events off the system queue.
- * May process asynchroneous connect.
+ * Processes socket events off the system queue. May process
+ * asynchroneous connects.
*
*----------------------------------------------------------------------
*/
@@ -426,11 +439,11 @@ WaitForConnect(
int timeout;
/*
- * Check if an async connect failed already and error reporting is demanded,
- * return the error ENOTCONN
+ * Check if an async connect failed already and error reporting is
+ * demanded, return the error ENOTCONN
*/
- if (errorCodePtr != NULL && (statePtr->flags & TCP_ASYNC_FAILED)) {
+ if (errorCodePtr != NULL && GOT_BITS(statePtr->flags, TCP_ASYNC_FAILED)) {
*errorCodePtr = ENOTCONN;
return -1;
}
@@ -439,26 +452,43 @@ WaitForConnect(
* Check if an async connect is running. If not return ok
*/
- if (!(statePtr->flags & TCP_ASYNC_PENDING)) {
+ if (!GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)) {
return 0;
}
- if (errorCodePtr == NULL || (statePtr->flags & TCP_NONBLOCKING)) {
+ /*
+ * In socket test mode do not continue with the connect.
+ * Exceptions are:
+ * - Call by recv/send and blocking socket
+ * (errorCodePtr != NULL && !GOT_BITS(flags, TCP_NONBLOCKING))
+ */
+
+ if (GOT_BITS(statePtr->testFlags, TCP_ASYNC_TEST_MODE)
+ && !(errorCodePtr != NULL
+ && !GOT_BITS(statePtr->flags, TCP_NONBLOCKING))) {
+ *errorCodePtr = EWOULDBLOCK;
+ return -1;
+ }
+
+ if (errorCodePtr == NULL || GOT_BITS(statePtr->flags, TCP_NONBLOCKING)) {
timeout = 0;
} else {
timeout = -1;
}
do {
if (TclUnixWaitForFile(statePtr->fds.fd,
- TCL_WRITABLE | TCL_EXCEPTION, timeout) != 0) {
+ TCL_WRITABLE | TCL_EXCEPTION, timeout) != 0) {
TcpConnect(NULL, statePtr);
}
- /* Do this only once in the nonblocking case and repeat it until the
- * socket is final when blocking */
- } while (timeout == -1 && statePtr->flags & TCP_ASYNC_CONNECT);
+
+ /*
+ * Do this only once in the nonblocking case and repeat it until the
+ * socket is final when blocking.
+ */
+ } while (timeout == -1 && GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT));
if (errorCodePtr != NULL) {
- if (statePtr->flags & TCP_ASYNC_PENDING) {
+ if (GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)) {
*errorCodePtr = EAGAIN;
return -1;
} else if (statePtr->connectError != 0) {
@@ -615,6 +645,7 @@ TcpCloseProc(
fds = statePtr->fds.next;
while (fds != NULL) {
TcpFdList *next = fds->next;
+
ckfree(fds);
fds = next;
}
@@ -685,10 +716,9 @@ TcpClose2Proc(
*
* TcpHostPortList --
*
- * This function is called by the -gethostname and -getpeername
- * switches of TcpGetOptionProc() to add three list elements
- * with the textual representation of the given address to the
- * given DString.
+ * This function is called by the -gethostname and -getpeername switches
+ * of TcpGetOptionProc() to add three list elements with the textual
+ * representation of the given address to the given DString.
*
* Results:
* None.
@@ -709,22 +739,22 @@ TcpHostPortList(
char host[NI_MAXHOST], nhost[NI_MAXHOST], nport[NI_MAXSERV];
int flags = 0;
- getnameinfo(&addr.sa, salen,
- nhost, sizeof(nhost), nport, sizeof(nport),
- NI_NUMERICHOST | NI_NUMERICSERV);
+ getnameinfo(&addr.sa, salen, nhost, sizeof(nhost), nport, sizeof(nport),
+ NI_NUMERICHOST | NI_NUMERICSERV);
Tcl_DStringAppendElement(dsPtr, nhost);
+
/*
- * We don't want to resolve INADDR_ANY and sin6addr_any; they
- * can sometimes cause problems (and never have a name).
+ * We don't want to resolve INADDR_ANY and sin6addr_any; they can
+ * sometimes cause problems (and never have a name).
*/
+
if (addr.sa.sa_family == AF_INET) {
if (addr.sa4.sin_addr.s_addr == INADDR_ANY) {
flags |= NI_NUMERICHOST;
}
#ifndef NEED_FAKE_RFC2553
} else if (addr.sa.sa_family == AF_INET6) {
- if ((IN6_ARE_ADDR_EQUAL(&addr.sa6.sin6_addr,
- &in6addr_any))
+ if ((IN6_ARE_ADDR_EQUAL(&addr.sa6.sin6_addr, &in6addr_any))
|| (IN6_IS_ADDR_V4MAPPED(&addr.sa6.sin6_addr) &&
addr.sa6.sin6_addr.s6_addr[12] == 0 &&
addr.sa6.sin6_addr.s6_addr[13] == 0 &&
@@ -734,15 +764,27 @@ TcpHostPortList(
}
#endif /* NEED_FAKE_RFC2553 */
}
- /* Check if reverse DNS has been switched off globally */
- if (interp != NULL && Tcl_GetVar2(interp, SUPPRESS_RDNS_VAR, NULL, 0) != NULL) {
+
+ /*
+ * Check if reverse DNS has been switched off globally.
+ */
+
+ if (interp != NULL &&
+ Tcl_GetVar2(interp, SUPPRESS_RDNS_VAR, NULL, 0) != NULL) {
flags |= NI_NUMERICHOST;
}
- if (getnameinfo(&addr.sa, salen, host, sizeof(host), NULL, 0, flags) == 0) {
- /* Reverse mapping worked */
+ if (getnameinfo(&addr.sa, salen, host, sizeof(host), NULL, 0,
+ flags) == 0) {
+ /*
+ * Reverse mapping worked.
+ */
+
Tcl_DStringAppendElement(dsPtr, host);
} else {
- /* Reverse mappong failed - use the numeric rep once more */
+ /*
+ * Reverse mapping failed - use the numeric rep once more.
+ */
+
Tcl_DStringAppendElement(dsPtr, nhost);
}
Tcl_DStringAppendElement(dsPtr, nport);
@@ -792,16 +834,20 @@ TcpGetOptionProc(
(strncmp(optionName, "-error", len) == 0)) {
socklen_t optlen = sizeof(int);
- if (statePtr->flags & TCP_ASYNC_CONNECT) {
- /* Suppress errors as long as we are not done */
+ if (GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT)) {
+ /*
+ * Suppress errors as long as we are not done.
+ */
+
errno = 0;
} else if (statePtr->connectError != 0) {
errno = statePtr->connectError;
statePtr->connectError = 0;
} else {
int err;
- getsockopt(statePtr->fds.fd, SOL_SOCKET, SO_ERROR,
- (char *) &err, &optlen);
+
+ getsockopt(statePtr->fds.fd, SOL_SOCKET, SO_ERROR, (char *) &err,
+ &optlen);
errno = err;
}
if (errno != 0) {
@@ -812,9 +858,8 @@ TcpGetOptionProc(
if ((len > 1) && (optionName[1] == 'c') &&
(strncmp(optionName, "-connecting", len) == 0)) {
-
Tcl_DStringAppend(dsPtr,
- (statePtr->flags & TCP_ASYNC_CONNECT) ? "1" : "0", -1);
+ GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT) ? "1" : "0", -1);
return TCL_OK;
}
@@ -823,10 +868,11 @@ TcpGetOptionProc(
address peername;
socklen_t size = sizeof(peername);
- if ( (statePtr->flags & TCP_ASYNC_CONNECT) ) {
+ if (GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT)) {
/*
* In async connect output an empty string
*/
+
if (len == 0) {
Tcl_DStringAppendElement(dsPtr, "-peername");
Tcl_DStringAppendElement(dsPtr, "");
@@ -837,6 +883,7 @@ TcpGetOptionProc(
/*
* Peername fetch succeeded - output list
*/
+
if (len == 0) {
Tcl_DStringAppendElement(dsPtr, "-peername");
Tcl_DStringStartSublist(dsPtr);
@@ -876,11 +923,12 @@ TcpGetOptionProc(
Tcl_DStringAppendElement(dsPtr, "-sockname");
Tcl_DStringStartSublist(dsPtr);
}
- if ( (statePtr->flags & TCP_ASYNC_CONNECT) ) {
+ if (GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT)) {
/*
* In async connect output an empty string
*/
- found = 1;
+
+ found = 1;
} else {
for (fds = &statePtr->fds; fds != NULL; fds = fds->next) {
size = sizeof(sockname);
@@ -905,14 +953,15 @@ TcpGetOptionProc(
}
if (len > 0) {
- return Tcl_BadChannelOption(interp, optionName, "connecting peername sockname");
+ return Tcl_BadChannelOption(interp, optionName,
+ "connecting peername sockname");
}
return TCL_OK;
}
/*
- *----------------------------------------------------------------------
+ * ----------------------------------------------------------------------
*
* TcpWatchProc --
*
@@ -925,7 +974,7 @@ TcpGetOptionProc(
* Sets up the notifier so that a future event on the channel will be
* seen by Tcl.
*
- *----------------------------------------------------------------------
+ * ----------------------------------------------------------------------
*/
static void
@@ -938,17 +987,17 @@ WrapNotify(
if (newmask == 0) {
/*
- * There was no overlap between the states the channel is
- * interested in notifications for, and the states that are
- * reported present on the file descriptor by select(). The
- * only way that can happen is when the channel is interested
- * in a writable condition, and only a readable state is reported
- * present (see TcpWatchProc() below). In that case, signal back
- * to the caller the writable state, which is really an error
- * condition. As an extra check on that assumption, check for
- * a non-zero value of errno before reporting an artificial
+ * There was no overlap between the states the channel is interested
+ * in notifications for, and the states that are reported present on
+ * the file descriptor by select(). The only way that can happen is
+ * when the channel is interested in a writable condition, and only a
+ * readable state is reported present (see TcpWatchProc() below). In
+ * that case, signal back to the caller the writable state, which is
+ * really an error condition. As an extra check on that assumption,
+ * check for a non-zero value of errno before reporting an artificial
* writable state.
*/
+
if (errno == 0) {
return;
}
@@ -972,33 +1021,36 @@ TcpWatchProc(
* be readable or writable at the Tcl level. This keeps Tcl scripts
* from interfering with the -accept behavior (bug #3394732).
*/
+
return;
}
- if (statePtr->flags & TCP_ASYNC_PENDING) {
- /* Async sockets use a FileHandler internally while connecting, so we
- * need to cache this request until the connection has succeeded. */
+ if (GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)) {
+ /*
+ * Async sockets use a FileHandler internally while connecting, so we
+ * need to cache this request until the connection has succeeded.
+ */
+
statePtr->filehandlers = mask;
} else if (mask) {
/*
- * Whether it is a bug or feature or otherwise, it is a fact
- * of life that on at least some Linux kernels select() fails
- * to report that a socket file descriptor is writable when
- * the other end of the socket is closed. This is in contrast
- * to the guarantees Tcl makes that its channels become
- * writable and fire writable events on an error conditon.
- * This has caused a leak of file descriptors in a state of
+ * Whether it is a bug or feature or otherwise, it is a fact of life
+ * that on at least some Linux kernels select() fails to report that a
+ * socket file descriptor is writable when the other end of the socket
+ * is closed. This is in contrast to the guarantees Tcl makes that
+ * its channels become writable and fire writable events on an error
+ * conditon. This has caused a leak of file descriptors in a state of
* background flushing. See Tcl ticket 1758a0b603.
*
- * As a workaround, when our caller indicates an interest in
- * writable notifications, we must tell the notifier built
- * around select() that we are interested in the readable state
- * of the file descriptor as well, as that is the only reliable
- * means to get notified of error conditions. Then it is the
- * task of WrapNotify() above to untangle the meaning of these
- * channel states and report the chan events as best it can.
- * We save a copy of the mask passed in to assist with that.
+ * As a workaround, when our caller indicates an interest in writable
+ * notifications, we must tell the notifier built around select() that
+ * we are interested in the readable state of the file descriptor as
+ * well, as that is the only reliable means to get notified of error
+ * conditions. Then it is the task of WrapNotify() above to untangle
+ * the meaning of these channel states and report the chan events as
+ * best it can. We save a copy of the mask passed in to assist with
+ * that.
*/
statePtr->interest = mask;
@@ -1010,7 +1062,7 @@ TcpWatchProc(
}
/*
- *----------------------------------------------------------------------
+ * ----------------------------------------------------------------------
*
* TcpGetHandleProc --
*
@@ -1024,7 +1076,7 @@ TcpWatchProc(
* Side effects:
* None.
*
- *----------------------------------------------------------------------
+ * ----------------------------------------------------------------------
*/
/* ARGSUSED */
@@ -1041,16 +1093,17 @@ TcpGetHandleProc(
}
/*
- *----------------------------------------------------------------------
+ * ----------------------------------------------------------------------
*
* TcpAsyncCallback --
*
- * Called by the event handler that TcpConnect sets up
- * internally for [socket -async] to get notified when the
- * asyncronous connection attempt has succeeded or failed.
+ * Called by the event handler that TcpConnect sets up internally for
+ * [socket -async] to get notified when the asyncronous connection
+ * attempt has succeeded or failed.
*
- *----------------------------------------------------------------------
+ * ----------------------------------------------------------------------
*/
+
static void
TcpAsyncCallback(
ClientData clientData, /* The socket state. */
@@ -1062,7 +1115,7 @@ TcpAsyncCallback(
}
/*
- *----------------------------------------------------------------------
+ * ----------------------------------------------------------------------
*
* TcpConnect --
*
@@ -1088,7 +1141,7 @@ TcpAsyncCallback(
* return and the loops resume as if they had never been interrupted.
* For syncronously connecting sockets, the loops work the usual way.
*
- *----------------------------------------------------------------------
+ * ----------------------------------------------------------------------
*/
static int
@@ -1097,9 +1150,9 @@ TcpConnect(
TcpState *statePtr)
{
socklen_t optlen;
- int async_callback = statePtr->flags & TCP_ASYNC_PENDING;
+ int async_callback = GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING);
int ret = -1, error = EHOSTUNREACH;
- int async = statePtr->flags & TCP_ASYNC_CONNECT;
+ int async = GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT);
if (async_callback) {
goto reenter;
@@ -1107,8 +1160,8 @@ TcpConnect(
for (statePtr->addr = statePtr->addrlist; statePtr->addr != NULL;
statePtr->addr = statePtr->addr->ai_next) {
-
- for (statePtr->myaddr = statePtr->myaddrlist; statePtr->myaddr != NULL;
+ for (statePtr->myaddr = statePtr->myaddrlist;
+ statePtr->myaddr != NULL;
statePtr->myaddr = statePtr->myaddr->ai_next) {
int reuseaddr = 1;
@@ -1132,7 +1185,8 @@ TcpConnect(
errno = 0;
}
- statePtr->fds.fd = socket(statePtr->addr->ai_family, SOCK_STREAM, 0);
+ statePtr->fds.fd = socket(statePtr->addr->ai_family, SOCK_STREAM,
+ 0);
if (statePtr->fds.fd < 0) {
continue;
}
@@ -1151,14 +1205,18 @@ TcpConnect(
TclSockMinimumBuffers(INT2PTR(statePtr->fds.fd), SOCKET_BUFSIZE);
if (async) {
- ret = TclUnixSetBlockingMode(statePtr->fds.fd,TCL_MODE_NONBLOCKING);
+ ret = TclUnixSetBlockingMode(statePtr->fds.fd,
+ TCL_MODE_NONBLOCKING);
if (ret < 0) {
continue;
}
}
- /* Gotta reset the error variable here, before we use it for the
- * first time in this iteration. */
+ /*
+ * Must reset the error variable here, before we use it for the
+ * first time in this iteration.
+ */
+
error = 0;
(void) setsockopt(statePtr->fds.fd, SOL_SOCKET, SO_REUSEADDR,
@@ -1179,10 +1237,13 @@ TcpConnect(
ret = connect(statePtr->fds.fd, statePtr->addr->ai_addr,
statePtr->addr->ai_addrlen);
- if (ret < 0) error = errno;
+ if (ret < 0) {
+ error = errno;
+ }
if (ret < 0 && errno == EINPROGRESS) {
Tcl_CreateFileHandler(statePtr->fds.fd,
- TCL_WRITABLE|TCL_EXCEPTION, TcpAsyncCallback, statePtr);
+ TCL_WRITABLE | TCL_EXCEPTION, TcpAsyncCallback,
+ statePtr);
errno = EWOULDBLOCK;
SET_BITS(statePtr->flags, TCP_ASYNC_PENDING);
return TCL_OK;
@@ -1210,7 +1271,7 @@ TcpConnect(
}
}
-out:
+ out:
statePtr->connectError = error;
CLEAR_BITS(statePtr->flags, TCP_ASYNC_CONNECT);
if (async_callback) {
@@ -1308,6 +1369,7 @@ Tcl_OpenTcpClient(
/*
* Allocate a new TcpState for this socket.
*/
+
statePtr = ckalloc(sizeof(TcpState));
memset(statePtr, 0, sizeof(TcpState));
statePtr->flags = async ? TCP_ASYNC_CONNECT : 0;
@@ -1319,6 +1381,7 @@ Tcl_OpenTcpClient(
/*
* Create a new client socket and wrap it in a channel.
*/
+
if (TcpConnect(interp, statePtr) != TCL_OK) {
TcpCloseProc(statePtr, NULL);
return NULL;
@@ -1326,8 +1389,8 @@ Tcl_OpenTcpClient(
sprintf(channelName, SOCK_TEMPLATE, (long) statePtr);
- statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, statePtr,
- (TCL_READABLE | TCL_WRITABLE));
+ statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
+ statePtr, TCL_READABLE | TCL_WRITABLE);
if (Tcl_SetChannelOption(interp, statePtr->channel, "-translation",
"auto crlf") == TCL_ERROR) {
Tcl_Close(NULL, statePtr->channel);
@@ -1356,7 +1419,8 @@ Tcl_Channel
Tcl_MakeTcpClientChannel(
ClientData sock) /* The socket to wrap up into a channel. */
{
- return (Tcl_Channel) TclpMakeTcpClientChannelMode(sock, (TCL_READABLE | TCL_WRITABLE));
+ return (Tcl_Channel) TclpMakeTcpClientChannelMode(sock,
+ TCL_READABLE | TCL_WRITABLE);
}
/*
@@ -1456,6 +1520,7 @@ Tcl_OpenTcpServerEx(
* families. We try this at most MAXRETRY times to avoid an endless loop
* if all ports are taken.
*/
+
int retry = 0;
#define MAXRETRY 10
@@ -1481,7 +1546,8 @@ Tcl_OpenTcpServerEx(
goto error;
}
- if (!TclCreateSocketAddress(interp, &addrlist, myHost, port, 1, &errorMsg)) {
+ if (!TclCreateSocketAddress(interp, &addrlist, myHost, port, 1,
+ &errorMsg)) {
my_errno = errno;
goto error;
}
@@ -1514,24 +1580,25 @@ Tcl_OpenTcpServerEx(
* Set up to reuse server addresses and/or ports if requested.
*/
- if (flags & TCL_TCPSERVER_REUSEADDR) {
+ if (GOT_BITS(flags, TCL_TCPSERVER_REUSEADDR)) {
optvalue = 1;
(void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
- (char *) &optvalue, sizeof(optvalue));
+ (char *) &optvalue, sizeof(optvalue));
}
- if (flags & TCL_TCPSERVER_REUSEPORT) {
+ if (GOT_BITS(flags, TCL_TCPSERVER_REUSEPORT)) {
#ifndef SO_REUSEPORT
/*
- * If the platform doesn't support the SO_REUSEPORT flag we can't do
- * much beside erroring out.
+ * If the platform doesn't support the SO_REUSEPORT flag we can't
+ * do much beside erroring out.
*/
+
errorMsg = "SO_REUSEPORT isn't supported by this platform";
goto error;
#else
optvalue = 1;
(void) setsockopt(sock, SOL_SOCKET, SO_REUSEPORT,
- (char *) &optvalue, sizeof(optvalue));
+ (char *) &optvalue, sizeof(optvalue));
#endif
}
@@ -1549,7 +1616,10 @@ Tcl_OpenTcpServerEx(
}
#ifdef IPV6_V6ONLY
- /* Missing on: Solaris 2.8 */
+ /*
+ * Missing on: Solaris 2.8
+ */
+
if (addrPtr->ai_family == AF_INET6) {
int v6only = 1;
@@ -1701,7 +1771,7 @@ TcpAccept(
sprintf(channelName, SOCK_TEMPLATE, (long) newSockState);
newSockState->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
- newSockState, (TCL_READABLE | TCL_WRITABLE));
+ newSockState, TCL_READABLE | TCL_WRITABLE);
Tcl_SetChannelOption(NULL, newSockState->channel, "-translation",
"auto crlf");
diff --git a/unix/tclUnixThrd.c b/unix/tclUnixThrd.c
index 805599d..f475aed 100644
--- a/unix/tclUnixThrd.c
+++ b/unix/tclUnixThrd.c
@@ -644,6 +644,7 @@ TclpFinalizeCondition(
*----------------------------------------------------------------------
*/
+#ifndef TCL_NO_DEPRECATED
Tcl_DirEntry *
TclpReaddir(
DIR * dir)
@@ -666,6 +667,7 @@ TclpInetNtoa(
return inet_ntoa(addr);
#endif
}
+#endif /* TCL_NO_DEPRECATED */
#ifdef TCL_THREADS
/*
diff --git a/win/tclWinSock.c b/win/tclWinSock.c
index 5e0d7c8..ee6be96 100644
--- a/win/tclWinSock.c
+++ b/win/tclWinSock.c
@@ -69,6 +69,7 @@
#define SET_BITS(var, bits) ((var) |= (bits))
#define CLEAR_BITS(var, bits) ((var) &= ~(bits))
+#define GOT_BITS(var, bits) (((var) & (bits)) != 0)
/* "sock" + a pointer in hex + \0 */
#define SOCK_CHAN_LENGTH (4 + sizeof(void *) * 2 + 1)
@@ -124,6 +125,8 @@ typedef struct TcpFdList {
struct TcpState {
Tcl_Channel channel; /* Channel associated with this socket. */
+ int testFlags; /* bit field for tests. Is set by testsocket
+ * test procedure */
struct TcpFdList *sockets; /* Windows SOCKET handle. */
int flags; /* Bit field comprised of the flags described
* below. */
@@ -184,6 +187,15 @@ struct TcpState {
#define TCP_ASYNC_FAILED (1<<5) /* An async connect finally failed */
/*
+ * These bits may be ORed together into the "testFlags" field of a TcpState
+ * structure.
+ */
+
+#define TCP_ASYNC_TEST_MODE (1<<0) /* Async testing activated. Do not
+ * automatically continue connection
+ * process */
+
+/*
* The following structure is what is added to the Tcl event queue when a
* socket event occurs.
*/
@@ -292,22 +304,39 @@ static const Tcl_ChannelType tcpChannelType = {
static TclInitProcessGlobalValueProc InitializeHostName;
static ProcessGlobalValue hostName =
{0, 0, NULL, NULL, InitializeHostName, NULL, NULL};
+
+/*
+ * Simple wrapper round the SendMessage syscall.
+ */
+
+#define SendSelectMessage(tsdPtr, message, payload) \
+ SendMessage((tsdPtr)->hwnd, SOCKET_SELECT, \
+ (WPARAM) (message), (LPARAM) (payload))
+
/*
* Address print debug functions
*/
#if 0
-void printaddrinfo(struct addrinfo *ai, char *prefix)
+void
+printaddrinfo(
+ struct addrinfo *ai,
+ char *prefix)
{
char host[NI_MAXHOST], port[NI_MAXSERV];
+
getnameinfo(ai->ai_addr, ai->ai_addrlen,
- host, sizeof(host),
- port, sizeof(port),
- NI_NUMERICHOST|NI_NUMERICSERV);
+ host, sizeof(host), port, sizeof(port),
+ NI_NUMERICHOST|NI_NUMERICSERV);
}
-void printaddrinfolist(struct addrinfo *addrlist, char *prefix)
+
+void
+printaddrinfolist(
+ struct addrinfo *addrlist,
+ char *prefix)
{
struct addrinfo *ai;
+
for (ai = addrlist; ai != NULL; ai = ai->ai_next) {
printaddrinfo(ai, prefix);
}
@@ -524,9 +553,9 @@ TcpBlockModeProc(
TcpState *statePtr = instanceData;
if (mode == TCL_MODE_NONBLOCKING) {
- statePtr->flags |= TCP_NONBLOCKING;
+ SET_BITS(statePtr->flags, TCP_NONBLOCKING);
} else {
- statePtr->flags &= ~(TCP_NONBLOCKING);
+ CLEAR_BITS(statePtr->flags, TCP_NONBLOCKING);
}
return 0;
}
@@ -536,29 +565,28 @@ TcpBlockModeProc(
*
* WaitForConnect --
*
- * Check the state of an async connect process. If a connection
- * attempt terminated, process it, which may finalize it or may
- * start the next attempt. If a connect error occures, it is saved
- * in statePtr->connectError to be reported by 'fconfigure -error'.
+ * Check the state of an async connect process. If a connection attempt
+ * terminated, process it, which may finalize it or may start the next
+ * attempt. If a connect error occures, it is saved in
+ * statePtr->connectError to be reported by 'fconfigure -error'.
*
* There are two modes of operation, defined by errorCodePtr:
- * * non-NULL: Called by explicite read/write command. block if
- * socket is blocking.
+ * * non-NULL: Called by explicite read/write command. Block if socket
+ * is blocking.
* May return two error codes:
* * EWOULDBLOCK: if connect is still in progress
- * * ENOTCONN: if connect failed. This would be the error
- * message of a rect or sendto syscall so this is
- * emulated here.
- * * Null: Called by a backround operation. Do not block and
- * don't return any error code.
+ * * ENOTCONN: if connect failed. This would be the error message
+ * of a rect or sendto syscall so this is emulated here.
+ * * Null: Called by a backround operation. Do not block and don't
+ * return any error code.
*
* Results:
- * 0 if the connection has completed, -1 if still in progress
- * or there is an error.
+ * 0 if the connection has completed, -1 if still in progress or there is
+ * an error.
*
* Side effects:
- * Processes socket events off the system queue.
- * May process asynchroneous connect.
+ * Processes socket events off the system queue. May process
+ * asynchroneous connect.
*
*----------------------------------------------------------------------
*/
@@ -566,20 +594,19 @@ TcpBlockModeProc(
static int
WaitForConnect(
TcpState *statePtr, /* State of the socket. */
- int *errorCodePtr) /* Where to store errors?
- * A passed null-pointer activates background mode.
- */
+ int *errorCodePtr) /* Where to store errors? A passed
+ * null-pointer activates background mode. */
{
int result;
int oldMode;
ThreadSpecificData *tsdPtr;
/*
- * Check if an async connect failed already and error reporting is demanded,
- * return the error ENOTCONN
+ * Check if an async connect failed already and error reporting is
+ * demanded, return the error ENOTCONN.
*/
- if (errorCodePtr != NULL && (statePtr->flags & TCP_ASYNC_FAILED)) {
+ if (errorCodePtr != NULL && GOT_BITS(statePtr->flags, TCP_ASYNC_FAILED)) {
*errorCodePtr = ENOTCONN;
return -1;
}
@@ -588,11 +615,26 @@ WaitForConnect(
* Check if an async connect is running. If not return ok
*/
- if (!(statePtr->flags & TCP_ASYNC_CONNECT)) {
+ if (!GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT)) {
return 0;
}
/*
+ * In socket test mode do not continue with the connect
+ * Exceptions are:
+ * - Call by recv/send and blocking socket
+ * (errorCodePtr != NULL && !GOT_BITS(flags, TCP_NONBLOCKING))
+ * - Call by the event queue (errorCodePtr == NULL)
+ */
+
+ if (GOT_BITS(statePtr->testFlags, TCP_ASYNC_TEST_MODE)
+ && errorCodePtr != NULL
+ && GOT_BITS(statePtr->flags, TCP_NONBLOCKING)) {
+ *errorCodePtr = EWOULDBLOCK;
+ return -1;
+ }
+
+ /*
* Be sure to disable event servicing so we are truly modal.
*/
@@ -603,36 +645,51 @@ WaitForConnect(
*/
while (1) {
+ /*
+ * Get the statePtr lock.
+ */
- /* get statePtr lock */
tsdPtr = TclThreadDataKeyGet(&dataKey);
WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
- /* Check for connect event */
- if (statePtr->readyEvents & FD_CONNECT) {
+ /*
+ * Check for connect event.
+ */
+
+ if (GOT_BITS(statePtr->readyEvents, FD_CONNECT)) {
+ /*
+ * Consume the connect event.
+ */
- /* Consume the connect event */
- statePtr->readyEvents &= ~(FD_CONNECT);
+ CLEAR_BITS(statePtr->readyEvents, FD_CONNECT);
/*
- * For blocking sockets and foreground processing
- * disable async connect as we continue now synchoneously
+ * For blocking sockets and foreground processing, disable async
+ * connect as we continue now synchoneously.
*/
- if ( errorCodePtr != NULL &&
- ! (statePtr->flags & TCP_NONBLOCKING) ) {
+
+ if (errorCodePtr != NULL &&
+ !GOT_BITS(statePtr->flags, TCP_NONBLOCKING)) {
CLEAR_BITS(statePtr->flags, TCP_ASYNC_CONNECT);
}
- /* Free list lock */
+ /*
+ * Free list lock.
+ */
+
SetEvent(tsdPtr->socketListLock);
/*
- * Continue connect.
- * If switched to synchroneous connect, the connect is terminated.
+ * Continue connect. If switched to synchroneous connect, the
+ * connect is terminated.
*/
+
result = TcpConnect(NULL, statePtr);
- /* Restore event service mode */
+ /*
+ * Restore event service mode.
+ */
+
(void) Tcl_SetServiceMode(oldMode);
/*
@@ -641,10 +698,11 @@ WaitForConnect(
if (result == TCL_OK) {
/*
- * Check for async connect restart
- * (not possible for foreground blocking operation)
+ * Check for async connect restart (not possible for
+ * foreground blocking operation)
*/
- if ( statePtr->flags & TCP_ASYNC_PENDING ) {
+
+ if (GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)) {
if (errorCodePtr != NULL) {
*errorCodePtr = EWOULDBLOCK;
}
@@ -654,8 +712,8 @@ WaitForConnect(
}
/*
- * Connect finally failed.
- * For foreground operation return ENOTCONN.
+ * Connect finally failed. For foreground operation return
+ * ENOTCONN.
*/
if (errorCodePtr != NULL) {
@@ -664,7 +722,10 @@ WaitForConnect(
return -1;
}
- /* Free list lock */
+ /*
+ * Free list lock.
+ */
+
SetEvent(tsdPtr->socketListLock);
/*
@@ -672,16 +733,16 @@ WaitForConnect(
* event
*/
- if ( errorCodePtr == NULL ) {
+ if (errorCodePtr == NULL) {
return -1;
}
/*
- * A non blocking socket waiting for an asyncronous connect
- * returns directly the error EWOULDBLOCK
+ * A non blocking socket waiting for an asyncronous connect returns
+ * directly the error EWOULDBLOCK.
*/
- if (statePtr->flags & TCP_NONBLOCKING) {
+ if (GOT_BITS(statePtr->flags, TCP_NONBLOCKING)) {
*errorCodePtr = EWOULDBLOCK;
return -1;
}
@@ -745,7 +806,7 @@ TcpInputProc(
* socket stack after the first time EOF is detected.
*/
- if (statePtr->flags & SOCKET_EOF) {
+ if (GOT_BITS(statePtr->flags, SOCKET_EOF)) {
return 0;
}
@@ -768,18 +829,22 @@ TcpInputProc(
*/
while (1) {
- SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
- (WPARAM) UNSELECT, (LPARAM) statePtr);
- /* single fd operation: this proc is only called for a connected socket. */
+ SendSelectMessage(tsdPtr, UNSELECT, statePtr);
+
+ /*
+ * Single fd operation: this proc is only called for a connected
+ * socket.
+ */
+
bytesRead = recv(statePtr->sockets->fd, buf, bufSize, 0);
- statePtr->readyEvents &= ~(FD_READ);
+ CLEAR_BITS(statePtr->readyEvents, FD_READ);
/*
* Check for end-of-file condition or successful read.
*/
if (bytesRead == 0) {
- statePtr->flags |= SOCKET_EOF;
+ SET_BITS(statePtr->flags, SOCKET_EOF);
}
if (bytesRead != SOCKET_ERROR) {
break;
@@ -790,8 +855,8 @@ TcpInputProc(
* error and report an EOF.
*/
- if (statePtr->readyEvents & FD_CLOSE) {
- statePtr->flags |= SOCKET_EOF;
+ if (GOT_BITS(statePtr->readyEvents, FD_CLOSE)) {
+ SET_BITS(statePtr->flags, SOCKET_EOF);
bytesRead = 0;
break;
}
@@ -804,7 +869,7 @@ TcpInputProc(
*/
if (error == WSAECONNRESET) {
- statePtr->flags |= SOCKET_EOF;
+ SET_BITS(statePtr->flags, SOCKET_EOF);
bytesRead = 0;
break;
}
@@ -813,7 +878,8 @@ TcpInputProc(
* Check for error condition or underflow in non-blocking case.
*/
- if ((statePtr->flags & TCP_NONBLOCKING) || (error != WSAEWOULDBLOCK)) {
+ if (GOT_BITS(statePtr->flags, TCP_NONBLOCKING)
+ || (error != WSAEWOULDBLOCK)) {
TclWinConvertError(error);
*errorCodePtr = Tcl_GetErrno();
bytesRead = -1;
@@ -831,7 +897,7 @@ TcpInputProc(
}
}
- SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM)SELECT, (LPARAM)statePtr);
+ SendSelectMessage(tsdPtr, SELECT, statePtr);
return bytesRead;
}
@@ -889,10 +955,13 @@ TcpOutputProc(
}
while (1) {
- SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
- (WPARAM) UNSELECT, (LPARAM) statePtr);
+ SendSelectMessage(tsdPtr, UNSELECT, statePtr);
+
+ /*
+ * Single fd operation: this proc is only called for a connected
+ * socket.
+ */
- /* single fd operation: this proc is only called for a connected socket. */
written = send(statePtr->sockets->fd, buf, toWrite, 0);
if (written != SOCKET_ERROR) {
/*
@@ -901,8 +970,9 @@ TcpOutputProc(
* until the condition changes.
*/
- if (statePtr->watchEvents & FD_WRITE) {
+ if (GOT_BITS(statePtr->watchEvents, FD_WRITE)) {
Tcl_Time blockTime = { 0, 0 };
+
Tcl_SetMaxBlockTime(&blockTime);
}
break;
@@ -917,8 +987,8 @@ TcpOutputProc(
error = WSAGetLastError();
if (error == WSAEWOULDBLOCK) {
- statePtr->readyEvents &= ~(FD_WRITE);
- if (statePtr->flags & TCP_NONBLOCKING) {
+ CLEAR_BITS(statePtr->readyEvents, FD_WRITE);
+ if (GOT_BITS(statePtr->flags, TCP_NONBLOCKING)) {
*errorCodePtr = EWOULDBLOCK;
written = -1;
break;
@@ -941,7 +1011,7 @@ TcpOutputProc(
}
}
- SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM)SELECT, (LPARAM)statePtr);
+ SendSelectMessage(tsdPtr, SELECT, statePtr);
return written;
}
@@ -988,10 +1058,10 @@ TcpCloseProc(
* background.
*/
- while ( statePtr->sockets != NULL ) {
+ while (statePtr->sockets != NULL) {
TcpFdList *thisfd = statePtr->sockets;
- statePtr->sockets = thisfd->next;
+ statePtr->sockets = thisfd->next;
if (closesocket(thisfd->fd) == SOCKET_ERROR) {
TclWinConvertError((DWORD) WSAGetLastError());
errorCode = Tcl_GetErrno();
@@ -1009,18 +1079,25 @@ TcpCloseProc(
/*
* Clear an eventual tsd info list pointer.
+ *
* This may be called, if an async socket connect fails or is closed
* between connect and thread action callback.
*/
+
if (tsdPtr->pendingTcpState != NULL
&& tsdPtr->pendingTcpState == statePtr) {
+ /*
+ * Get infoPtr lock, because this concerns the notifier thread.
+ */
- /* get infoPtr lock, because this concerns the notifier thread */
WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
tsdPtr->pendingTcpState = NULL;
- /* Free list lock */
+ /*
+ * Free list lock.
+ */
+
SetEvent(tsdPtr->socketListLock);
}
@@ -1081,8 +1158,11 @@ TcpClose2Proc(
return TCL_ERROR;
}
- /* single fd operation: Tcl_OpenTcpServer() does not set TCL_READABLE or
- * TCL_WRITABLE so this should never be called for a server socket. */
+ /*
+ * Single fd operation: Tcl_OpenTcpServer() does not set TCL_READABLE or
+ * TCL_WRITABLE so this should never be called for a server socket.
+ */
+
if (shutdown(statePtr->sockets->fd, sd) == SOCKET_ERROR) {
TclWinConvertError((DWORD) WSAGetLastError());
errorCode = Tcl_GetErrno();
@@ -1134,7 +1214,7 @@ TcpSetOptionProc(
}
#ifdef TCL_FEATURE_KEEPALIVE_NAGLE
- #error "TCL_FEATURE_KEEPALIVE_NAGLE not reviewed for whether to treat statePtr->sockets as single fd or list"
+#error "TCL_FEATURE_KEEPALIVE_NAGLE not reviewed for whether to treat statePtr->sockets as single fd or list"
sock = statePtr->sockets->fd;
if (!strcasecmp(optionName, "-keepalive")) {
@@ -1243,9 +1323,14 @@ TcpGetOptionProc(
/*
* Go one step in async connect
- * If any error is thrown save it as backround error to report eventually below
+ *
+ * If any error is thrown save it as backround error to report eventually
+ * below.
*/
- WaitForConnect(statePtr, NULL);
+
+ if (!GOT_BITS(statePtr->testFlags, TCP_ASYNC_TEST_MODE)) {
+ WaitForConnect(statePtr, NULL);
+ }
sock = statePtr->sockets->fd;
if (optionName != NULL) {
@@ -1254,31 +1339,26 @@ TcpGetOptionProc(
if ((len > 1) && (optionName[1] == 'e') &&
(strncmp(optionName, "-error", len) == 0)) {
-
/*
- * Do not return any errors if async connect is running
- */
- if ( ! (statePtr->flags & TCP_ASYNC_PENDING) ) {
-
-
- if ( statePtr->flags & TCP_ASYNC_FAILED ) {
+ * Do not return any errors if async connect is running.
+ */
+ if (!GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)) {
+ if (GOT_BITS(statePtr->flags, TCP_ASYNC_FAILED)) {
/*
* In case of a failed async connect, eventually report the
- * connect error only once.
- * Do not report the system error, as this comes again and again.
+ * connect error only once. Do not report the system error,
+ * as this comes again and again.
*/
- if ( statePtr->connectError != 0 ) {
+ if (statePtr->connectError != 0) {
Tcl_DStringAppend(dsPtr,
Tcl_ErrnoMsg(statePtr->connectError), -1);
statePtr->connectError = 0;
}
-
} else {
-
/*
- * Report an eventual last error of the socket system
+ * Report an eventual last error of the socket system.
*/
int optlen;
@@ -1286,24 +1366,30 @@ TcpGetOptionProc(
DWORD err;
/*
- * Populater the err Variable with a possix error
+ * Populate the err variable with a POSIX error
*/
+
optlen = sizeof(int);
ret = getsockopt(sock, SOL_SOCKET, SO_ERROR,
(char *)&err, &optlen);
+
/*
- * The error was not returned directly but should be
- * taken from WSA
+ * The error was not returned directly but should be taken
+ * from WSA.
*/
+
if (ret == SOCKET_ERROR) {
err = WSAGetLastError();
}
+
/*
- * Return error message
+ * Return error message.
*/
+
if (err) {
TclWinConvertError(err);
- Tcl_DStringAppend(dsPtr, Tcl_ErrnoMsg(Tcl_GetErrno()), -1);
+ Tcl_DStringAppend(dsPtr, Tcl_ErrnoMsg(Tcl_GetErrno()),
+ -1);
}
}
}
@@ -1312,14 +1398,14 @@ TcpGetOptionProc(
if ((len > 1) && (optionName[1] == 'c') &&
(strncmp(optionName, "-connecting", len) == 0)) {
-
Tcl_DStringAppend(dsPtr,
- (statePtr->flags & TCP_ASYNC_PENDING)
+ GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)
? "1" : "0", -1);
return TCL_OK;
}
- if (interp != NULL && Tcl_GetVar2(interp, SUPPRESS_RDNS_VAR, NULL, 0) != NULL) {
+ if (interp != NULL
+ && Tcl_GetVar2(interp, SUPPRESS_RDNS_VAR, NULL, 0) != NULL) {
reverseDNS = NI_NUMERICHOST;
}
@@ -1328,20 +1414,23 @@ TcpGetOptionProc(
address peername;
socklen_t size = sizeof(peername);
- if ( (statePtr->flags & TCP_ASYNC_PENDING) ) {
+ if (GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)) {
/*
* In async connect output an empty string
*/
+
if (len == 0) {
Tcl_DStringAppendElement(dsPtr, "-peername");
Tcl_DStringAppendElement(dsPtr, "");
} else {
return TCL_OK;
}
- } else if ( getpeername(sock, (LPSOCKADDR) &(peername.sa), &size) == 0) {
+ } else if (getpeername(sock, (LPSOCKADDR) &(peername.sa),
+ &size) == 0) {
/*
* Peername fetch succeeded - output list
*/
+
if (len == 0) {
Tcl_DStringAppendElement(dsPtr, "-peername");
Tcl_DStringStartSublist(dsPtr);
@@ -1390,11 +1479,12 @@ TcpGetOptionProc(
Tcl_DStringAppendElement(dsPtr, "-sockname");
Tcl_DStringStartSublist(dsPtr);
}
- if ( (statePtr->flags & TCP_ASYNC_PENDING ) ) {
+ if (GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)) {
/*
* In async connect output an empty string
*/
- found = 1;
+
+ found = 1;
} else {
for (fds = statePtr->sockets; fds != NULL; fds = fds->next) {
sock = fds->fd;
@@ -1408,9 +1498,11 @@ TcpGetOptionProc(
Tcl_DStringAppendElement(dsPtr, host);
/*
- * We don't want to resolve INADDR_ANY and sin6addr_any; they
- * can sometimes cause problems (and never have a name).
+ * We don't want to resolve INADDR_ANY and sin6addr_any;
+ * they can sometimes cause problems (and never have a
+ * name).
*/
+
flags |= NI_NUMERICSERV;
if (sockname.sa.sa_family == AF_INET) {
if (sockname.sa4.sin_addr.s_addr == INADDR_ANY) {
@@ -1494,7 +1586,8 @@ TcpGetOptionProc(
return Tcl_BadChannelOption(interp, optionName,
"connecting peername sockname keepalive nagle");
#else
- return Tcl_BadChannelOption(interp, optionName, "connecting peername sockname");
+ return Tcl_BadChannelOption(interp, optionName,
+ "connecting peername sockname");
#endif /*TCL_FEATURE_KEEPALIVE_NAGLE*/
}
@@ -1535,11 +1628,11 @@ TcpWatchProc(
if (!statePtr->acceptProc) {
statePtr->watchEvents = 0;
- if (mask & TCL_READABLE) {
- statePtr->watchEvents |= (FD_READ|FD_CLOSE);
+ if (GOT_BITS(mask, TCL_READABLE)) {
+ SET_BITS(statePtr->watchEvents, FD_READ | FD_CLOSE);
}
- if (mask & TCL_WRITABLE) {
- statePtr->watchEvents |= (FD_WRITE|FD_CLOSE);
+ if (GOT_BITS(mask, TCL_WRITABLE)) {
+ SET_BITS(statePtr->watchEvents, FD_WRITE | FD_CLOSE);
}
/*
@@ -1630,13 +1723,13 @@ TcpConnect(
TcpState *statePtr)
{
DWORD error;
- /*
- * We are started with async connect and the connect notification
- * was not jet received
- */
- int async_connect = statePtr->flags & TCP_ASYNC_CONNECT;
- /* We were called by the event procedure and continue our loop */
- int async_callback = statePtr->flags & TCP_ASYNC_PENDING;
+ int async_connect = GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT);
+ /* We are started with async connect and the
+ * connect notification was not yet
+ * received. */
+ int async_callback = GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING);
+ /* We were called by the event procedure and
+ * continue our loop. */
ThreadSpecificData *tsdPtr = TclThreadDataKeyGet(&dataKey);
if (async_callback) {
@@ -1644,11 +1737,10 @@ TcpConnect(
}
for (statePtr->addr = statePtr->addrlist; statePtr->addr != NULL;
- statePtr->addr = statePtr->addr->ai_next) {
-
- for (statePtr->myaddr = statePtr->myaddrlist; statePtr->myaddr != NULL;
- statePtr->myaddr = statePtr->myaddr->ai_next) {
-
+ statePtr->addr = statePtr->addr->ai_next) {
+ for (statePtr->myaddr = statePtr->myaddrlist;
+ statePtr->myaddr != NULL;
+ statePtr->myaddr = statePtr->myaddr->ai_next) {
/*
* No need to try combinations of local and remote addresses
* of different families.
@@ -1662,25 +1754,37 @@ TcpConnect(
* Close the socket if it is still open from the last unsuccessful
* iteration.
*/
+
if (statePtr->sockets->fd != INVALID_SOCKET) {
closesocket(statePtr->sockets->fd);
}
- /* get statePtr lock */
+ /*
+ * Get statePtr lock.
+ */
+
WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
/*
* Reset last error from last try
*/
+
statePtr->notifierConnectError = 0;
Tcl_SetErrno(0);
- statePtr->sockets->fd = socket(statePtr->myaddr->ai_family, SOCK_STREAM, 0);
+ statePtr->sockets->fd = socket(statePtr->myaddr->ai_family,
+ SOCK_STREAM, 0);
+
+ /*
+ * Free list lock.
+ */
- /* Free list lock */
SetEvent(tsdPtr->socketListLock);
- /* continue on socket creation error */
+ /*
+ * Continue on socket creation error.
+ */
+
if (statePtr->sockets->fd == INVALID_SOCKET) {
TclWinConvertError((DWORD) WSAGetLastError());
continue;
@@ -1691,31 +1795,39 @@ TcpConnect(
* processes by default. Turn off the inherit bit.
*/
- SetHandleInformation((HANDLE) statePtr->sockets->fd, HANDLE_FLAG_INHERIT, 0);
+ SetHandleInformation((HANDLE) statePtr->sockets->fd,
+ HANDLE_FLAG_INHERIT, 0);
/*
* Set kernel space buffering
*/
- TclSockMinimumBuffers((void *) statePtr->sockets->fd, TCP_BUFFER_SIZE);
+ TclSockMinimumBuffers((void *) statePtr->sockets->fd,
+ TCP_BUFFER_SIZE);
/*
* Try to bind to a local port.
*/
if (bind(statePtr->sockets->fd, statePtr->myaddr->ai_addr,
- statePtr->myaddr->ai_addrlen) == SOCKET_ERROR) {
+ statePtr->myaddr->ai_addrlen) == SOCKET_ERROR) {
TclWinConvertError((DWORD) WSAGetLastError());
continue;
}
+
/*
* For asyncroneous connect set the socket in nonblocking mode
* and activate connect notification
*/
+
if (async_connect) {
TcpState *statePtr2;
int in_socket_list = 0;
- /* get statePtr lock */
+
+ /*
+ * Get statePtr lock.
+ */
+
WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
/*
@@ -1725,8 +1837,8 @@ TcpConnect(
* It is set after this call by TcpThreadActionProc and is set
* on a second round.
*
- * If not, we buffer my statePtr in the tsd memory so it is not
- * lost by the event procedure
+ * If not, we buffer my statePtr in the tsd memory so it is
+ * not lost by the event procedure
*/
for (statePtr2 = tsdPtr->socketList; statePtr2 != NULL;
@@ -1739,21 +1851,27 @@ TcpConnect(
if (!in_socket_list) {
tsdPtr->pendingTcpState = statePtr;
}
+
/*
* Set connect mask to connect events
- * This is activated by a SOCKET_SELECT message to the notifier
- * thread.
+ *
+ * This is activated by a SOCKET_SELECT message to the
+ * notifier thread.
*/
- statePtr->selectEvents |= FD_CONNECT;
+
+ SET_BITS(statePtr->selectEvents, FD_CONNECT);
/*
- * Free list lock
+ * Free list lock.
*/
+
SetEvent(tsdPtr->socketListLock);
- /* activate accept notification */
- SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT,
- (LPARAM) statePtr);
+ /*
+ * Activate accept notification.
+ */
+
+ SendSelectMessage(tsdPtr, SELECT, statePtr);
}
/*
@@ -1769,12 +1887,11 @@ TcpConnect(
if (async_connect && error == WSAEWOULDBLOCK) {
/*
* Asynchroneous connect
- */
-
- /*
+ *
* Remember that we jump back behind this next round
*/
- statePtr->flags |= TCP_ASYNC_PENDING;
+
+ SET_BITS(statePtr->flags, TCP_ASYNC_PENDING);
return TCL_OK;
reenter:
@@ -1784,21 +1901,39 @@ TcpConnect(
*
* Clear the reenter flag
*/
- statePtr->flags &= ~(TCP_ASYNC_PENDING);
- /* get statePtr lock */
+
+ CLEAR_BITS(statePtr->flags, TCP_ASYNC_PENDING);
+
+ /*
+ * Get statePtr lock.
+ */
+
WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
- /* Get signaled connect error */
+
+ /*
+ * Get signaled connect error.
+ */
+
TclWinConvertError((DWORD) statePtr->notifierConnectError);
- /* Clear eventual connect flag */
- statePtr->selectEvents &= ~(FD_CONNECT);
- /* Free list lock */
+
+ /*
+ * Clear eventual connect flag.
+ */
+
+ CLEAR_BITS(statePtr->selectEvents, FD_CONNECT);
+
+ /*
+ * Free list lock.
+ */
+
SetEvent(tsdPtr->socketListLock);
}
/*
- * Clear the tsd socket list pointer if we did not wait for
- * the FD_CONNECT asyncroneously
+ * Clear the tsd socket list pointer if we did not wait for the
+ * FD_CONNECT asynchronously.
*/
+
tsdPtr->pendingTcpState = NULL;
if (Tcl_GetErrno() == 0) {
@@ -1807,7 +1942,7 @@ TcpConnect(
}
}
-out:
+ out:
/*
* Socket connected or connection failed
*/
@@ -1818,13 +1953,13 @@ out:
CLEAR_BITS(statePtr->flags, TCP_ASYNC_CONNECT);
- if ( Tcl_GetErrno() == 0 ) {
+ if (Tcl_GetErrno() == 0) {
/*
* Succesfully connected
- */
- /*
+ *
* Set up the select mask for read/write events.
*/
+
statePtr->selectEvents = FD_READ | FD_WRITE | FD_CLOSE;
/*
@@ -1832,35 +1967,56 @@ out:
* automatically places the socket into non-blocking mode.
*/
- SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT,
- (LPARAM) statePtr);
+ SendSelectMessage(tsdPtr, SELECT, statePtr);
} else {
/*
* Connect failed
- */
-
- /*
+ *
* For async connect schedule a writable event to report the fail.
*/
+
if (async_callback) {
/*
* Set up the select mask for read/write events.
*/
+
statePtr->selectEvents = FD_WRITE|FD_READ;
- /* get statePtr lock */
+
+ /*
+ * Get statePtr lock.
+ */
+
WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
- /* Signal ready readable and writable events */
- statePtr->readyEvents |= FD_WRITE | FD_READ;
- /* Flag error to event routine */
- statePtr->flags |= TCP_ASYNC_FAILED;
- /* Save connect error to be reported by 'fconfigure -error' */
+
+ /*
+ * Signal ready readable and writable events.
+ */
+
+ SET_BITS(statePtr->readyEvents, FD_WRITE | FD_READ);
+
+ /*
+ * Flag error to event routine.
+ */
+
+ SET_BITS(statePtr->flags, TCP_ASYNC_FAILED);
+
+ /*
+ * Save connect error to be reported by 'fconfigure -error'.
+ */
+
statePtr->connectError = Tcl_GetErrno();
- /* Free list lock */
+
+ /*
+ * Free list lock.
+ */
+
SetEvent(tsdPtr->socketListLock);
}
+
/*
* Error message on syncroneous connect
*/
+
if (interp != NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"couldn't open socket: %s", Tcl_PosixError(interp)));
@@ -1938,7 +2094,7 @@ Tcl_OpenTcpClient(
statePtr->addrlist = addrlist;
statePtr->myaddrlist = myaddrlist;
if (async) {
- statePtr->flags |= TCP_ASYNC_CONNECT;
+ SET_BITS(statePtr->flags, TCP_ASYNC_CONNECT);
}
/*
@@ -2008,7 +2164,7 @@ Tcl_MakeTcpClientChannel(
*/
statePtr->selectEvents = FD_READ | FD_CLOSE | FD_WRITE;
- SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM)SELECT, (LPARAM)statePtr);
+ SendSelectMessage(tsdPtr, SELECT, statePtr);
sprintf(channelName, SOCK_TEMPLATE, statePtr);
statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
@@ -2078,7 +2234,8 @@ Tcl_OpenTcpServerEx(
goto error;
}
- if (!TclCreateSocketAddress(interp, &addrlist, myHost, port, 1, &errorMsg)) {
+ if (!TclCreateSocketAddress(interp, &addrlist, myHost, port, 1,
+ &errorMsg)) {
goto error;
}
@@ -2117,13 +2274,14 @@ Tcl_OpenTcpServerEx(
}
/*
- * The SO_REUSEADDR option on Windows behaves like SO_REUSEPORT on unix
- * systems.
+ * The SO_REUSEADDR option on Windows behaves like SO_REUSEPORT on
+ * unix systems.
*/
- if (flags & TCL_TCPSERVER_REUSEPORT) {
+
+ if (GOT_BITS(flags, TCL_TCPSERVER_REUSEPORT)) {
optvalue = 1;
(void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
- (char *) &optvalue, sizeof(optvalue));
+ (char *) &optvalue, sizeof(optvalue));
}
/*
@@ -2134,8 +2292,8 @@ Tcl_OpenTcpServerEx(
* place to look for bugs.
*/
- if (bind(sock, addrPtr->ai_addr, addrPtr->ai_addrlen)
- == SOCKET_ERROR) {
+ if (bind(sock, addrPtr->ai_addr,
+ addrPtr->ai_addrlen) == SOCKET_ERROR) {
TclWinConvertError((DWORD) WSAGetLastError());
closesocket(sock);
continue;
@@ -2170,13 +2328,14 @@ Tcl_OpenTcpServerEx(
/*
* Add this socket to the global list of sockets.
*/
+
statePtr = NewSocketInfo(sock);
} else {
- AddSocketInfoFd( statePtr, sock );
+ AddSocketInfoFd(statePtr, sock);
}
}
-error:
+ error:
if (addrlist != NULL) {
freeaddrinfo(addrlist);
}
@@ -2201,8 +2360,7 @@ error:
*/
ioctlsocket(sock, (long) FIONBIO, &flag);
- SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT,
- (LPARAM) statePtr);
+ SendSelectMessage(tsdPtr, SELECT, statePtr);
if (Tcl_SetChannelOption(interp, statePtr->channel, "-eofchar", "")
== TCL_ERROR) {
Tcl_Close(NULL, statePtr->channel);
@@ -2271,8 +2429,7 @@ TcpAccept(
*/
newInfoPtr->selectEvents = (FD_READ | FD_WRITE | FD_CLOSE);
- SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT,
- (LPARAM) newInfoPtr);
+ SendSelectMessage(tsdPtr, SELECT, newInfoPtr);
sprintf(channelName, SOCK_TEMPLATE, newInfoPtr);
newInfoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
@@ -2503,7 +2660,7 @@ SocketSetupProc(
Tcl_Time blockTime = { 0, 0 };
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- if (!(flags & TCL_FILE_EVENTS)) {
+ if (!GOT_BITS(flags, TCL_FILE_EVENTS)) {
return;
}
@@ -2513,9 +2670,8 @@ SocketSetupProc(
WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
for (statePtr = tsdPtr->socketList; statePtr != NULL;
statePtr = statePtr->nextPtr) {
- if (statePtr->readyEvents &
- (statePtr->watchEvents | FD_CONNECT | FD_ACCEPT)
- ) {
+ if (GOT_BITS(statePtr->readyEvents,
+ statePtr->watchEvents | FD_CONNECT | FD_ACCEPT)) {
Tcl_SetMaxBlockTime(&blockTime);
break;
}
@@ -2549,7 +2705,7 @@ SocketCheckProc(
SocketEvent *evPtr;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- if (!(flags & TCL_FILE_EVENTS)) {
+ if (!GOT_BITS(flags, TCL_FILE_EVENTS)) {
return;
}
@@ -2562,11 +2718,10 @@ SocketCheckProc(
WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
for (statePtr = tsdPtr->socketList; statePtr != NULL;
statePtr = statePtr->nextPtr) {
- if ((statePtr->readyEvents &
- (statePtr->watchEvents | FD_CONNECT | FD_ACCEPT))
- && !(statePtr->flags & SOCKET_PENDING)
- ) {
- statePtr->flags |= SOCKET_PENDING;
+ if (GOT_BITS(statePtr->readyEvents,
+ statePtr->watchEvents | FD_CONNECT | FD_ACCEPT)
+ && !GOT_BITS(statePtr->flags, SOCKET_PENDING)) {
+ SET_BITS(statePtr->flags, SOCKET_PENDING);
evPtr = ckalloc(sizeof(SocketEvent));
evPtr->header.proc = SocketEventProc;
evPtr->socket = statePtr->sockets->fd;
@@ -2612,7 +2767,7 @@ SocketEventProc(
address addr;
int len;
- if (!(flags & TCL_FILE_EVENTS)) {
+ if (!GOT_BITS(flags, TCL_FILE_EVENTS)) {
return 0;
}
@@ -2641,29 +2796,26 @@ SocketEventProc(
* Clear flag that (this) event is pending
*/
- statePtr->flags &= ~SOCKET_PENDING;
+ CLEAR_BITS(statePtr->flags, SOCKET_PENDING);
/*
* Continue async connect if pending and ready
*/
- if ( statePtr->readyEvents & FD_CONNECT ) {
- if ( statePtr->flags & TCP_ASYNC_PENDING ) {
-
+ if (GOT_BITS(statePtr->readyEvents, FD_CONNECT)) {
+ if (GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)) {
/*
* Do one step and save eventual connect error
*/
SetEvent(tsdPtr->socketListLock);
WaitForConnect(statePtr,NULL);
-
} else {
-
/*
* No async connect reenter pending. Just clear event.
*/
- statePtr->readyEvents &= ~(FD_CONNECT);
+ CLEAR_BITS(statePtr->readyEvents, FD_CONNECT);
SetEvent(tsdPtr->socketListLock);
}
return 1;
@@ -2672,20 +2824,23 @@ SocketEventProc(
/*
* Handle connection requests directly.
*/
- if (statePtr->readyEvents & FD_ACCEPT) {
- for (fds = statePtr->sockets; fds != NULL; fds = fds->next) {
+ if (GOT_BITS(statePtr->readyEvents, FD_ACCEPT)) {
+ for (fds = statePtr->sockets; fds != NULL; fds = fds->next) {
/*
- * Accept the incoming connection request.
- */
- len = sizeof(address);
+ * Accept the incoming connection request.
+ */
+ len = sizeof(address);
newSocket = accept(fds->fd, &(addr.sa), &len);
- /* On Tcl server sockets with multiple OS fds we loop over the fds trying
- * an accept() on each, so we expect INVALID_SOCKET. There are also other
- * network stack conditions that can result in FD_ACCEPT but a subsequent
- * failure on accept() by the time we get around to it.
+ /*
+ * On Tcl server sockets with multiple OS fds we loop over the fds
+ * trying an accept() on each, so we expect INVALID_SOCKET. There
+ * are also other network stack conditions that can result in
+ * FD_ACCEPT but a subsequent failure on accept() by the time we
+ * get around to it.
+ *
* Access to sockets (acceptEventCount, readyEvents) in socketList
* is still protected by the lock (prevents reintroduction of
* SF Tcl Bug 3056775.
@@ -2697,35 +2852,40 @@ SocketEventProc(
}
/*
- * It is possible that more than one FD_ACCEPT has been sent, so an extra
- * count must be kept. Decrement the count, and reset the readyEvent bit
- * if the count is no longer > 0.
+ * It is possible that more than one FD_ACCEPT has been sent, so
+ * an extra count must be kept. Decrement the count, and reset the
+ * readyEvent bit if the count is no longer > 0.
*/
+
statePtr->acceptEventCount--;
if (statePtr->acceptEventCount <= 0) {
- statePtr->readyEvents &= ~(FD_ACCEPT);
+ CLEAR_BITS(statePtr->readyEvents, FD_ACCEPT);
}
SetEvent(tsdPtr->socketListLock);
- /* Caution: TcpAccept() has the side-effect of evaluating the server
- * accept script (via AcceptCallbackProc() in tclIOCmd.c), which can
- * close the server socket and invalidate statePtr and fds.
- * If TcpAccept() accepts a socket we must return immediately and let
- * SocketCheckProc queue additional FD_ACCEPT events.
+ /*
+ * Caution: TcpAccept() has the side-effect of evaluating the
+ * server accept script (via AcceptCallbackProc() in tclIOCmd.c),
+ * which can close the server socket and invalidate statePtr and
+ * fds. If TcpAccept() accepts a socket we must return immediately
+ * and let SocketCheckProc queue additional FD_ACCEPT events.
*/
+
TcpAccept(fds, newSocket, addr);
return 1;
}
- /* Loop terminated with no sockets accepted; clear the ready mask so
+ /*
+ * Loop terminated with no sockets accepted; clear the ready mask so
* we can detect the next connection request. Note that connection
* requests are level triggered, so if there is a request already
* pending, a new event will be generated.
*/
+
statePtr->acceptEventCount = 0;
- statePtr->readyEvents &= ~(FD_ACCEPT);
+ CLEAR_BITS(statePtr->readyEvents, FD_ACCEPT);
SetEvent(tsdPtr->socketListLock);
return 1;
@@ -2740,7 +2900,7 @@ SocketEventProc(
events = statePtr->readyEvents & statePtr->watchEvents;
- if (events & FD_CLOSE) {
+ if (GOT_BITS(events, FD_CLOSE)) {
/*
* If the socket was closed and the channel is still interested in
* read events, then we need to ensure that we keep polling for this
@@ -2754,17 +2914,14 @@ SocketEventProc(
Tcl_Time blockTime = { 0, 0 };
Tcl_SetMaxBlockTime(&blockTime);
- mask |= TCL_READABLE|TCL_WRITABLE;
- } else if (events & FD_READ) {
-
+ SET_BITS(mask, TCL_READABLE | TCL_WRITABLE);
+ } else if (GOT_BITS(events, FD_READ)) {
/*
* Throw the readable event if an async connect failed.
*/
- if ( statePtr->flags & TCP_ASYNC_FAILED ) {
-
- mask |= TCL_READABLE;
-
+ if (GOT_BITS(statePtr->flags, TCP_ASYNC_FAILED)) {
+ SET_BITS(mask, TCL_READABLE);
} else {
fd_set readFds;
struct timeval timeout;
@@ -2777,8 +2934,7 @@ SocketEventProc(
* async select handler and keep waiting.
*/
- SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
- (WPARAM) UNSELECT, (LPARAM) statePtr);
+ SendSelectMessage(tsdPtr, UNSELECT, statePtr);
FD_ZERO(&readFds);
FD_SET(statePtr->sockets->fd, &readFds);
@@ -2786,11 +2942,10 @@ SocketEventProc(
timeout.tv_sec = 0;
if (select(0, &readFds, NULL, NULL, &timeout) != 0) {
- mask |= TCL_READABLE;
+ SET_BITS(mask, TCL_READABLE);
} else {
- statePtr->readyEvents &= ~(FD_READ);
- SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
- (WPARAM) SELECT, (LPARAM) statePtr);
+ CLEAR_BITS(statePtr->readyEvents, FD_READ);
+ SendSelectMessage(tsdPtr, SELECT, statePtr);
}
}
}
@@ -2799,8 +2954,8 @@ SocketEventProc(
* writable event
*/
- if (events & FD_WRITE) {
- mask |= TCL_WRITABLE;
+ if (GOT_BITS(events, FD_WRITE)) {
+ SET_BITS(mask, TCL_WRITABLE);
}
/*
@@ -2837,13 +2992,19 @@ AddSocketInfoFd(
{
TcpFdList *fds = statePtr->sockets;
- if ( fds == NULL ) {
- /* Add the first FD */
+ if (fds == NULL) {
+ /*
+ * Add the first FD.
+ */
+
statePtr->sockets = ckalloc(sizeof(TcpFdList));
fds = statePtr->sockets;
} else {
- /* Find end of list and append FD */
- while ( fds->next != NULL ) {
+ /*
+ * Find end of list and append FD.
+ */
+
+ while (fds->next != NULL) {
fds = fds->next;
}
@@ -2851,7 +3012,10 @@ AddSocketInfoFd(
fds = fds->next;
}
- /* Populate new FD */
+ /*
+ * Populate new FD.
+ */
+
fds->fd = socket;
fds->statePtr = statePtr;
fds->next = NULL;
@@ -2921,6 +3085,7 @@ WaitForSocketEvent(
int result = 1;
int oldMode;
ThreadSpecificData *tsdPtr = TclThreadDataKeyGet(&dataKey);
+
/*
* Be sure to disable event servicing so we are truly modal.
*/
@@ -2931,29 +3096,42 @@ WaitForSocketEvent(
* Reset WSAAsyncSelect so we have a fresh set of events pending.
*/
- SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) UNSELECT,
- (LPARAM) statePtr);
- SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT,
- (LPARAM) statePtr);
+ SendSelectMessage(tsdPtr, UNSELECT, statePtr);
+ SendSelectMessage(tsdPtr, SELECT, statePtr);
while (1) {
int event_found;
- /* get statePtr lock */
+ /*
+ * Get statePtr lock.
+ */
+
WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
- /* Check if event occured */
- event_found = (statePtr->readyEvents & events);
+ /*
+ * Check if event occured.
+ */
+
+ event_found = GOT_BITS(statePtr->readyEvents, events);
+
+ /*
+ * Free list lock.
+ */
- /* Free list lock */
SetEvent(tsdPtr->socketListLock);
- /* exit loop if event occured */
+ /*
+ * Exit loop if event occured.
+ */
+
if (event_found) {
break;
}
- /* Exit loop if event did not occur but this is a non-blocking channel */
+ /*
+ * Exit loop if event did not occur but this is a non-blocking channel
+ */
+
if (statePtr->flags & TCP_NONBLOCKING) {
*errorCodePtr = EWOULDBLOCK;
result = 0;
@@ -3110,55 +3288,59 @@ SocketProc(
for (statePtr = tsdPtr->socketList; statePtr != NULL;
statePtr = statePtr->nextPtr) {
- if ( FindFDInList(statePtr,socket) ) {
+ if (FindFDInList(statePtr, socket)) {
info_found = 1;
break;
}
}
+
/*
- * Check if there is a pending info structure not jet in the
- * list
+ * Check if there is a pending info structure not jet in the list.
*/
- if ( !info_found
+
+ if (!info_found
&& tsdPtr->pendingTcpState != NULL
- && FindFDInList(tsdPtr->pendingTcpState,socket) ) {
+ && FindFDInList(tsdPtr->pendingTcpState, socket)) {
statePtr = tsdPtr->pendingTcpState;
info_found = 1;
}
if (info_found) {
-
/*
* Update the socket state.
*
* A count of FD_ACCEPTS is stored, so if an FD_CLOSE event
- * happens, then clear the FD_ACCEPT count. Otherwise,
- * increment the count if the current event is an FD_ACCEPT.
+ * happens, then clear the FD_ACCEPT count. Otherwise, increment
+ * the count if the current event is an FD_ACCEPT.
*/
- if (event & FD_CLOSE) {
+ if (GOT_BITS(event, FD_CLOSE)) {
statePtr->acceptEventCount = 0;
- statePtr->readyEvents &= ~(FD_WRITE|FD_ACCEPT);
- } else if (event & FD_ACCEPT) {
+ CLEAR_BITS(statePtr->readyEvents, FD_WRITE | FD_ACCEPT);
+ } else if (GOT_BITS(event, FD_ACCEPT)) {
statePtr->acceptEventCount++;
}
- if (event & FD_CONNECT) {
+ if (GOT_BITS(event, FD_CONNECT)) {
/*
* Remember any error that occurred so we can report
* connection failures.
*/
+
if (error != ERROR_SUCCESS) {
statePtr->notifierConnectError = error;
}
}
+
/*
* Inform main thread about signaled events
*/
- statePtr->readyEvents |= event;
+
+ SET_BITS(statePtr->readyEvents, event);
/*
* Wake up the Main Thread.
*/
+
SetEvent(tsdPtr->readyEvent);
Tcl_ThreadAlert(tsdPtr->threadId);
}
@@ -3239,6 +3421,7 @@ FindFDInList(
*----------------------------------------------------------------------
*/
+#ifndef TCL_NO_DEPRECATED
#undef TclWinGetSockOpt
int
TclWinGetSockOpt(
@@ -3278,6 +3461,7 @@ TclWinGetServByName(
{
return getservbyname(name, proto);
}
+#endif /* TCL_NO_DEPRECATED */
/*
*----------------------------------------------------------------------
@@ -3367,8 +3551,7 @@ TcpThreadActionProc(
* thread.
*/
- SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
- (WPARAM) notifyCmd, (LPARAM) statePtr);
+ SendSelectMessage(tsdPtr, notifyCmd, statePtr);
}
/*