Giter Club home page Giter Club logo

uvw's Introduction

uvw - libuv wrapper in modern C++

Build Status Coverage Documentation Vcpkg port Gitter chat Donate

Do you have a question that doesn't require you to open an issue? Join the gitter channel.
If you use uvw and you want to say thanks or support the project, please consider becoming a sponsor.
You can help me make the difference. Many thanks to those who supported me and still support me today.

Introduction

uvw started as a header-only, event based, tiny and easy to use wrapper for libuv written in modern C++.
Now it's finally available also as a compilable static library.

The basic idea is to wrap the C-ish interface of libuv behind a graceful C++ API.
Note that uvw stays true to the API of libuv and it doesn't add anything to its interface. For the same reasons, users of the library must follow the same rules which are used with libuv.
As an example, a handle should be initialized before any other operation and closed once it is no longer in use.

Code Example

#include <uvw.hpp>
#include <memory>

void listen(uvw::loop &loop) {
    std::shared_ptr<uvw::tcp_handle> tcp = loop.resource<uvw::tcp_handle>();

    tcp->on<uvw::listen_event>([](const uvw::listen_event &, uvw::tcp_handle &srv) {
        std::shared_ptr<uvw::tcp_handle> client = srv.parent().resource<uvw::tcp_handle>();

        client->on<uvw::close_event>([ptr = srv.shared_from_this()](const uvw::close_event &, uvw::tcp_handle &) { ptr->close(); });
        client->on<uvw::end_event>([](const uvw::end_event &, uvw::tcp_handle &client) { client.close(); });

        srv.accept(*client);
        client->read();
    });

    tcp->bind("127.0.0.1", 4242);
    tcp->listen();
}

void conn(uvw::loop &loop) {
    auto tcp = loop.resource<uvw::tcp_handle>();

    tcp->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { /* handle errors */ });

    tcp->on<uvw::connect_event>([](const uvw::connect_event &, uvw::tcp_handle &tcp) {
        auto dataWrite = std::unique_ptr<char[]>(new char[2]{ 'b', 'c' });
        tcp.write(std::move(dataWrite), 2);
        tcp.close();
    });

    tcp->connect(std::string{"127.0.0.1"}, 4242);
}

int main() {
    auto loop = uvw::loop::get_default();
    listen(*loop);
    conn(*loop);
    loop->run();
}

Motivation

The main reason for which uvw has been written is the fact that there does not exist a valid libuv wrapper in C++. That's all.

Build Instructions

Requirements

To be able to use uvw, users must provide the following system-wide tools:

  • A full-featured compiler that supports at least C++17.
  • libuv (which version depends on the tag of uvw in use)
    • If you use meson, libuv will be downloaded for you

The requirements below are mandatory to compile the tests and to extract the documentation:

  • CMake version 3.13 or later.
  • Doxygen version 1.8 or later.

Note that libuv is part of the dependencies of the project and may be cloned by CMake in some cases (see below for further details).
Because of that, users don't have to install it to run the tests or when uvw libraries are compiled through CMake.

Meson

You can use uvw with meson by simply adding it to your subprojects directory in your project. Currently, uvw is not available with meson wrap, but this will change with the release of uvw 3.4.x.

To compile uvw from source without using it as a subproject, in the uvw source directory, run:

  • $ meson setup build
    • If you want a static library, add --default-library=static
  • $ cd build
  • $ meson compile

Library

uvw is a dual-mode library. It can be used in its header-only form or as a compiled static library.
The following sections describe what to do in both cases to get uvw up and runningin your own project.

Header-only

To use uvw as a header-only library, all is needed is to include the uvw.hpp header or one of the other uvw/*.hpp files.
It's a matter of adding the following line at the top of a file:

#include <uvw.hpp>

Then pass the proper -I argument to the compiler to add the src directory to the include paths.
Note that users are required to correctly setup the include directories and libraries search paths for libuv in this case.

When used through CMake, the uvw::uvw target is exported for convenience.

Static

To use uvw as a compiled library, set the BUILD_UVW_LIBS options in cmake before including the project.
This option triggers the generation of a targets named uvw::uvw-static. The matching version of libuv is also compiled and exported as uv::uv-static for convenience.

In case you don't use or don't want to use CMake, you can still compile all .cpp files and include all .h files to get the job done. In this case, users are required to correctly setup the include directories and libraries search paths for libuv.

Versioning

Starting with tag v1.12.0 of libuv, uvw follows the semantic versioning scheme.
The problem is that any version of uvw also requires to track explicitly the version of libuv to which it is bound.
Because of that, the latter wil be appended to the version of uvw. As an example:

vU.V.W_libuv-vX.Y

In particular, the following applies:

  • U.V.W are major, minor and patch versions of uvw.
  • X.Y is the version of libuv to which to refer (where any patch version is valid).

In other terms, tags will look like this from now on:

v1.0.0_libuv-v1.12

Branch master of uvw will be a work in progress branch that follows branch v1.x of libuv (at least as long as it remains their master branch).

Documentation

The documentation is based on doxygen. To build it:

  • $ cd build
  • $ cmake ..
  • $ make docs

The API reference will be created in HTML format within the directory build/docs/html.
To navigate it with your favorite browser:

  • $ cd build
  • $ your_favorite_browser docs/html/index.html

The same version is also available online for the latest release, that is the last stable tag.

Note

The documentation is mostly inspired by the official libuv API documentation for obvious reasons.

Tests

To compile and run the tests, uvw requires libuv and googletest.
CMake will download and compile both the libraries before compiling anything else.

To build the tests:

  • $ cd build
  • $ cmake .. -DBUILD_TESTING=ON
  • $ make
  • $ ctest -j4 -R uvw

Omit -R uvw if you also want to test libuv and other dependencies.

Crash Course

Vademecum

There is only one rule when using uvw: always initialize the resources and terminate them.

Resources belong mainly to two families: handles and requests.
Handles represent long-lived objects capable of performing certain operations while active.
Requests represent (typically) short-lived operations performed either over a handle or standalone.

The following sections will explain in short what it means to initialize and terminate these kinds of resources.
For more details, please refer to the online documentation.

Handles

Initialization is usually performed under the hood and can be even passed over, as far as handles are created using the loop::resource member function.
On the other side, handles keep themselves alive until one explicitly closes them. Because of that, memory usage will grow if users simply forget about a handle.
Therefore the rule quickly becomes always close your handles. It's as simple as calling the close member function on them.

Requests

Usually initializing a request object is not required. Anyway, the recommended way to create a request is still through the loop::resource member function.
Requests will keep themselves alive as long as they are bound to unfinished underlying activities. This means that users don't have to discard a request explicitly .
Therefore the rule quickly becomes feel free to make a request and forget about it. It's as simple as calling a member function on them.

The Loop and the Resource

The first thing to do to use uvw is to create a loop. In case the default one is enough, it's easy as doing this:

auto loop = uvw::loop::get_default();

Note that loop objects don't require being closed explicitly, even if they offer the close member function in case a user wants to do that.
Loops can be started using the run member function. The two calls below are equivalent:

loop->run();
loop->run(uvw::loop::run_mode::DEFAULT);

Available modes are: DEFAULT, ONCE, NOWAIT. Please refer to the documentation of libuv for further details.

In order to create a resource and to bind it to the given loop, just do the following:

auto tcp = loop->resource<uvw::tcp_handle>();

The line above creates and initializes a tcp handle, then a shared pointer to that resource is returned.
Users should check if pointers have been correctly initialized: in case of errors, they won't be.
It also is possible to create uninitialized resources to init later on as:

auto tcp = loop->uninitialized_resource<uvw::tcp_handle>();
tcp->init();

All resources also accept arbitrary user-data that won't be touched in any case.
Users can set and get them through the data member function as it follows:

resource->data(std::make_shared<int>(42));
std::shared_ptr<void> data = resource->data();

Resources expect a std::shared_pointer<void> and return it, therefore any kind of data is welcome.
Users can explicitly specify a type other than void when calling the data member function:

std::shared_ptr<int> data = resource->data<int>();

Remember from the previous section that a handle will keep itself alive until one invokes the close member function on it.
To know what are the handles that are still alive and bound to a given loop, there exists the walk member function. It returns handles with their types. Therefore, the use of overloaded is recommended to be able to intercept all types of interest:

handle.parent().walk(uvw::overloaded{
    [](uvw::timer_handle &h){ /* application code for timers here */ },
    [](auto &&){ /* ignore all other types */ }
});

This function can also be used for a completely generic approach. For example, all the pending handles can be closed easily as it follows:

loop->walk([](auto &&h){ h.close(); });

No need to keep track of them.

The event-based approach

uvw offers an event-based approach where resources are small event emitters to which listeners are attached.
Attaching listeners to resources is the recommended way to receive notifications about their operations.
Listeners are callable objects of type void(event_type &, resource_type &), where:

  • event_type is the type of the event for which they have been designed.
  • resource_type is the type of the resource that has originated the event.

It means that the following function types are all valid:

  • void(event_type &, resource_type &)
  • void(const event_type &, resource_type &)
  • void(event_type &, const resource_type &)
  • void(const event_type &, const resource_type &)

Please note that there is no need to keep around references to the resources, since they pass themselves as an argument whenever an event is published.
The on member function is the way to go to register long-running listeners:

resource.on<event_type>(listener)

To know if a listener exists for a given type, the class offers a has function template. Similarly, the reset function template is be used to reset and thus disconnect listeners, if any. A non-template version of reset also exists to clear an emitter as a whole.

Almost all the resources emit error_event in case of errors.
All the other events are specific for the given resource and documented in the API reference.

The code below shows how to create a simple tcp server using uvw:

auto loop = uvw::loop::get_default();
auto tcp = loop->resource<uvw::tcp_handle>();

tcp->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { /* something went wrong */ });

tcp->on<uvw::listen_event>([](const uvw::listen_event &, uvw::tcp_handle &srv) {
    std::shared_ptr<uvw::tcp_handle> client = srv.parent().resource<uvw::tcp_handle>();
    client->on<uvw::end_event>([](const uvw::end_event &, uvw::tcp_handle &client) { client.close(); });
    client->on<uvw::data_event>([](const uvw::data_event &, uvw::tcp_handle &) { /* data received */ });
    srv.accept(*client);
    client->read();
});

tcp->bind("127.0.0.1", 4242);
tcp->listen();

Note also that uvw::tcp_handle already supports IPv6 out-of-the-box.
The API reference is the recommended documentation for further details about resources and their methods.

Going raw

In case users need to use functionalities not wrapped yet by uvw or if they want to get the underlying data structures as defined by libuv for some other reasons, almost all the classes in uvw give direct access to them.
Please, note that this functions should not be used directly unless users know exactly what they are doing and what are the risks. Going raw is dangerous, mainly because the lifetime management of a loop, a handle or a request is completely controlled by the library and working around it could quickly break things.

That being said, going raw is a matter of using the raw member functions:

auto loop = uvw::loop::get_default();
auto tcp = loop->resource<uvw::tcp_handle>();

uv_loop_t *raw = loop->raw();
uv_tcp_t *handle = tcp->raw();

Go the raw way at your own risk, but do not expect any support in case of bugs.

Contributors

If you want to contribute, please send patches as pull requests against the branch master.
Check the contributors list to see who has partecipated so far.

License

Code and documentation Copyright (c) 2016-2024 Michele Caini.
Logo Copyright (c) 2018-2021 Richard Caseres.

Code and documentation released under the MIT license.
Logo released under CC BY-SA 4.0.

Support

If you want to support this project, you can offer me an espresso.
If you find that it's not enough, feel free to help me the way you prefer.

uvw's People

Contributors

aloisklink avatar bmagistro avatar brenfwd avatar elindsey avatar ender-events avatar fcelda avatar ffontaine avatar filonik avatar gallexme avatar janekolszak avatar jopadan avatar lpmi-13 avatar lucamartini avatar miigon avatar moodyhunter avatar njakob avatar palkarz avatar pemensik avatar qix- avatar raoulh avatar reimunotmoe avatar sgiurgiu avatar skypjack avatar slyshyko avatar stefanofiorentino avatar tusharpm avatar tversteeg avatar uilianries avatar yisonpylkita avatar zxtwonder avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

uvw's Issues

Help wanted: libuv v2 is almost ready to release

It seems that libuv v2 is almost ready and it will be released on March (at least part of it).
uvw requires probably a good amount of work to support it and currently I've not much free time to work on this project. Moreover, I'm no longer using the library actively on any project, so I won't work on this during the day.

Unless either some volunteers show up here or someone is willing to consider funded development (contact me privately in this case), uvw will be discontinued or put under dual license if I find the time to work on uvw v2.


I'll close this issue in a couple of weeks.

Improve low-level TCP connection interface

I have an application that needs to do the following:

  • Resolve a DNS name
  • Try to connect to all the resolved addresses (until one succeeds)

This is currently difficult to do with the API exposed by uvw. The DNS interface is just fine, but I think the TCP connect methods need some work. Specifically, the TCP::connect methods take a string name, and only connect to the first resolved name.

Right now I've just kind of copied the logic from TCP::connect in my own application, which works but is kind of ugly (in my opinion). A cleaner way to do this would be to add a new TCP::connect overloaded method that accepts a pointer/reference to a struct addrinfo.

C++11 / C++14 status?

Great to see this fork is actively developed! 👍
Could you please enlighten the C++ standard focus? (11 vs. 14) The libuv wiki states it's '14 only, the title here says "modern". Would be great if this could integrate with larroy/uvpp#6 to be its successor.

uv_loop_t escape hatch?

Could an escape hatch be added to the Loop class that simply returns the internal uv_loop_t handle? I find myself having to add an accessor to get at it so that I can call any unwrapped functions (there are a couple still) or pass it to another libuv-based library.

multithread and shared_ptr usage

So I've heard libuv doesn't have a good way to support multi-thread out of the box (possibly something as easy as spawning a separate loop in each thread, not sure). It would be nice if uvw had a way to wrap the event loop this way optionally. If this is a welcome feature I may contribute once I get it working.

Also, using shared_ptr in single-threaded cases might not be worth the overhead in a library like this.
boost::shared_ptr<> has similar problems and using the single-thread define would enforce its use in the rest of the code. So, I'm thinking migrate to a system where the smart ptr impl can be selected by the user somehow, or pick a good alternative.

I'll probably contribute to development of this soon, since I'm quite interested in seeing something similar to node.js happen with C++ (was also interested in node.native).

Call for comments: make uvw allocator-aware

Currently, uvw allocates handles and requests using mainly std::make_shared. Memory is automatically released when a handle is closed or a request ends.

