Skip to content

co v2.0.0

Compare
Choose a tag to compare
@idealvin idealvin released this 28 May 16:04
· 782 commits to master since this release

Detailed reference documents


First of all, it is particularly emphasized that more detailed documents are provided this time:


New features

SSL


Co 2.0 finally supports SSL. Users need to install openssl 1.1 or above. It has been tested on openssl and other SSL libraries have not been tested yet.


It is recommended to use xmake as the build tool, it will prompt the user whether to install openssl, libcurl, zlib and other third-party libraries. To enable the SSL feature, you need to predefine the CO_SSL macro, which is automatically defined by xmake when openssl is detected.


co/so/ssl.h provides a coroutine-based openssl interface, but users may not use it directly, because co has embedded the SSL feature into the TCP module, and users can use tcp::Server and tcp::Client instead.


Important improvements

Coroutine

  • go
    go() supports any function or class method with 0 or 1 parameter, as well as function objects or pointers of type std::function<void()>.

    void f();
    void g(int);
    void h(int, int);
    struct T {
    	void f();
    	void g(int);
    };
    
    T o;
    std::function<void()> k(std::bind(h, 3, 7));
    
    go(f);
    go(g, 7);
    go(&T::f, &o);
    go(&T::g, &o, 3);
    go(k);
    go(&k); // The user must ensure that k is alive when the coroutine is running.
  • Coroutine API

    • Adding the co::timeout() function, users can use it to determine whether the last I/O function like co::recv or co::send has timed out.
    • The co::coroutine_id() function returns a globally unique id. In version 1.x, coroutines in different scheduling threads may have the same id.
  • co::Event
    The signaled state is added internally to solve the problem that the synchronization signal will be lost when there is no waiting coroutines.

  • co::IoEvent
    In the 1.x version, it is only used internally, and this class is public in 2.0, so that users can coroutineize third-party network libraries by themselves.

    int recv(SSL* s, void* buf, int n, int ms) {
        CHECK(co::scheduler()) << "must be called in coroutine..";
        int r, e;
        int fd = SSL_get_fd(s);
        if (fd <0) return -1;
    
        do {
            ERR_clear_error();
            r = SSL_read(s, buf, n);
            if (r> 0) return r; // success
            if (r == 0) {
                DLOG << "SSL_read return 0, error: "<< SSL_get_error(s, 0);
                return 0;
            }
    
            e = SSL_get_error(s, r);
            if (e == SSL_ERROR_WANT_READ) {
                co::IoEvent ev(fd, co::EV_read);
                if (!ev.wait(ms)) return -1;
            } else if (e == SSL_ERROR_WANT_WRITE) {
                co::IoEvent ev(fd, co::EV_write);
                if (!ev.wait(ms)) return -1;
            } else {
                DLOG << "SSL_read return "<< r << ", error:" << e;
                return r;
            }
        } while (true);
    }


    The above is an example of coroutineizing the SSL_read() function in openssl. You only need to use a non-blocking socket. When openssl generates an SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE error, call the wait() method of co::IoEvent and wait for the corresponding I/O Event.


TCP

  • Added the tcp::Connection class for the implementing TCP server. This class provides recv(), send() and other methods. Users can directly use this class to receive and send data without worrying about whether the underlying SSL is enabled.

  • tcp::Server

    void on_connection(tcp::Connection* conn);
    
    tcp::Server s;
    s.on_connection(on_connection);
    s.start("0.0.0.0", 7788); // no ssl
    s.start("0.0.0.0", 7788, "privkey.pem", "certificate.pem"); // use ssl

    Users can specify the SSL private key and certificate file in the start() method to enable SSL.


  • tcp::Client

    bool use_ssl = false;
    tcp::Client c("127.0.0.1", 7788, use_ssl);
    c.connect(1000);
    c.send(...);


    tcp::Client can enable SSL through the third parameter of the constructor.


HTTP

  • http::Client
    In co 2.0, http::Client is implemented based on libcurl. To enable this feature, you must install libcurl and predefine the HAS_LIBCURL macro. Again, it is recommended to use xmake to build, it will automatically handle these third-party dependencies.

    http::Client c("https://github.com");
    http::Client c("http://127.0.0.1:7777");
    c.get("/");
    c.get("/idealvin/co");
    LOG << c.response_code();
  • http::Server

    http::Server s
    s.on_req(...);
    s.start("0.0.0.0", 7777); // http
    s.start("0.0.0.0", 7777, "privkey.pem", "certificate.pem"); // https

RPC


In co 2.0, some new features have been added to the RPC framework:

  • Support SSL.
  • Support username and password authentication, and multiple usernames and passwords can be set for rpc::Server.
  • Multiple services can be added into rpc::Server.
  • The code generator can also generate code for RPC client.

JSON


In the 1.x version, the JSON library uses only one json::Value class to represent a JSON. The elements in the JSON object are also json::Value. When constructing a JSON object, you need to allocate memory for each element. When the JSON object is destructed, All internal elements must call the destructor of json::Value. Implementation based on this method will cause frequent memory allocation and release, which greatly affects program performance.


In co 2.0, the JSON object is built into a continuous memory. After the program runs stably, the parsing of JSON requires almost no memory allocation, which greatly improves the parsing speed.


In addition, co 2.0 uses the Json class to represent a JSON, and the json::Value class to represent the elements in the JSON. json::Value is just a trivial class, only including a index position in the JSON memory block. When a JSON is destructed, the destructor of the Json class is called only once, and the destructor of json::Value will never be called.


Others

  • Fix the nested log bug in co/log.
  • Fix some bugs caused by dependence of global static variables.
  • Add milliseconds in log time of co/log.
  • The TaskSched class is renamed to Tasked.
  • co/time.h. Add epoch::ms() and epoch::us() to obtain the time since the EPOCH.
  • co/os.h Add os::signal() method to set the signal handler function.
  • Added safe_clear() method in fastring.
  • Added safe_clear() method in Json.