@@ -558,13 +558,213 @@ test_nc_ch_delete_client_while_session(void **state)
558558 }
559559}
560560
561+ static int session_count = 0 ;
562+ static pthread_mutex_t session_count_mutex = PTHREAD_MUTEX_INITIALIZER ;
563+
564+ struct ch_thread_arg {
565+ struct ln2_test_ctx * test_ctx ;
566+ const char * ch_client_name ;
567+ int port ;
568+ };
569+
570+ static int
571+ ch_new_session_count_cb (const char * client_name , struct nc_session * new_session , void * user_data )
572+ {
573+ int ret = 0 ;
574+ struct nc_pollsession * ps = (struct nc_pollsession * )user_data ;
575+
576+ (void ) client_name ;
577+
578+ ret = nc_ps_add_session (ps , new_session );
579+ assert_int_equal (ret , 0 );
580+
581+ pthread_mutex_lock (& session_count_mutex );
582+ session_count ++ ;
583+ pthread_mutex_unlock (& session_count_mutex );
584+
585+ return 0 ;
586+ }
587+
588+ static void *
589+ server_thread_two_ch (void * arg )
590+ {
591+ int ret ;
592+ struct nc_pollsession * ps ;
593+ struct ch_thread_arg * ch_arg = arg ;
594+
595+ ps = nc_ps_new ();
596+ assert_non_null (ps );
597+
598+ pthread_barrier_wait (& ch_arg -> test_ctx -> barrier );
599+
600+ ret = nc_connect_ch_client_dispatch (ch_arg -> ch_client_name , ch_session_acquire_ctx_cb ,
601+ ch_session_release_ctx_cb , ch_arg -> test_ctx , ch_new_session_count_cb , ps );
602+ assert_int_equal (ret , 0 );
603+
604+ while (1 ) {
605+ pthread_mutex_lock (& session_count_mutex );
606+ if (session_count >= 2 ) {
607+ pthread_mutex_unlock (& session_count_mutex );
608+ break ;
609+ }
610+ pthread_mutex_unlock (& session_count_mutex );
611+
612+ ret = nc_ps_poll (ps , NC_PS_POLL_TIMEOUT , NULL );
613+ if (ret & (NC_PSPOLL_TIMEOUT | NC_PSPOLL_NOSESSIONS )) {
614+ usleep (10000 );
615+ }
616+ }
617+
618+ nc_ps_clear (ps , 1 , NULL );
619+ nc_ps_free (ps );
620+
621+ free (ch_arg );
622+ return NULL ;
623+ }
624+
625+ static void *
626+ client_thread_two_ch (void * arg )
627+ {
628+ int ret ;
629+ struct nc_session * session = NULL ;
630+ struct ch_thread_arg * ch_arg = arg ;
631+
632+ nc_client_ssh_ch_set_knownhosts_mode (NC_SSH_KNOWNHOSTS_SKIP );
633+ ret = nc_client_set_schema_searchpath (MODULES_DIR );
634+ assert_int_equal (ret , 0 );
635+ ret = nc_client_ssh_ch_set_username ("test_ch_simul" );
636+ assert_int_equal (ret , 0 );
637+ ret = nc_client_ssh_ch_add_keypair (TESTS_DIR "/data/id_ed25519.pub" , TESTS_DIR "/data/id_ed25519" );
638+ assert_int_equal (ret , 0 );
639+
640+ ret = nc_client_ssh_ch_add_bind_listen ("127.0.0.1" , ch_arg -> port );
641+ assert_int_equal (ret , 0 );
642+
643+ pthread_barrier_wait (& ch_arg -> test_ctx -> barrier );
644+
645+ ret = nc_accept_callhome (NC_ACCEPT_TIMEOUT , NULL , & session );
646+ assert_int_equal (ret , 1 );
647+
648+ ret = nc_client_ssh_ch_del_bind ("127.0.0.1" , ch_arg -> port );
649+ assert_int_equal (ret , 0 );
650+
651+ nc_session_free (session , NULL );
652+ free (ch_arg );
653+ return NULL ;
654+ }
655+
656+ static int
657+ setup_two_simultaneous (void * * state )
658+ {
659+ int ret ;
660+ struct lyd_node * tree = NULL ;
661+ struct ln2_test_ctx * test_ctx ;
662+ struct test_ch_data * test_data ;
663+
664+ ret = ln2_glob_test_setup (& test_ctx );
665+ assert_int_equal (ret , 0 );
666+
667+ pthread_barrier_destroy (& test_ctx -> barrier );
668+ ret = pthread_barrier_init (& test_ctx -> barrier , NULL , 4 );
669+ assert_int_equal (ret , 0 );
670+
671+ test_data = calloc (1 , sizeof * test_data );
672+ assert_non_null (test_data );
673+
674+ test_ctx -> test_data = test_data ;
675+ test_ctx -> free_test_data = test_nc_ch_free_test_data ;
676+ * state = test_ctx ;
677+
678+ session_count = 0 ;
679+
680+ ret = nc_server_config_add_ch_address_port (test_ctx -> ctx , "ch_simul_1" , "endpt" , NC_TI_SSH ,
681+ "127.0.0.1" , TEST_PORT_3_STR , & tree );
682+ assert_int_equal (ret , 0 );
683+
684+ ret = nc_server_config_add_ch_persistent (test_ctx -> ctx , "ch_simul_1" , & tree );
685+ assert_int_equal (ret , 0 );
686+
687+ ret = nc_server_config_add_ch_ssh_hostkey (test_ctx -> ctx , "ch_simul_1" , "endpt" , "hostkey" ,
688+ TESTS_DIR "/data/key_ecdsa" , NULL , & tree );
689+ assert_int_equal (ret , 0 );
690+
691+ ret = nc_server_config_add_ch_ssh_user_pubkey (test_ctx -> ctx , "ch_simul_1" , "endpt" , "test_ch_simul" ,
692+ "pubkey" , TESTS_DIR "/data/id_ed25519.pub" , & tree );
693+ assert_int_equal (ret , 0 );
694+
695+ ret = nc_server_config_add_ch_address_port (test_ctx -> ctx , "ch_simul_2" , "endpt" , NC_TI_SSH ,
696+ "127.0.0.1" , TEST_PORT_4_STR , & tree );
697+ assert_int_equal (ret , 0 );
698+
699+ ret = nc_server_config_add_ch_persistent (test_ctx -> ctx , "ch_simul_2" , & tree );
700+ assert_int_equal (ret , 0 );
701+
702+ ret = nc_server_config_add_ch_ssh_hostkey (test_ctx -> ctx , "ch_simul_2" , "endpt" , "hostkey" ,
703+ TESTS_DIR "/data/key_ecdsa" , NULL , & tree );
704+ assert_int_equal (ret , 0 );
705+
706+ ret = nc_server_config_add_ch_ssh_user_pubkey (test_ctx -> ctx , "ch_simul_2" , "endpt" , "test_ch_simul" ,
707+ "pubkey" , TESTS_DIR "/data/id_ed25519.pub" , & tree );
708+ assert_int_equal (ret , 0 );
709+
710+ ret = nc_server_config_setup_data (tree );
711+ assert_int_equal (ret , 0 );
712+
713+ test_data -> tree = tree ;
714+ return 0 ;
715+ }
716+
717+ static void
718+ test_nc_ch_two_simultaneous (void * * state )
719+ {
720+ int ret , i ;
721+ pthread_t tids [4 ];
722+ struct ch_thread_arg * ch_arg ;
723+ struct ln2_test_ctx * test_ctx = * state ;
724+
725+ assert_non_null (state );
726+
727+ ch_arg = calloc (1 , sizeof * ch_arg );
728+ assert_non_null (ch_arg );
729+ ch_arg -> test_ctx = test_ctx ;
730+ ch_arg -> port = TEST_PORT_3 ;
731+ ret = pthread_create (& tids [0 ], NULL , client_thread_two_ch , ch_arg );
732+ assert_int_equal (ret , 0 );
733+
734+ ch_arg = calloc (1 , sizeof * ch_arg );
735+ assert_non_null (ch_arg );
736+ ch_arg -> test_ctx = test_ctx ;
737+ ch_arg -> port = TEST_PORT_4 ;
738+ ret = pthread_create (& tids [1 ], NULL , client_thread_two_ch , ch_arg );
739+ assert_int_equal (ret , 0 );
740+
741+ ch_arg = calloc (1 , sizeof * ch_arg );
742+ assert_non_null (ch_arg );
743+ ch_arg -> test_ctx = test_ctx ;
744+ ch_arg -> ch_client_name = "ch_simul_1" ;
745+ ret = pthread_create (& tids [2 ], NULL , server_thread_two_ch , ch_arg );
746+ assert_int_equal (ret , 0 );
747+
748+ ch_arg = calloc (1 , sizeof * ch_arg );
749+ assert_non_null (ch_arg );
750+ ch_arg -> test_ctx = test_ctx ;
751+ ch_arg -> ch_client_name = "ch_simul_2" ;
752+ ret = pthread_create (& tids [3 ], NULL , server_thread_two_ch , ch_arg );
753+ assert_int_equal (ret , 0 );
754+
755+ for (i = 0 ; i < 4 ; i ++ ) {
756+ pthread_join (tids [i ], NULL );
757+ }
758+ }
759+
561760int
562761main (void )
563762{
564763 const struct CMUnitTest tests [] = {
565764 cmocka_unit_test_setup_teardown (test_nc_ch_ssh , setup_ssh , ln2_glob_test_teardown ),
566765 cmocka_unit_test_setup_teardown (test_nc_ch_tls , setup_tls , ln2_glob_test_teardown ),
567766 cmocka_unit_test_setup_teardown (test_nc_ch_delete_client_while_session , setup_delete_while_session , ln2_glob_test_teardown ),
767+ cmocka_unit_test_setup_teardown (test_nc_ch_two_simultaneous , setup_two_simultaneous , ln2_glob_test_teardown ),
568768 };
569769
570770 if (ln2_glob_test_get_ports (4 , & TEST_PORT , & TEST_PORT_STR , & TEST_PORT_2 , & TEST_PORT_2_STR ,
0 commit comments