Uploaded image for project: 'C Driver'
  1. C Driver
  2. CDRIVER-619

Fail fast after hangup with TLS

    • Type: Icon: Bug Bug
    • Resolution: Done
    • Priority: Icon: Blocker - P1 Blocker - P1
    • 1.1.5
    • Affects Version/s: 1.1.4
    • Component/s: None
    • None
    • Fully Compatible

      In 1.1.4, a network error at certain point(s) in the TLS code path causes the driver to spin infinitely.

      To reproduce, first install pip, then mongo-mockup-db:

      $ wget https://bootstrap.pypa.io/get-pip.py
      $ sudo python get-pip.py
      $ sudo python -m pip install https://github.com/ajdavis/mongo-mockup-db/archive/master.zip
      

      Then save this in a Python file and run it like "python file.py":

      from mockupdb import MockupDB, Command
      
      server = MockupDB(port=27017, auto_ismaster=True, verbose=True, ssl=True)
      server.autoresponds('ping')
      server.run()
      server.receives(Command('listCollections'), timeout=100).hangup()
      

      That'll wait up to 100 seconds for a driver to issue listCollections, then when it receives the command it hangs up.

      I've started this mock server and run this file, using the C Driver built from master (0bd7850609):

      #include <mongoc.h>
      
      int
      main (int   argc,
            char *argv[])
      {
         mongoc_client_t *client;
         mongoc_database_t *db;
         bson_error_t error;
         mongoc_ssl_opt_t ssl_options = { 0 };
         const char *uristr = "mongodb://127.0.0.1/?ssl=true";
         char **names = NULL;
         int i = 0;
         mongoc_init ();
      
         if (argc > 1) {
            uristr = argv [1];
         }
      
         client = mongoc_client_new (uristr);
         ssl_options.weak_cert_validation = true;
         mongoc_client_set_ssl_opts (client, &ssl_options);
      
         if (!client) {
            fprintf (stderr, "Failed to parse URI.\n");
            return EXIT_FAILURE;
         }
      
         db = mongoc_client_get_database (client, "test");
         if ((names = mongoc_database_get_collection_names (db, &error))) {
            printf ("got collection names\n");
            for (i = 0; names [i]; i++)
               printf ("collection: %s\n", names [i]);
            bson_strfreev (names);
         } else {
            fprintf (stderr, "Command failed: %s\n", error.message);
         }
         mongoc_database_destroy (db);
         mongoc_client_destroy (client);
      
         mongoc_cleanup ();
      
         return EXIT_SUCCESS;
      }
      

      The Python server hangs up, and the client hangs and spins the CPU.

      If I remove "ssl=True" from the Python and "ssl=true" from the C, and rerun both sides, I instead get an immediate log about the hangup from the C Driver and it exits as desired:

      stream: Failure to buffer 4 bytes: Failed to buffer 4 bytes within 300000 milliseconds.
      

      The C code also gets a non-NULL return value from mongoc_database_get_collection_names, which is filed as a separate bug CDRIVER-618.

            Assignee:
            jesse@mongodb.com A. Jesse Jiryu Davis
            Reporter:
            jesse@mongodb.com A. Jesse Jiryu Davis
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: