Thanks for your comments. I decided to keep the mutex because that is what cv_timedwait knows how to deal with. But I no longer hold the mutex over the call to ksocket_connect. So that should eliminate the possible recursive mutex call that you were worried about.

Here is what I ended up with. I have tested this with successful connects, connects that time out, and connects that are immediately rejected.

I probably don't need the variable "final_pass". If the socket callback is called, then ksocket_connect should then return either success or some definite error. But I felt safer writing that assumption into the code.

/* used by idm_so_timed_socket_connect */
typedef struct idm_so_timed_socket_s {
       kcondvar_t      it_cv;
       boolean_t       it_callback_called;
} idm_so_timed_socket_t;


/* ARGSUSED */
void *
idm_so_timed_socket_connect_cb(ksocket_t ks,
   ksocket_callback_event_t ev, void *arg, uintptr_t info)
{
       idm_so_timed_socket_t   *itp =
               (idm_so_timed_socket_t *)arg;
       ASSERT(itp != NULL);
       ASSERT(ev == KSOCKET_EV_CONNECTED ||
              ev == KSOCKET_EV_CONNECTFAILED ||
              ev == KSOCKET_EV_DISCONNECTED);

       mutex_enter(&idm_so_timed_socket_mutex);
       itp->it_callback_called = B_TRUE;
       cv_signal(&itp->it_cv);
       mutex_exit(&idm_so_timed_socket_mutex);
       return (NULL);
}

int
idm_so_timed_socket_connect(ksocket_t ks,
   struct sockaddr_storage *sa, int sa_sz, int login_max_usec)
{
       clock_t                 conn_login_max, lbolt;
       int                     rc, nonblocking, rval;
       idm_so_timed_socket_t   it;
       ksocket_callbacks_t     ks_cb;
       boolean_t               final_pass = B_FALSE;
conn_login_max = ddi_get_lbolt() + drv_usectohz(login_max_usec);

       /*
         Set to non-block socket mode, with callback on connect
         Early volo used "disconnected" instead of "connectfailed",
         so set callback to look for both.
        */
       bzero(&it, sizeof (it));
ks_cb.ksock_cb_flags = KSOCKET_CB_CONNECTED | KSOCKET_CB_CONNECTFAILED | KSOCKET_CB_DISCONNECTED;
       ks_cb.ksock_cb_connected =
           (ksocket_callback_t)idm_so_timed_socket_connect_cb;
       ks_cb.ksock_cb_connectfailed =
           (ksocket_callback_t)idm_so_timed_socket_connect_cb;
       ks_cb.ksock_cb_disconnected =
           (ksocket_callback_t)idm_so_timed_socket_connect_cb;
       cv_init(&it.it_cv, NULL, CV_DEFAULT, NULL);
       (void) ksocket_setcallbacks(ks, &ks_cb, (void *)&it, CRED());

       /* Set to non-blocking mode */
       nonblocking = 1;
       (void)  ksocket_ioctl(ks, FIONBIO, (intptr_t)&nonblocking, &rval,
           CRED());

       for (;;) {
               /*
                * Warning -- in a loopback scenario, the call to
                * the connect_cb can occur inside the call to
                * ksocket_connect. Do not hold the mutex around the
                * call to ksocket_connect.
                */
               rc = ksocket_connect(ks, (struct sockaddr *)sa, sa_sz, CRED());
               if (rc == 0 || rc == EISCONN) {
                       /* socket success or already success */
                       rc = 0;
                       break;
               }
               if ((rc != EINPROGRESS) && (rc != EALREADY)) {
                       break;
               }

               lbolt = ddi_get_lbolt();
               if (lbolt > conn_login_max || final_pass) {
                       /*
                        * Connection retry timeout,
                        * failed connect to target.
                        */
                       rc = ETIMEDOUT;
                       break;
               }
               /* TCP connect still in progress.  Sleep until callback. */
               mutex_enter(&idm_so_timed_socket_mutex);
               if (! it.it_callback_called) {
                       (void) cv_timedwait(&it.it_cv,
                           &idm_so_timed_socket_mutex, conn_login_max);
               } else {
                       final_pass = B_TRUE;
               }
               mutex_exit(&idm_so_timed_socket_mutex);
       }

       /* resume blocking mode */
       nonblocking = 0;
       (void)  ksocket_ioctl(ks, FIONBIO, (intptr_t)&nonblocking, &rval,
           CRED());
       ksocket_setcallbacks(ks, NULL, NULL, CRED());
       cv_destroy(&it.it_cv);

       return (rc);
}




_______________________________________________
networking-discuss mailing list
[email protected]

Reply via email to