Making uvw allocator-aware could improve the way it manages memory. Moreover, applications could have a finer control over the memory usage and the allocation policy in general.

I'm not that sure it's worth adding such a feature to the library, but I can have a go with it.
If anyone out there is listening, every comment or suggestion is welcome as usual.

ProcessHandle::stdio problems and improvement

Multiple point here:
1- When trying to use

template<typename T>
ProcessHandle& stdio(Flags<StdIO> flags, FileHandle fd);

What is the use of T ? I think it should be removed, right?

2- Another problem I have is doing that:

proc->stdio(uvw::ProcessHandle::StdIO::CREATE_PIPE | uvw::ProcessHandle::StdIO::READABLE_PIPE, pipe);

It fails to build because of the | (OR) operator that is not found. Am I missing something here?

3- Finally, the stdio() API could be somehow improved because it is painful to do something like:

  uv_pipe_init(uv_default_loop(), &out, 0);
  options.stdio = stdio;
  options.stdio[0].flags = UV_IGNORE;
  options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
  options.stdio[1].data.stream = (uv_stream_t*)&out;
  options.stdio_count = 2;
  r = uv_spawn(uv_default_loop(), &process, &options);

is not working right now using uvw (or I missed something?) I tried to do this:

  pipe = uvw::Loop::getDefault()->resource<uvw::PipeHandle>();
  proc->stdio(uvw::ProcessHandle::StdIO::IGNORE_STREAM, static_cast<uvw::FileHandle>(0));
  //The ignore stream flag I must use FileHandle(0)... ?

  proc->stdio(uvw::ProcessHandle::StdIO::CREATE_PIPE | uvw::ProcessHandle::StdIO::READABLE_PIPE, *pipe);

Patreon

Hi all,

I created this issue to make you know that I opened a patreon account to support this and other projects of mine.
The idea is to get uvw out of the maintenance mode, port it to C++17 and continue to maintain the C++14 version, greatly reduce compilation time, make it fully allocator-aware, start adding more features as some of you asked during the last months and so on, up to the creation of a sort of lightweight and native counterpart of node js targeted to C++ developers.

However, I need your help to do that.
I'm doing all of this in my free time at the moment and it's hard to go straight to the goal in a short time sometimes.
If you find you're interested in supporting me and the project you use, here is a way to do that.

Thank you all in any case for the support shown so far.

GCC minimum version required

Actually uvw requires a C++14 compiler. Problem is C++14 have a lots of features and not all compiler have all C++14 features working. I tried to build my project using uvw on a Debian Jessie where the current GCC is 4.9.2.

I have a c++14 detection macro in my autotools to detect C++14 availability from the compiler and GCC4.9.2 say it can do C++14.
But I have an error in the build:

uvw/src/uvw/fs.hpp:190:45: error: cannot convert 'std::remove_reference<uv_stat_t&>::type {aka uv_stat_t}' to 'uint64_t {aka long unsigned int}' in initialization
         : path{_path}, stat{std::move(_stat)}

My question here is: Is there a minimum required GCC version that we can check on, or is it worth trying to workaround compilation issue like this one above? or maybe do you know if some checks can be done to detect if compiler can handle this code or not?

Please don't default BUILD_TESTING to ON - it messes with other projects

BUILD_TESTING is considered a 'special' option for the entire CMake environment, and is thus used across all projects that use CMake.

