Index: generic/tls.c ================================================================== --- generic/tls.c +++ generic/tls.c @@ -229,10 +229,11 @@ Tcl_Interp *interp = statePtr->interp; Tcl_Obj *cmdPtr; char *ver, *type; BIO *bio; char buffer[15000]; + Tcl_Size blen = 0; buffer[0] = 0; dprintf("Called"); if (statePtr->callback == (Tcl_Obj*)NULL) { @@ -298,15 +299,14 @@ type = "unknown"; } /* Needs compile time option "enable-ssl-trace". */ if ((bio = BIO_new(BIO_s_mem())) != NULL) { - int n; SSL_trace(write_p, version, content_type, buf, len, ssl, (void *)bio); - n = BIO_read(bio, buffer, BIO_pending(bio) < 15000 ? BIO_pending(bio) : 14999); - n = (n<0) ? 0 : n; - buffer[n] = 0; + blen = (Tcl_Size) BIO_read(bio, buffer, BIO_pending(bio) < 15000 ? BIO_pending(bio) : 14999); + blen = (blen<0) ? 0 : blen; + buffer[blen] = 0; (void)BIO_flush(bio); BIO_free(bio); } dprintf("Message direction=%d, ver=%s, type=%s, message=%s", write_p, ver, type, &buffer[0]); @@ -317,11 +317,11 @@ Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj(Tcl_GetChannelName(statePtr->self), -1)); Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj(write_p ? "Sent" : "Received", -1)); Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj(ver, -1)); Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj(type, -1)); - Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj(buffer, -1)); + Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj(buffer, blen)); /* Eval callback command */ Tcl_IncrRefCount(cmdPtr); EvalCallback(interp, statePtr, cmdPtr); Tcl_DecrRefCount(cmdPtr); @@ -2566,11 +2566,11 @@ /* Get SNI requested server name */ LAPPEND_STR(interp, objPtr, "servername", SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name), -1); /* Report the selected protocol as a result of the negotiation */ - SSL_get0_alpn_selected(statePtr->ssl, &proto, &ulen); + SSL_get0_alpn_selected(ssl, &proto, &ulen); LAPPEND_STR(interp, objPtr, "alpn", (char *)proto, (Tcl_Size) ulen); /* Get protocol */ LAPPEND_STR(interp, objPtr, "protocol", SSL_get_version(ssl), -1); @@ -3102,15 +3102,15 @@ if (statePtr->protos) { ckfree(statePtr->protos); statePtr->protos = NULL; } - /* BIO_free_all() frees up an entire BIO chain */ + /* BIO_free() frees up a single BIO */ if (statePtr->bio) { /* This will call SSL_shutdown. Bug 1414045 */ dprintf("BIO_free(%p)", statePtr->bio); - BIO_free_all(statePtr->bio); + BIO_free(statePtr->bio); statePtr->bio = NULL; } /* Free SSL context and statePtr->p_bio */ if (statePtr->ssl) { Index: generic/tlsIO.c ================================================================== --- generic/tlsIO.c +++ generic/tlsIO.c @@ -984,35 +984,32 @@ ClientData clientData) /* Socket state. */ { State *statePtr = (State *) clientData; int mask = statePtr->want; /* Init to SSL_ERROR_WANT_READ and SSL_ERROR_WANT_WRITE */ - dprintf("Called"); + dprintf("Called with mask 0x%02x", mask); statePtr->timer = (Tcl_TimerToken) NULL; - /* Check for amount of data pending in BIO write buffer */ - if (BIO_wpending(statePtr->bio)) { + /* Check for amount of data pending in IO or BIO write buffer */ + if (Tcl_OutputBuffered(statePtr->self) || BIO_wpending(statePtr->bio)) { dprintf("[chan=%p] BIO writable", statePtr->self); mask |= TCL_WRITABLE; } - /* Check for amount of data pending in BIO read buffer */ - if (BIO_pending(statePtr->bio)) { + /* Check for amount of data pending in IO or BIO read buffer */ + if (Tcl_InputBuffered(statePtr->self) || BIO_pending(statePtr->bio)) { dprintf("[chan=%p] BIO readable", statePtr->self); mask |= TCL_READABLE; } - /* Notify the generic IO layer that the mask events have occurred on the channel */ - dprintf("Notifying ourselves"); + /* Notify the generic IO layer that mask events have occurred on the channel */ + dprintf("Notifying ourselves with mask=%d", mask); Tcl_NotifyChannel(statePtr->self, mask); statePtr->want = 0; - - dprintf("Returning"); - return; } /* *----------------------------------------------------------------------------- @@ -1081,13 +1078,13 @@ /* Do we have any pending events */ pending = (statePtr->want || \ ((mask & TCL_READABLE) && ((Tcl_InputBuffered(statePtr->self) > 0) || (BIO_ctrl_pending(statePtr->bio) > 0))) || ((mask & TCL_WRITABLE) && ((Tcl_OutputBuffered(statePtr->self) > 0) || (BIO_ctrl_wpending(statePtr->bio) > 0)))); - dprintf("IO Want=%d, input buffer=%d, output buffer=%d, BIO pending=%zd, BIO wpending=%zd", \ + dprintf("IO Want=%d, input buffer=%d, output buffer=%d, BIO pending=%zd, BIO wpending=%zd, pending=%d", \ statePtr->want, Tcl_InputBuffered(statePtr->self), Tcl_OutputBuffered(statePtr->self), \ - BIO_ctrl_pending(statePtr->bio), BIO_ctrl_wpending(statePtr->bio)); + BIO_ctrl_pending(statePtr->bio), BIO_ctrl_wpending(statePtr->bio), pending); if (!(mask & TCL_READABLE) || pending == 0) { /* Remove timer, if any */ if (statePtr->timer != (Tcl_TimerToken) NULL) { dprintf("A timer was found, deleting it"); @@ -1155,25 +1152,14 @@ * combination of TCL_READABLE or TCL_WRITABLE */ { State *statePtr = (State *) instanceData; int errorCode = 0; - dprintf("Called"); - - /* - * Delete an existing timer. It was not fired, yet we are - * here, so the channel below generated such an event and we - * don't have to. The renewal of the interest after the - * execution of channel handlers will eventually cause us to - * recreate the timer (in WatchProc). - */ - if (statePtr->timer != (Tcl_TimerToken) NULL) { - Tcl_DeleteTimerHandler(statePtr->timer); - statePtr->timer = (Tcl_TimerToken) NULL; - } - - /* Skip if user verify callback is still running */ + dprintf("Called with mask 0x%02x", mask); + + /* Abort if the user verify callback is still running to avoid triggering + * another call before the current one is complete. */ if (statePtr->flags & TLS_TCL_CALLBACK) { dprintf("Callback is on-going, returning failed"); return 0; } @@ -1194,17 +1180,26 @@ dprintf("Tls_WaitForConnect returned an error"); } } - dprintf("Returning %i", mask); + /* + * Delete an existing timer. It was not fired, yet we are here, so the + * channel below generated such an event and we don't have to. The renewal + * of the interest after the execution of channel handlers will eventually + * cause us to recreate the timer (in WatchProc). + */ + if (statePtr->timer != (Tcl_TimerToken) NULL) { + Tcl_DeleteTimerHandler(statePtr->timer); + statePtr->timer = (Tcl_TimerToken) NULL; + } /* - * An event occurred in the underlying channel. This - * transformation doesn't process such events thus returns the - * incoming mask unchanged. + * An event occurred in the underlying channel. This transformation doesn't + * process such events thus returns the incoming mask unchanged. */ + dprintf("Returning %i", mask); return mask; } /* *-----------------------------------------------------------------------------