Use third-party network libraries

#Use third-party network libraries in coroutines

There are two ways to use third-party network libraries in coroutines:

  • Directly use the blocking APIs of the third-party network library. This is the simplest way, but it relies on the system API hook in coost.
  • Use the non-blocking APIs of the third-party network library. In this way, users need to convert the APIs to synchronous manner with co::io_event.

#System API hook

API hook simply intercepts system API requests. If the request is in coroutine and uses a blocking socket, modify the socket to non-blocking mode. When the socket is unreadable or unwritable, use co::io_event or the lower-level APIs in coost to wait for the I/O event. When the I/O event arrives, wake up the coroutine and call the system’s native socket API to complete the I/O operation.

#Using non-blocking APIs

The following is the recv method implemented based on openssl’s non-blocking API:

int recv(S* s, void* buf, int n, int ms) {
     CHECK(co::sched()) << "must be called in coroutine..";
     int r, e;
     int fd = SSL_get_fd((SSL*)s);
     if (fd < 0) return -1;

     do {
         ERR_clear_error();
         r = SSL_read((SSL*)s, buf, n);
         if (r > 0) return r; // success
         if (r == 0) return 0;
 
         e = SSL_get_error((SSL*)s, r);
         if (e == SSL_ERROR_WANT_READ) {
             co::io_event ev(fd, co::ev_read);
             if (!ev.wait(ms)) return -1;
         } else if (e == SSL_ERROR_WANT_WRITE) {
             co::io_event ev(fd, co::ev_write);
             if (!ev.wait(ms)) return -1;
         } else {
             return r;
         }
     } while (true);
}

The whole process is relatively simple. The underlying socket must be non-blocking. When SSL_read generates SSL_ERROR_WANT_READ error, use co::io_event to wait for the read event. When SSL_ERROR_WANT_WRITE error occurs, use co:: io_event to wait for the write event, when wait() returns normally, it means the socket is readable or writable, continue to call SSL_read to complete the I/O operation.