Explicitly defining it using option() is unnecessary (using it in an if() when it hasn't explicitly been set just results in a falsey conditional value) -- and further, specifying it as ON causes drastically higher compilation times for those that do not want them.

A small fix in process I/O initialization

If I understand the intentions correctly, the following code inside process.hpp

        std::vector<uv_stdio_container_t> poStdio{poFdStdio.size() + poStreamStdio.size()};
        poStdio.insert(poStdio.begin(), poStreamStdio.cbegin(), poStreamStdio.cend());
        poStdio.insert(poStdio.begin(), poFdStdio.cbegin(), poFdStdio.cend());

should be changed to something like this:

        std::vector<uv_stdio_container_t> poStdio{ poFdStdio.size() + poStreamStdio.size() };
        std::copy(poFdStdio.cbegin(), poFdStdio.cend(), poStdio.begin());
        std::copy(poStreamStdio.cbegin(), poStreamStdio.cend(), poStdio.begin() + poStreamStdio.size());

And thanks for the library. It's MUCH nicer to use then the raw libuv.

Expose type in BaseHandle

From the libuv docs it appears that uv_handle_t has the ability to provide the type. It would be nice if this was also available in uvw. Per docs calling loop->walk on the thread's loop only provides the count and cannot get you back to the handle type.

Use case:
We would like to report periodic stats on the number of open/active handles in a thread grouped by type.

Edit:
Co worker suggested using typeid() which does seem to allow me to get back to the type.

Assert in libuv

Hi,

I have a strange bug, and don't know if it's in uvw, libuv or my own code. I will explain here and maybe someone has any hints.

I have an Idle handle that start a process at some point. It works and at some random point in time my my code crashes with an assert exactly when the process is launched:

[INF] lua (ScriptExec.cpp:39) Starting script. (0xd7b480)
[INF] process (ExternProc.cpp:191) Starting process: /usr/bin/calaos_script --socket /tmp/calaos_proc_c79ad522-33ff-978a-3d31-08070a51c459_lua_21499 --namespace lua
calaos_server: ../libuv-1.19.1/src/unix/stream.c:1574: uv_read_start: Assertion `uv__stream_fd(stream) >= 0' failed.

What my code does is basically easy:

  • it create a uvw::ProcessHandle
  • setup uvw::ExitEvent and uvw::ErrorEvent for the process handle
  • then create a uvw::PipeHandle for communicating with the process
  • setup uvw::EndEvent and uvw::DataEvent for the pipe
  • spawn the process
  • start pipe->read() (aka. uv_read_start())

Full code of the function is here:
https://github.com/calaos/calaos_base/blob/master/src/bin/calaos_server/IO/ExternProc.cpp#L147

It works. Sometime it works for a long time (hours). And then it crashes with this backtrace:

Program received signal SIGABRT, Aborted.
__GI_raise (sig=sig@entry=6) at /usr/src/debug/glibc/2.25-r0/git/sysdeps/unix/sysv/linux/raise.c:51
51      }
(gdb) bt
#0  __GI_raise (sig=sig@entry=6) at /usr/src/debug/glibc/2.25-r0/git/sysdeps/unix/sysv/linux/raise.c:51
#1  0x000000310e23450a in __GI_abort () at /usr/src/debug/glibc/2.25-r0/git/stdlib/abort.c:89
#2  0x000000310e22bfe7 in __assert_fail_base (fmt=<optimized out>, assertion=assertion@entry=0x7ffff7deaca6 "uv__stream_fd(stream) >= 0",
    file=file@entry=0x7ffff7dea998 "../libuv-1.19.1/src/unix/stream.c", line=line@entry=1574, function=function@entry=0x7ffff7deae48 <__PRETTY_FUNCTION__.9160> "uv_read_start")
    at /usr/src/debug/glibc/2.25-r0/git/assert/assert.c:92
#3  0x000000310e22c092 in __GI___assert_fail (assertion=assertion@entry=0x7ffff7deaca6 "uv__stream_fd(stream) >= 0",
    file=file@entry=0x7ffff7dea998 "../libuv-1.19.1/src/unix/stream.c", line=line@entry=1574, function=function@entry=0x7ffff7deae48 <__PRETTY_FUNCTION__.9160> "uv_read_start")
    at /usr/src/debug/glibc/2.25-r0/git/assert/assert.c:101
#4  0x00007ffff7de316d in uv_read_start (stream=stream@entry=0xd8b418,
    alloc_cb=alloc_cb@entry=0x48ffe0 <uvw::Handle<uvw::PipeHandle, uv_pipe_s>::allocCallback(uv_handle_s*, unsigned long, uv_buf_t*)>,
    read_cb=read_cb@entry=0x498320 <uvw::StreamHandle<uvw::PipeHandle, uv_pipe_s>::readCallback(uv_stream_s*, long, uv_buf_t const*)>)
    at /usr/src/debug/libuv/1.19.1-r0/libuv-1.19.1/src/unix/stream.c:1574
#5  0x0000000000497bf9 in uvw::Handle<uvw::PipeHandle, uv_pipe_s>::invoke<int (*)(uv_stream_s*, void (*)(uv_handle_s*, unsigned long, uv_buf_t*), void (*)(uv_stream_s*, long, uv_buf_t const*)), uv_stream_s*, void (*)(uv_handle_s*, unsigned long, uv_buf_t*), void (*)(uv_stream_s*, long, uv_buf_t const*)>(int (*&&)(uv_stream_s*, void (*)(uv_handle_s*, unsigned long, uv_buf_t*), void (*)(uv_stream_s*, long, uv_buf_t const*)), uv_stream_s*&&, void (*&&)(uv_handle_s*, unsigned long, uv_buf_t*), void (*&&)(uv_stream_s*, long, uv_buf_t const*)) (f=<optimized out>, this=0xd8b3b0) at /usr/src/debug/calaos-server/1_3.0-rc1+r0+gitAUTOINC+19f8b098fd-r0/git/src/lib/uvw/src/uvw/handle.hpp:62
#6  uvw::StreamHandle<uvw::PipeHandle, uv_pipe_s>::read (this=0xd8b3b0)
    at /usr/src/debug/calaos-server/1_3.0-rc1+r0+gitAUTOINC+19f8b098fd-r0/git/src/lib/uvw/src/uvw/stream.hpp:228
#7  ExternProcServer::startProcess (this=0xd7b480, process=..., name=..., args=...)
    at /usr/src/debug/calaos-server/1_3.0-rc1+r0+gitAUTOINC+19f8b098fd-r0/git/src/bin/calaos_server/IO/ExternProc.cpp:193
#8  0x000000000062b8f3 in ScriptExec::ExecuteScriptDetached(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::function<void (bool)>, Params) (script=..., cb=..., env=...) at /usr/src/debug/calaos-server/1_3.0-rc1+r0+gitAUTOINC+19f8b098fd-r0/git/src/bin/calaos_server/LuaScript/ScriptExec.cpp:150
#9  0x000000000063c021 in Calaos::ActionScript::Execute (this=<optimized out>)
    at /usr/src/debug/calaos-server/1_3.0-rc1+r0+gitAUTOINC+19f8b098fd-r0/git/src/bin/calaos_server/Rules/ActionScript.cpp:39
#10 0x00000000006358f1 in Calaos::Rule::ExecuteActions (this=0xc441f0)
    at /usr/src/debug/calaos-server/1_3.0-rc1+r0+gitAUTOINC+19f8b098fd-r0/git/src/bin/calaos_server/Rule.cpp:148
#11 0x0000000000626eae in Calaos::ListeRule::ExecuteRuleSignal (this=this@entry=0x977980 <Calaos::ListeRule::Instance()::inst>, id=...)
    at /usr/src/debug/calaos-server/1_3.0-rc1+r0+gitAUTOINC+19f8b098fd-r0/git/src/bin/calaos_server/ListeRule.cpp:182
#12 0x00000000006241ce in Calaos::ListeRule::<lambda()>::operator() (__closure=0xd8b660)
    at /usr/src/debug/calaos-server/1_3.0-rc1+r0+gitAUTOINC+19f8b098fd-r0/git/src/bin/calaos_server/ListeRule.cpp:101
#13 sigc::adaptor_functor<Calaos::ListeRule::ExecuteRuleSignal(std::__cxx11::string)::<lambda()> >::operator() (this=0xd8b660)
    at /usr/include/sigc++-2.0/sigc++/adaptors/adaptor_trait.h:256
#14 sigc::internal::slot_call0<Calaos::ListeRule::ExecuteRuleSignal(std::__cxx11::string)::<lambda()>, void>::call_it(sigc::internal::slot_rep *) (rep=0xd8b630)
    at /usr/include/sigc++-2.0/sigc++/functors/slot.h:114
#15 0x0000000000670602 in sigc::slot0<void>::operator() (this=0xd8b608) at /usr/include/sigc++-2.0/sigc++/functors/slot.h:513
#16 Idler::<lambda()>::operator() (__closure=0xd8b608) at /usr/src/debug/calaos-server/1_3.0-rc1+r0+gitAUTOINC+19f8b098fd-r0/git/src/lib/Timer.cpp:136
#17 sigc::adaptor_functor<Idler::singleIdler(sigc::slot<void>)::<lambda()> >::operator() (this=0xd8b600) at /usr/include/sigc++-2.0/sigc++/adaptors/adaptor_trait.h:256
#18 sigc::internal::slot_call<Idler::singleIdler(sigc::slot<void>)::<lambda()>, void>::call_it(sigc::internal::slot_rep *) (rep=0xd8b5d0)
    at /usr/include/sigc++-2.0/sigc++/functors/slot.h:461
#19 0x000000000066f84a in sigc::internal::signal_emit0<void, sigc::nil>::emit (impl=0xd6ef20) at /usr/include/sigc++-2.0/sigc++/signal.h:794
#20 sigc::signal0<void, sigc::nil>::emit (this=<optimized out>) at /usr/include/sigc++-2.0/sigc++/signal.h:2800
#21 Idler::<lambda(const auto:32&, auto:33&)>::operator()<uvw::IdleEvent, uvw::IdleHandle> (__closure=<optimized out>)
    at /usr/src/debug/calaos-server/1_3.0-rc1+r0+gitAUTOINC+19f8b098fd-r0/git/src/lib/Timer.cpp:125
#22 std::_Function_handler<void(uvw::IdleEvent&, uvw::IdleHandle&), Idler::createIdler()::<lambda(const auto:32&, auto:33&)> >::_M_invoke(const std::_Any_data &, uvw::IdleEvent &, uvw::IdleHandle &) (__functor=..., __args#0=..., __args#1=...) at /usr/include/c++/6.3.0/functional:1731
#23 0x000000000066f95e in std::function<void (uvw::IdleEvent&, uvw::IdleHandle&)>::operator()(uvw::IdleEvent&, uvw::IdleHandle&) const (__args#1=..., __args#0=...,
    this=<optimized out>) at /usr/include/c++/6.3.0/functional:2127
#24 _ZZN3uvw7EmitterINS_10IdleHandleEE7HandlerINS_9IdleEventEE7publishES4_RS1_ENKUlOT_E_clIRSt4pairIbSt8functionIFvRS4_S6_EEEEEDaS8_ (element=..., __closure=<synthetic pointer>)
    at /usr/src/debug/calaos-server/1_3.0-rc1+r0+gitAUTOINC+19f8b098fd-r0/git/src/lib/uvw/src/uvw/emitter.hpp:118
#25 _ZSt8for_eachISt16reverse_iteratorISt14_List_iteratorISt4pairIbSt8functionIFvRN3uvw9IdleEventERNS4_10IdleHandleEEEEEEZNS4_7EmitterIS7_E7HandlerIS5_E7publishES5_S8_EUlOT_E_ET0_SI_SI_SL_ (__first=..., __last=..., __f=...) at /usr/include/c++/6.3.0/bits/stl_algo.h:3769
#26 0x000000000066fedd in uvw::Emitter<uvw::IdleHandle>::Handler<uvw::IdleEvent>::publish (ref=..., event=..., this=<optimized out>)
    at /usr/src/debug/calaos-server/1_3.0-rc1+r0+gitAUTOINC+19f8b098fd-r0/git/src/lib/uvw/src/uvw/emitter.hpp:123
#27 uvw::Emitter<uvw::IdleHandle>::publish<uvw::IdleEvent> (this=0xd8b268, event=...)
    at /usr/src/debug/calaos-server/1_3.0-rc1+r0+gitAUTOINC+19f8b098fd-r0/git/src/lib/uvw/src/uvw/emitter.hpp:166
#28 uvw::IdleHandle::startCallback (handle=<optimized out>) at /usr/src/debug/calaos-server/1_3.0-rc1+r0+gitAUTOINC+19f8b098fd-r0/git/src/lib/uvw/src/uvw/idle.hpp:40
#29 0x00007ffff7dde3c4 in uv__run_idle (loop=loop@entry=0x7ffff7ff2cc0 <default_loop_struct>) at /usr/src/debug/libuv/1.19.1-r0/libuv-1.19.1/src/unix/loop-watcher.c:68
#30 0x00007ffff7dd8175 in uv_run (loop=0x7ffff7ff2cc0 <default_loop_struct>, mode=mode@entry=UV_RUN_DEFAULT) at /usr/src/debug/libuv/1.19.1-r0/libuv-1.19.1/src/unix/core.c:361
#31 0x0000000000413e99 in uvw::Loop::run<(uvw::details::UVRunMode)0> (this=<optimized out>)
    at /usr/src/debug/calaos-server/1_3.0-rc1+r0+gitAUTOINC+19f8b098fd-r0/git/src/lib/uvw/src/uvw/loop.hpp:284
#32 main (argc=<optimized out>, argv=<optimized out>) at /usr/src/debug/calaos-server/1_3.0-rc1+r0+gitAUTOINC+19f8b098fd-r0/git/src/bin/calaos_server/main.cpp:185

When inspecting the stream->io_watcher.fd it is -1. So the assert is correct that the uv_read cannot start- But why is this sometime -1... I really don't know...

(gdb) p *stream
$1 = {data = 0xd8b3b0, loop = 0x7ffff7ff2cc0 <default_loop_struct>, type = UV_NAMED_PIPE, close_cb = 0x0, handle_queue = {0xd88488, 0xd8bb78}, u = {fd = 0, reserved = {0x0,
      0x0, 0x0, 0x0}}, next_closing = 0x0, flags = 8196, write_queue_size = 0, alloc_cb = 0x0, read_cb = 0x0, connect_req = 0x0, shutdown_req = 0x0, io_watcher = {
    cb = 0x7ffff7de2170 <uv__stream_io>, pending_queue = {0xd8b4a8, 0xd8b4a8}, watcher_queue = {0xd8b4b8, 0xd8b4b8}, pevents = 0, events = 0, fd = -1}, write_queue = {0xd8b4d8,
    0xd8b4d8}, write_completed_queue = {0xd8b4e8, 0xd8b4e8}, connection_cb = 0x0, delayed_error = 0, accepted_fd = -1, queued_fds = 0x0}

My question here is: do I need to setup something or check something prior starting pipe->read() ? Is it a bug in libuv? uvw?

Thank you very much for any pointer.

buffer management

Thanks Before for wonderful project (y).
Several weeks ago I gave up upon libuv buffer management. I didn't have any idea how to receive clean server data at any size on no matter how much client send. calling uv_read_start requires to call again uv_read_start at the next incoming buffer echo_cb. Say I send 2 mb data post data via curl. how to make uv_read_start friendly by I means without calling uv_read_start again at echo_read_cb. I have set either uv_recv_buffer_size before uv_listen and alloc_cb in uv_read_start to 3mb instead of 65kb yields no effect. Is this case solvable in uvw project?

Proper way to copy buffer

How to make local copy of this buffer correctly, this code silently segfaults on msvc 2015 update 3.

    srv.accept(*client);
    uvw::Addr local = srv.sock();
    std::cout << "local: " << local.ip << " " << local.port << std::endl;
    std::string buffer="";
    uvw::Addr remote = client->peer();
    std::cout << "remote: " << remote.ip << " " << remote.port << std::endl;
    client->on<uvw::DataEvent>(
        [&buffer](const uvw::DataEvent &event, uvw::TcpHandle &client) { 
                  std::cout << "\ndata length: " << event.length <<
                      std::endl;
          std::cout << " data event called"; 
          std::stringstream stm;
          stm<<std::string(event.data.get (),event.length); 
          std::string tmp=stm.str ();
          //either of these code fails to copy
        // std::copy(tmp.begin (),tmp.end (),std::back_inserter(buffer)); //crash
          buffer.append (tmp.c_str()); //crash here
        });

thanks

Problems building projects

Hello,

I am on OpenSuse with a separate download of the libuv project.

I tried:

cd build 
cmake ..

and

cd tests/build
cmake ..

Both did not result into some correct build.
Maybe something should be populated in the deps folder. But I see no information what exactly.

Actually i am just trying to build an example in a separate project

https://github.com/mulderp/uvw_sandbox

Maybe you have some pointers what I can try.

Thanks a lot!

ErrorEvent should contain more details

I suggest ErrorEvent contains operation details, so user can retrieve more informations.
Errors from various opertaions could identify by sub-classes of ErrorEvent, such as:

handle->on<uvw::ErrorEvent>([](const uvw::ErrorEvent &event, uvw::UdpHandle &handle) {
    switch (event.operation())
    {
        case uvw::UdpHandle::Operation::Bind:
        {
            const uvw::UdpBindFailedEvent& e = static_cast<const uvw::UdpBindFailedEvent&>(event);
            // contains uvw::Addr addr()
            break;
        }
        case uvw::UdpHandle::Operation::Send:
        {
            const uvw::UdpSendErrorEvent& e = static_cast<const uvw::UdpSendErrorEvent&>(event);
            // UdpSendErrorEvent contains same member as UDPDataEvent
            break;
        }
        default:
            break;
    }
});
client->bind(address, port);
client->send(uvw::Addr{ address , port }, std::move(dataSend), 2);

To achieve this, Request can be used instead of Handler class methods(like SendReq), but it's not so convenient as handler classes.

How to decide whether Addr is IPV4 or IPV6

Hello,

I met some trouble while dealing with UDPHandle.

auto handle = loop.resource<uvw::UDPHandle>();
handle->on<uvw::UDPDataHandle>(
    [](const uvw::UDPDataEvent &event, uvw::UDPHandle &handle) {
            Addr sender = event.sender;
            // I want to know that sender is whether v4 or v6
            // so that I can call handle->send<V4_OR_V6>(...)
    }
);

Is there any workaround?
I think it may be convenience to get a `struct sockaddr &' in the callback.

Building problems in Ubuntu 16.04 Server Edition

`marco@PC:~$ cd uvw/
marco@PC:~/uvw$ cd build/
marco@PC:~/uvw/build$ cmake ..
-- The C compiler identification is GNU 8.1.0
-- The CXX compiler identification is GNU 8.1.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
*
* uvw v1.10.0 (Debug)
* Copyright (c) 2018 Michele Caini <[email protected]>
*
-- Looking for pthread.h
-- Looking for pthread.h - found
-- Looking for pthread_create
-- Looking for pthread_create - not found
-- Check if compiler accepts -pthread
-- Check if compiler accepts -pthread - yes
-- Found Threads: TRUE
-- Could NOT find Doxygen (missing:  DOXYGEN_EXECUTABLE) (Required is at least version "1.8")
-- Configuring done
-- Generating done
-- Build files have been written to: /home/marco/uvw/deps/googletest
Scanning dependencies of target googletest
[ 11%] Creating directories for 'googletest'
[ 22%] Performing download step (git clone) for 'googletest'
Cloning into 'src'...
Already on 'master'
Your branch is up-to-date with 'origin/master'.
[ 33%] No patch step for 'googletest'
[ 44%] Performing update step for 'googletest'
Current branch master is up to date.
[ 55%] No configure step for 'googletest'
[ 66%] No build step for 'googletest'
[ 77%] No install step for 'googletest'
[ 88%] No test step for 'googletest'
[100%] Completed 'googletest'
[100%] Built target googletest
-- Found PythonInterp: /usr/bin/python (found version "2.7.12")
-- Configuring done
-- Generating done
-- Build files have been written to: /home/marco/uvw/deps/libuv
Scanning dependencies of target libuv
[ 11%] Creating directories for 'libuv'
[ 22%] Performing download step (git clone) for 'libuv'
Cloning into 'src'...
Note: checking out 'v1.21.0'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b <new-branch-name>

HEAD is now at e4983a9... 2018.06.23, Version 1.21.0 (Stable)
[ 33%] No patch step for 'libuv'
[ 44%] Performing update step for 'libuv'
[ 55%] Performing configure step for 'libuv'
/home/marco/uvw/deps/libuv/src/autogen.sh: 1: /home/marco/uvw/deps/libuv/src/autogen.sh:   
automake: not found
/home/marco/uvw/deps/libuv/src/autogen.sh: 33: test: Illegal number:
/home/marco/uvw/deps/libuv/src/autogen.sh: 34: test: Illegal number:
+ libtoolize --copy
/home/marco/uvw/deps/libuv/src/autogen.sh: 43: /home/marco/uvw/deps/libuv/src/autogen.sh:   
libtoolize: not found
CMakeFiles/libuv.dir/build.make:106: recipe for target 'stamp/libuv-configure' failed
make[2]: *** [stamp/libuv-configure] Error 127
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/libuv.dir/all' failed
make[1]: *** [CMakeFiles/libuv.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
CMake Error: The following variables are used in this project, but they are set to NOTFOUND.
Please set them or make sure they are set and tested correctly in the CMake files:
libuv_static
    linked by target "util" in directory /home/marco/uvw/test
    linked by target "work" in directory /home/marco/uvw/test
    linked by target "fs_req" in directory /home/marco/uvw/test
    linked by target "udp" in directory /home/marco/uvw/test
    linked by target "handle" in directory /home/marco/uvw/test
    linked by target "fs_event" in directory /home/marco/uvw/test
    linked by target "thread" in directory /home/marco/uvw/test
    linked by target "fs_poll" in directory /home/marco/uvw/test
    linked by target "main" in directory /home/marco/uvw/test
    linked by target "loop" in directory /home/marco/uvw/test
    linked by target "file_req" in directory /home/marco/uvw/test
    linked by target "idle" in directory /home/marco/uvw/test
    linked by target "emitter" in directory /home/marco/uvw/test
    linked by target "async" in directory /home/marco/uvw/test
    linked by target "dns" in directory /home/marco/uvw/test
    linked by target "prepare" in directory /home/marco/uvw/test
    linked by target "lib" in directory /home/marco/uvw/test
    linked by target "process" in directory /home/marco/uvw/test
    linked by target "check" in directory /home/marco/uvw/test
    linked by target "resource" in directory /home/marco/uvw/test
    linked by target "signal" in directory /home/marco/uvw/test
    linked by target "poll" in directory /home/marco/uvw/test
    linked by target "stream" in directory /home/marco/uvw/test
    linked by target "tcp" in directory /home/marco/uvw/test
    linked by target "request" in directory /home/marco/uvw/test
    linked by target "timer" in directory /home/marco/uvw/test
    linked by target "tty" in directory /home/marco/uvw/test
    linked by target "underlying_type" in directory /home/marco/uvw/test
    linked by target "pipe" in directory /home/marco/uvw/test

-- Configuring incomplete, errors occurred!
See also "/home/marco/uvw/build/CMakeFiles/CMakeOutput.log".
See also "/home/marco/uvw/build/CMakeFiles/CMakeError.log".
marco@PC:~/uvw/build$
`

What to do to solve the problem?
Marco

Broken example

At least on Ubuntu 16.04 with g++-5, clang++-3.8, the example from readme seems to require some update:

mmm@mmm-U2442:~/devel/uvw/build$ clang++-3.8 -I ../src/ -std=c++14 -o socket_example example.cpp 
In file included from example.cpp:1:
In file included from ../src/uvw.hpp:1:
In file included from ../src/uvw/async.hpp:8:
In file included from ../src/uvw/handle.hpp:9:
../src/uvw/util.hpp:188:28: error: use of undeclared identifier 'uv_passwd_t'
    Passwd(std::shared_ptr<uv_passwd_t> passwd): passwd{passwd} { }
                           ^
../src/uvw/util.hpp:188:28: error: use of undeclared identifier 'uv_passwd_t'
../src/uvw/util.hpp:197:21: error: use of undeclared identifier 'uv_passwd_t'
    std::shared_ptr<uv_passwd_t> passwd;
                    ^
../src/uvw/util.hpp:382:35: error: use of undeclared identifier 'uv_os_tmpdir'
            return details::path(&uv_os_tmpdir);
                                  ^
../src/uvw/util.hpp:398:31: error: unknown type name 'uv_passwd_t'
            auto deleter = [](uv_passwd_t *passwd){
                              ^
../src/uvw/util.hpp:403:29: error: use of undeclared identifier 'uv_passwd_t'
            std::shared_ptr<uv_passwd_t> ptr{new uv_passwd_t, std::move(deleter)};
                            ^
../src/uvw/util.hpp:403:42: error: C++ requires a type specifier for all declarations
            std::shared_ptr<uv_passwd_t> ptr{new uv_passwd_t, std::move(deleter)};
                                         ^
../src/uvw/util.hpp:403:50: error: unknown type name 'uv_passwd_t'
            std::shared_ptr<uv_passwd_t> ptr{new uv_passwd_t, std::move(deleter)};
                                                 ^
In file included from example.cpp:1:
In file included from ../src/uvw.hpp:12:
../src/uvw/poll.hpp:22:18: error: use of undeclared identifier 'UV_DISCONNECT'; did you mean 'UV_CONNECT'?
    DISCONNECT = UV_DISCONNECT
                 ^~~~~~~~~~~~~
                 UV_CONNECT
/usr/include/uv.h:192:19: note: 'UV_CONNECT' declared here
  UV_REQ_TYPE_MAP(XX)
                  ^
In file included from example.cpp:1:
In file included from ../src/uvw.hpp:1:
In file included from ../src/uvw/async.hpp:8:
In file included from ../src/uvw/handle.hpp:9:
../src/uvw/util.hpp:327:54: error: too few arguments to function call, expected 4, have 2
    auto err = std::forward<F>(f)(args..., buf, &size);
               ~~~~~~~~~~~~~~~~~~                    ^
../src/uvw/util.hpp:382:29: note: in instantiation of function template specialization 'uvw::details::path<int (*)(uv_loop_s *, uv_fs_s *, const char *, void (*)(uv_fs_s *))>'
      requested here
            return details::path(&uv_os_tmpdir);
                            ^
10 errors generated.

build error with vs2017

1>uvw\stream.hpp(162): error C2061: syntax error: identifier 'ConstructorAccess'
1>uvw\stream.hpp(448): note: see reference to class template instantiation 'uvw::StreamHandle<T,U>' being compiled
1>uvw\resource.hpp(19): note: see reference to class template instantiation 'uvw::UnderlyingType<T,U>' being compiled
......................

The same source code can build successful with vs2015

#94 broke Process class

#94 accidentally removed friend declaration and get member functions that accept a Resource as an argument. It broke Process class and probably some others classes.
We should put back that stuff in the UnderlyingType class to make it working again.

FileReq::data data member shadows Resource::data member function

We know that the FileReq is inherited from Request and Request is inherited from Resource. However, FileReq has a data member FileReq::data whose name is same as Resource::data member function. Therefore, I have to call Resource::data like this:

req->uvw::Resource<uvw::FileReq, uv_fs_t>::data(ctx);

which is quite not elegant and annoying since I have to know the template arguments of Resource.

racecondition in posix platform

Hey Michele,

File:
uvw/src/uvw/fs.hpp:1177
uvw/test/uvw/fs_req.cpp:298

    fileReq->on<uvw::FsEvent<uvw::FileReq::Type::CLOSE>>([&fsReq, &filename](const auto &, auto &) {
        fsReq->access(filename, R_OK);
});

I believe this indicates a security flaw, If an attacker can change anything along the path between the call access() and the files actually used, attacker may exploit the race condition or a time-of-check, time-of-use race condition, request team to please have a look and validate.

Reference: https://linux.die.net/man/2/access

Provide doc howto link to custom libuv

Would you consider improving the Readme with a more detailed guide how to link against a custom (built from source, as the newest version is required, #64) libuv, please?

Status:

  • successfully installed libuv latest from git to /usr/local ; as >=1.9 is required (#64)
  • older version of libuv is also installed on my system (ubuntu 16.04) as a dependency of other packages
  • the cmake .. phase fails, due to libuv not found:
Could NOT find UV (missing: UV_STATIC_LIBRARY UV_SHARED_LIBRARY
  UV_INCLUDE_DIR)

Need help using uvw together with boost::coroutines2

I don't know where to ask. So I ended up with submitting an issue here.
I'm new to libuv & uvw. I'm trying to apply async-await pattern to libuv, so I tried using uvw together with boost::coroutines2.

template<typename EventType, typename EmitterType>
EventType awaitEvent(std::shared_ptr<uvw::Loop>& loop, std::shared_ptr<EmitterType>& emitter) {
    using coro_t = boost::coroutines2::coroutine<EventType>;
    
    typename coro_t::pull_type source([&](typename coro_t::push_type& sink) {
        typename EmitterType::template Connection<EventType> ok;
        auto err = emitter->template once<uvw::ErrorEvent>([&](uvw::ErrorEvent &error, auto&) {
            emitter->template erase(ok);
            throw error;
        });
        ok = emitter->template once<EventType>([&](EventType& event, auto&) {
            emitter->template erase(err);
            sink(std::move(event));
        });
        loop->run<uvw::Loop::Mode::ONCE>();
    });
    auto result = std::move(source().get());
    source();
    return result;
}

To use it:

auto fileReq = loop->resource<FileReq>();

fileReq->open(path + "/" + event.filename, Flags<FileReq::FileOpen>(FileReq::FileOpen::RDONLY), S_IRUSR);

awaitEvent<FsEvent<FsReq::Type::OPEN>>(loop, fileReq);

fileReq->stat();
const auto fileSize = awaitEvent<FsEvent<FsReq::Type::STAT>>(loop, fileReq).stat.st_size;

The program always crashes at the second awaitEvent because loop->run<uvw::Loop::Mode::ONCE>(); won't wait for next fs_event. If I changes the line to loop->run();, the program hangs forever.

I know it's not a good place to ask libuv usage, but I don't know where to ask. Please help. This is the full code(crashes at line 27) if needed.

Thanks in advance.

Build error with vs2019

I try to use v1.16.0_libuv-v1.28 release on Visual Studio 2019, and I got following errors:
image
Here are part of the compiler output:

1>------ Build started: Project: Server, Configuration: Debug x64 ------
1>pch.cpp
1>C:\source\Server\include\uvw\lib.hpp(68,1): error C3537:  you cannot cast to a type that contains 'auto'
1>C:\source\Server\include\uvw\lib.hpp(68,1): message :  This diagnostic occurred in the compiler generated function 'F *uvw::SharedLib::sym(std::string)'
1>C:\source\Server\include\uvw\lib.hpp(68,1): error C2100:  illegal indirection
1>C:\source\Server\include\uvw\lib.hpp(68,1): message :  This diagnostic occurred in the compiler generated function 'F *uvw::SharedLib::sym(std::string)'
1>C:\source\Server\include\uvw\thread.hpp(109,36): warning C4838:  conversion from 'uvw::Flags<uvw::Thread::Options>' to 'unsigned int' requires a narrowing conversion
1>C:\source\Server\include\uvw\thread.hpp(165,1): error C3537:  you cannot cast to a type that contains 'auto'
1>C:\source\Server\include\uvw\thread.hpp(165,1): message :  This diagnostic occurred in the compiler generated function 'T *uvw::ThreadLocalStorage::get(void) noexcept'
1>C:\source\Server\include\uvw\thread.hpp(165,1): error C2100:  illegal indirection

My cl.exe version is Microsoft (R) C/C++ Optimizing Compiler Version 19.21.27619.1 for x64

Rename UDP to Udp

I suggest rename all UDP in class names such as UDPDataEvent and UDPHandle to Udp, to get consistency with those Tcp classes which already use camel-case rather than uppercase.

Request: CMake library target

Hello!

Could you please add library target to CMakeLists? I want to use the library as cmake sub-project:

add_subdirectory(deps/uvw EXCLUDE_FROM_ALL)
...
add_executable(app ${sources})
target_link_libraries(app skypjack::uvw) # or target_link_libraries(app uvw)

In your CMakeLists.txt need to add something like:

add_library(uvw INTERFACE)
add_library(skypjack::uvw ALIAS uvw) # optional
target_include_directories(uvw INTERFACE ${LIBUV_DEPS_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/src)
target_link_libraries(uvw INTERFACE ${libuv_static})
target_compile_features(uvw INTERFACE cxx_std_14)

Thanks

vectorised writes on uv_stream_t handles

Hi,

I was looking through the documentation, and it seems that uvw does not expose a way to write multiple buffers in one uv_write. While I could use the raw handle and circumvent uvw, I am left wondering why this is the case and if you would introduce support for vectorised writes in the future.

cpp14 branch

Please consider having a cpp14 branch. We have an embedded platform whose compiler does not yet support cpp17.

uvw::CheckEvent is never fired in DEFAULT loop mode.

The following test code hangs but no output occurs. A run through with lldb/gdb prove the callback is never hit.

#include <iostream>

#include "uvw.hpp"

using namespace std;

int main() {
	auto loop = uvw::Loop::getDefault();
	auto handle = loop->resource<uvw::CheckHandle>();

	handle->on<uvw::ErrorEvent>([](const auto &, auto &) {
		cerr << "ERROR" << endl;
	});

	handle->on<uvw::CheckEvent>([](const auto &, auto &) {
		cerr << "poll" << endl;
	});

	handle->start();

	loop->run();
}

Running with NOWAIT, as in the tests, correctly show poll once, but the tests don't check an actual loop.

loop->run<uvw::Loop::Mode::NOWAIT>();

I'll submit a failing test case.

Internal compiler error

Hi,

When build on a fresh ubuntu 16.04 that uses gcc 5.4.0, compiler crashes with the following:

uvw/src/uvw/process.hpp:235:49: internal compiler error: in tsubst_copy, at cp/pt.c:13217
         container.data.stream = get<uv_stream_t>(stream);
                                                 ^
Please submit a full bug report,
with preprocessed source if appropriate.

Any ideas on this one?

Logo

Hi all,

I just realized that we don't have a logo for uvw yet. :-)
It would be great if someone wanted to suggest something or make a contribution directly with an image.
Thank you very much for your help!!

Crash when using process

Hi,

Using that example code:

#include <iostream>
#include "uvw.hpp"

class Object
{
public:
    Object()
    {
        std::cout << "Object()" << std::endl;
        proc = uvw::Loop::getDefault()->resource<uvw::ProcessHandle>();
        proc->once<uvw::ExitEvent>([](const uvw::ExitEvent &, auto &h)
        {
            std::cout << "process exited" << std::endl;
            h.close();
        });

        char *args[3];
        args[0] = "sleep";
        args[1] = "1";
        args[2] = NULL;

        proc->spawn(args[0], args);
    }
    ~Object()
    {
        std::cout << "~Object()" << std::endl;
        if (proc->referenced())
        {
            proc->kill(SIGTERM);
            proc->close();
            //Crash without this:
            // proc->once<uvw::CloseEvent>([h = proc](const uvw::CloseEvent &, auto &) { });
        }
    }

private:
    std::shared_ptr<uvw::ProcessHandle> proc;
};

int main(int argc, char **argv)
{
    auto loop = uvw::Loop::getDefault();

    Object *o = new Object();

    auto timer = loop->resource<uvw::TimerHandle>();
    timer->once<uvw::TimerEvent>([o](const auto &, auto &h)
    {
        delete o;
        h.close();
    });

    int time = atoi(argv[1]);
    timer->start(uvw::TimerHandle::Time{time},
                 uvw::TimerHandle::Time{time});

    loop->run();

    return 0;
}

This simple example crashes when the Object is deleted and the process is still running. For example if you start it with:

➜  src git:(upstream_master) ./test 200
Object()
~Object()
*** Error in `./test': double free or corruption (fasttop): 0x00000000014562e0 ***
======= Backtrace: =========
/usr/lib/libc.so.6(+0x722ab)[0x7f082ddd62ab]
/usr/lib/libc.so.6(+0x7890e)[0x7f082dddc90e]
/usr/lib/libc.so.6(+0x7911e)[0x7f082dddd11e]
./test[0x40f5b0]
./test[0x40d72a]
./test[0x40aa3c]
./test[0x40a19a]
./test[0x40708d]
./test[0x40c53b]
./test[0x408e82]
./test[0x40601d]
/usr/lib/libuv.so.1(uv_run+0x1d8)[0x7f082f2093a8]
./test[0x404b0d]
./test[0x401ca1]
/usr/lib/libc.so.6(__libc_start_main+0xf1)[0x7f082dd84511]
./test[0x40194a]

Deleting the object after it has finished works:

➜  src git:(upstream_master) ./test 2000
Object()
process exited
~Object()

It appears to crash in uvw::Handle::closeCallback when trying to get the uvw::Handle but it was already deleted when freeing Object. A workaround is to keep a reference of the uvw::Handle in a CloseEvent lambda like:

proc->once<uvw::CloseEvent>([h = proc](const uvw::CloseEvent &, auto &) { });

It works but it's not nice. Also this problem only occurs when using uvw::ProcessHandle.

Release loop when close success

Currently the uvw::Loop will call Loop::close() in destructor function if loop is not null which calls uv_loop_close(). However uv_loop_close() is not idempotent (it will return UV_EBUSY if the loop has already been closed in DEBUG build, or crash straight away in Release build) which means if I manually called Loop::close() and it success, then the process will crash when it try to destruct the object.

A workaround I could come up with is in Loop::close if the return error is 0 then reset the loop ptr. Then move the nullptr check from destroctor to Loop::close instead.

The following code could easily reproduce this:

#include <uvw.hpp>

int main()
{
	auto loop = uvw::Loop::getDefault();

	loop->on<uvw::ErrorEvent>([](const uvw::ErrorEvent& ev, uvw::Loop& l)
	{
		printf("Error!");
		if (ev.code() == UV_EBUSY)
		{
			l.walk([](uvw::BaseHandle& h)
			{
				h.close();
			});
		}
	});

	loop->close();
}

Build with VS2017 on windows.

In debug mode it will crash at:
image

While in release mode it will crash at:
image

Conan Package Support

Hello,

Do you know about Conan?

Conan is modern dependency and package manager for C/C++. And would be great if your library would be available via package manager for other developers.

All Conan packages are available on Conan Center, where is possible search, install and upload any official Conan package.

As your project uses libuv, we already have such dependency solved by Conan. So you are able to run uvw with libuv pre-built.

We could support you writing a recipe and publishing your packages on Bintray.

If you have any questions, just ask :-)

Regards!

uvw::ProcessHandle blocks user-supplied stream as stdin

Thank you for the excellent library!

We encountered an interesting issue with uvw::ProcessHandle's constructor, which always adds stdin as a fd.

poFdStdio[0].flags = static_cast<uv_stdio_flags>(StdIO::IGNORE_STREAM);

It prevents using uvw::StreamHandle for stdin since entries in poFdStdio are placed before those in poStreamStdio.

Was there some reason to always initialize stdin as a fd? Without this special treatment of stdin, logic in

ProcessHandle & stdio(FileHandle fd, Flags<StdIO> flags)

can also be simplified.

Thanks

Conan builds failing due to libuv/1.25.0@bincrafters/stable missing requirement

Hi!

I was trying the recipe for this library and seems the requirement for libuv 1.25.0 is not in Conan Center yet. Also found the CI with latest changes is failing: https://travis-ci.org/skypjack/uvw/jobs/483890012

Probably we would need to package the new version of libuv (cc/ @uilianries) and meanwhile revert this?

Another suggestion would be to fix the VCS field in https://bintray.com/skypjack/conan/uvw:skypjack and write the github URL there.

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.