@@ -3157,6 +3157,104 @@ static void TestChannelOpenFailCallbackRejects(void)
31573157 FreeChannelOpenHarness (& harness );
31583158}
31593159
3160+ /* What the close callback saw, including whether the channel was still on
3161+ * the list when it ran. */
3162+ static int closeCbCalls ;
3163+ static word32 closeCbChannel ;
3164+ static void * closeCbCtx ;
3165+ static word32 closeCbListSz ;
3166+ static int closeCbReturn ;
3167+
3168+ static int RecordingChannelCloseCb (WOLFSSH_CHANNEL * channel , void * ctx )
3169+ {
3170+ AssertNotNull (channel );
3171+ AssertNotNull (channel -> ssh );
3172+ closeCbCalls ++ ;
3173+ closeCbChannel = channel -> channel ;
3174+ closeCbCtx = ctx ;
3175+ closeCbListSz = channel -> ssh -> channelListSz ;
3176+
3177+ return closeCbReturn ;
3178+ }
3179+
3180+ /* Drives a peer close of a confirmed channel through the recording callback,
3181+ * set to return cbReturn, and returns what DoReceive() reported. */
3182+ static int CloseThroughRecordingCb (ChannelOpenHarness * harness , void * cbCtx ,
3183+ int cbReturn , word32 * selfChannelId )
3184+ {
3185+ WOLFSSH_CHANNEL * channel ;
3186+ byte in [64 ];
3187+ word32 inSz ;
3188+ int ret ;
3189+
3190+ closeCbCalls = 0 ;
3191+ closeCbChannel = REGRESS_NO_CHANNEL ;
3192+ closeCbCtx = NULL ;
3193+ closeCbListSz = 0 ;
3194+ closeCbReturn = cbReturn ;
3195+
3196+ InitChannelOpenHarness (harness , NULL , 0 );
3197+ AssertIntEQ (wolfSSH_CTX_SetChannelCloseCb (harness -> ctx ,
3198+ RecordingChannelCloseCb ), WS_SUCCESS );
3199+ AssertIntEQ (wolfSSH_SetChannelCloseCtx (harness -> ssh , cbCtx ), WS_SUCCESS );
3200+
3201+ channel = SeedUnconfirmedChannel (harness );
3202+ * selfChannelId = channel -> channel ;
3203+ AssertIntEQ (ChannelUpdatePeer (channel , 5 , 1024 , 1024 ), WS_SUCCESS );
3204+ channel -> openConfirmed = 1 ;
3205+
3206+ inSz = BuildChannelClosePacket (* selfChannelId , in , sizeof (in ));
3207+ RepointHarnessInput (harness , in , inSz );
3208+
3209+ ret = DoReceive (harness -> ssh );
3210+ AssertIntEQ (harness -> io .inOff , harness -> io .inSz );
3211+
3212+ return ret ;
3213+ }
3214+
3215+ /* The close callback is an application's only notice that a peer closed a
3216+ * channel, and it has to run while the channel is still findable:
3217+ * DoChannelClose() retires it a few lines later, and after that there is
3218+ * nothing left to name. */
3219+ static void TestChannelCloseCallbackRuns (void )
3220+ {
3221+ ChannelOpenHarness harness ;
3222+ word32 selfChannelId ;
3223+ int cbCtx = 0 ;
3224+ int ret ;
3225+
3226+ ret = CloseThroughRecordingCb (& harness , & cbCtx , WS_SUCCESS ,
3227+ & selfChannelId );
3228+ AssertIntEQ (ret , WS_CHANNEL_CLOSED );
3229+ AssertIntEQ (closeCbCalls , 1 );
3230+ AssertIntEQ (closeCbChannel , selfChannelId );
3231+ AssertTrue (closeCbCtx == & cbCtx );
3232+ AssertIntEQ (closeCbListSz , 1 );
3233+
3234+ /* And the channel is gone by the time the caller is told. */
3235+ AssertIntEQ (harness .ssh -> channelListSz , 0 );
3236+
3237+ FreeChannelOpenHarness (& harness );
3238+ }
3239+
3240+ /* The close callback's return is discarded: the peer has closed whatever
3241+ * the application thinks, so the close completes either way. */
3242+ static void TestChannelCloseCallbackReturnIgnored (void )
3243+ {
3244+ ChannelOpenHarness harness ;
3245+ word32 selfChannelId ;
3246+ int cbCtx = 0 ;
3247+ int ret ;
3248+
3249+ ret = CloseThroughRecordingCb (& harness , & cbCtx , WS_BAD_ARGUMENT ,
3250+ & selfChannelId );
3251+ AssertIntEQ (ret , WS_CHANNEL_CLOSED );
3252+ AssertIntEQ (closeCbCalls , 1 );
3253+ AssertIntEQ (harness .ssh -> channelListSz , 0 );
3254+
3255+ FreeChannelOpenHarness (& harness );
3256+ }
3257+
31603258/* A username change after the first userauth request must end the session. */
31613259static void TestUsernameChangeDisconnects (void )
31623260{
@@ -12355,6 +12453,8 @@ int main(int argc, char** argv)
1235512453 TestChannelOpenFailCallbackRuns ();
1235612454 TestChannelOpenConfCallbackRejects ();
1235712455 TestChannelOpenFailCallbackRejects ();
12456+ TestChannelCloseCallbackRuns ();
12457+ TestChannelCloseCallbackReturnIgnored ();
1235812458 TestSecondSessionChannelRejected ();
1235912459 TestUsernameChangeDisconnects ();
1236012460 TestSameUserRetryAllowed ();
0 commit comments