mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-28 02:11:43 +00:00
wpiutil: Add C++ libuv wrappers (#1166)
- Provide an EventLoopRunner to run uv::Loop on a separate thread. - Add raw_ostream wrapper for uv::Buffer.
This commit is contained in:
50
wpiutil/src/main/native/include/wpi/EventLoopRunner.h
Normal file
50
wpiutil/src/main/native/include/wpi/EventLoopRunner.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_WPI_EVENTLOOPRUNNER_H_
|
||||
#define WPIUTIL_WPI_EVENTLOOPRUNNER_H_
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "wpi/SafeThread.h"
|
||||
#include "wpi/uv/Loop.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/**
|
||||
* Executes an event loop on a separate thread.
|
||||
*/
|
||||
class EventLoopRunner {
|
||||
public:
|
||||
EventLoopRunner();
|
||||
virtual ~EventLoopRunner();
|
||||
|
||||
/**
|
||||
* Run a function asynchronously (once) on the loop.
|
||||
* This is safe to call from any thread, but is NOT safe to call from the
|
||||
* provided function (it will deadlock).
|
||||
* @param func function to execute on the loop
|
||||
*/
|
||||
void ExecAsync(std::function<void(wpi::uv::Loop&)> func);
|
||||
|
||||
/**
|
||||
* Run a function synchronously (once) on the loop.
|
||||
* This is safe to call from any thread, but is NOT safe to call from the
|
||||
* provided function (it will deadlock).
|
||||
* This does not return until the function finishes executing.
|
||||
* @param func function to execute on the loop
|
||||
*/
|
||||
void ExecSync(std::function<void(wpi::uv::Loop&)> func);
|
||||
|
||||
private:
|
||||
class Thread;
|
||||
wpi::SafeThreadOwner<Thread> m_owner;
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_EVENTLOOPRUNNER_H_
|
||||
70
wpiutil/src/main/native/include/wpi/raw_uv_ostream.h
Normal file
70
wpiutil/src/main/native/include/wpi/raw_uv_ostream.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_WPI_RAW_UV_OSTREAM_H_
|
||||
#define WPIUTIL_WPI_RAW_UV_OSTREAM_H_
|
||||
|
||||
#include "wpi/ArrayRef.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/raw_ostream.h"
|
||||
#include "wpi/uv/Buffer.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/**
|
||||
* raw_ostream style output to a SmallVector of uv::Buffer buffers. Fixed-size
|
||||
* buffers are allocated and appended as necessary to fit the data being output.
|
||||
* The SmallVector need not be empty at start.
|
||||
*/
|
||||
class raw_uv_ostream : public raw_ostream {
|
||||
public:
|
||||
/**
|
||||
* Construct a new raw_uv_ostream.
|
||||
* @param bufs Buffers vector. NOT cleared on construction.
|
||||
* @param allocSize Size to allocate for each buffer; allocation will be
|
||||
* performed using Buffer::Allocate().
|
||||
*/
|
||||
raw_uv_ostream(SmallVectorImpl<uv::Buffer>& bufs, size_t allocSize)
|
||||
: m_bufs(bufs),
|
||||
m_alloc([=]() { return uv::Buffer::Allocate(allocSize); }) {
|
||||
SetUnbuffered();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new raw_uv_ostream.
|
||||
* @param bufs Buffers vector. NOT cleared on construction.
|
||||
* @param alloc Allocator.
|
||||
*/
|
||||
raw_uv_ostream(SmallVectorImpl<uv::Buffer>& bufs,
|
||||
std::function<uv::Buffer()> alloc)
|
||||
: m_bufs(bufs), m_alloc(alloc) {
|
||||
SetUnbuffered();
|
||||
}
|
||||
|
||||
~raw_uv_ostream() override = default;
|
||||
|
||||
/**
|
||||
* Returns an ArrayRef to the buffers.
|
||||
*/
|
||||
ArrayRef<uv::Buffer> bufs() { return m_bufs; }
|
||||
|
||||
void flush() = delete;
|
||||
|
||||
private:
|
||||
void write_impl(const char* data, size_t len) override;
|
||||
uint64_t current_pos() const override;
|
||||
|
||||
SmallVectorImpl<uv::Buffer>& m_bufs;
|
||||
std::function<uv::Buffer()> m_alloc;
|
||||
|
||||
// How much allocated space is left in the current buffer.
|
||||
size_t m_left = 0;
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_RAW_UV_OSTREAM_H_
|
||||
68
wpiutil/src/main/native/include/wpi/uv/Async.h
Normal file
68
wpiutil/src/main/native/include/wpi/uv/Async.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_WPI_UV_ASYNC_H_
|
||||
#define WPIUTIL_WPI_UV_ASYNC_H_
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "wpi/Signal.h"
|
||||
#include "wpi/uv/Handle.h"
|
||||
|
||||
namespace wpi {
|
||||
namespace uv {
|
||||
|
||||
class Loop;
|
||||
|
||||
/**
|
||||
* Async handle.
|
||||
* Async handles allow the user to "wakeup" the event loop and have a signal
|
||||
* generated from another thread.
|
||||
*/
|
||||
class Async final : public HandleImpl<Async, uv_async_t> {
|
||||
struct private_init {};
|
||||
|
||||
public:
|
||||
explicit Async(const private_init&) {}
|
||||
~Async() noexcept override = default;
|
||||
|
||||
/**
|
||||
* Create an async handle.
|
||||
*
|
||||
* @param loop Loop object where this handle runs.
|
||||
*/
|
||||
static std::shared_ptr<Async> Create(Loop& loop);
|
||||
|
||||
/**
|
||||
* Create an async handle.
|
||||
*
|
||||
* @param loop Loop object where this handle runs.
|
||||
*/
|
||||
static std::shared_ptr<Async> Create(const std::shared_ptr<Loop>& loop) {
|
||||
return Create(*loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wakeup the event loop and emit the event.
|
||||
*
|
||||
* It’s safe to call this function from any thread.
|
||||
* An async event will be emitted on the loop thread.
|
||||
*/
|
||||
void Send() { Invoke(&uv_async_send, GetRaw()); }
|
||||
|
||||
/**
|
||||
* Signal generated (on event loop thread) when the async event occurs.
|
||||
*/
|
||||
sig::Signal<> wakeup;
|
||||
};
|
||||
|
||||
} // namespace uv
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_UV_ASYNC_H_
|
||||
92
wpiutil/src/main/native/include/wpi/uv/Buffer.h
Normal file
92
wpiutil/src/main/native/include/wpi/uv/Buffer.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_WPI_UV_BUFFER_H_
|
||||
#define WPIUTIL_WPI_UV_BUFFER_H_
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <initializer_list>
|
||||
#include <utility>
|
||||
|
||||
#include "wpi/ArrayRef.h"
|
||||
#include "wpi/StringRef.h"
|
||||
|
||||
namespace wpi {
|
||||
namespace uv {
|
||||
|
||||
/**
|
||||
* Data buffer. Convenience wrapper around uv_buf_t.
|
||||
*/
|
||||
class Buffer : public uv_buf_t {
|
||||
public:
|
||||
Buffer() {
|
||||
base = nullptr;
|
||||
len = 0;
|
||||
}
|
||||
/*implicit*/ Buffer(const uv_buf_t& oth) { // NOLINT(runtime/explicit)
|
||||
base = oth.base;
|
||||
len = oth.len;
|
||||
}
|
||||
/*implicit*/ Buffer(StringRef str) // NOLINT(runtime/explicit)
|
||||
: Buffer{str.data(), str.size()} {}
|
||||
/*implicit*/ Buffer(ArrayRef<uint8_t> arr) // NOLINT(runtime/explicit)
|
||||
: Buffer{reinterpret_cast<const char*>(arr.data()), arr.size()} {}
|
||||
Buffer(char* base_, size_t len_) {
|
||||
base = base_;
|
||||
len = len_;
|
||||
}
|
||||
Buffer(const char* base_, size_t len_) {
|
||||
base = const_cast<char*>(base_);
|
||||
len = len_;
|
||||
}
|
||||
|
||||
ArrayRef<char> data() const { return ArrayRef<char>{base, len}; }
|
||||
MutableArrayRef<char> data() { return MutableArrayRef<char>{base, len}; }
|
||||
|
||||
operator ArrayRef<char>() const { return data(); }
|
||||
operator MutableArrayRef<char>() { return data(); }
|
||||
|
||||
static Buffer Allocate(size_t size) { return Buffer{new char[size], size}; }
|
||||
|
||||
static Buffer Dup(StringRef in) {
|
||||
Buffer buf = Allocate(in.size());
|
||||
std::memcpy(buf.base, in.data(), in.size());
|
||||
return buf;
|
||||
}
|
||||
|
||||
static Buffer Dup(ArrayRef<uint8_t> in) {
|
||||
Buffer buf = Allocate(in.size());
|
||||
std::memcpy(buf.base, in.begin(), in.size());
|
||||
return buf;
|
||||
}
|
||||
|
||||
void Deallocate() {
|
||||
delete[] base;
|
||||
base = nullptr;
|
||||
len = 0;
|
||||
}
|
||||
|
||||
Buffer Move() {
|
||||
Buffer buf = *this;
|
||||
base = nullptr;
|
||||
len = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
friend void swap(Buffer& a, Buffer& b) {
|
||||
using std::swap;
|
||||
swap(a.base, b.base);
|
||||
swap(a.len, b.len);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace uv
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_UV_BUFFER_H_
|
||||
70
wpiutil/src/main/native/include/wpi/uv/Check.h
Normal file
70
wpiutil/src/main/native/include/wpi/uv/Check.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_WPI_UV_CHECK_H_
|
||||
#define WPIUTIL_WPI_UV_CHECK_H_
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "wpi/Signal.h"
|
||||
#include "wpi/uv/Handle.h"
|
||||
|
||||
namespace wpi {
|
||||
namespace uv {
|
||||
|
||||
class Loop;
|
||||
|
||||
/**
|
||||
* Check handle.
|
||||
* Check handles will generate a signal once per loop iteration, right
|
||||
* after polling for I/O.
|
||||
*/
|
||||
class Check final : public HandleImpl<Check, uv_check_t> {
|
||||
struct private_init {};
|
||||
|
||||
public:
|
||||
explicit Check(const private_init&) {}
|
||||
~Check() noexcept override = default;
|
||||
|
||||
/**
|
||||
* Create a check handle.
|
||||
*
|
||||
* @param loop Loop object where this handle runs.
|
||||
*/
|
||||
static std::shared_ptr<Check> Create(Loop& loop);
|
||||
|
||||
/**
|
||||
* Create a check handle.
|
||||
*
|
||||
* @param loop Loop object where this handle runs.
|
||||
*/
|
||||
static std::shared_ptr<Check> Create(const std::shared_ptr<Loop>& loop) {
|
||||
return Create(*loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the handle.
|
||||
*/
|
||||
void Start();
|
||||
|
||||
/**
|
||||
* Stop the handle. The signal will no longer be generated.
|
||||
*/
|
||||
void Stop() { Invoke(&uv_check_stop, GetRaw()); }
|
||||
|
||||
/**
|
||||
* Signal generated once per loop iteration after polling for I/O.
|
||||
*/
|
||||
sig::Signal<> check;
|
||||
};
|
||||
|
||||
} // namespace uv
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_UV_CHECK_H_
|
||||
51
wpiutil/src/main/native/include/wpi/uv/Error.h
Normal file
51
wpiutil/src/main/native/include/wpi/uv/Error.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_WPI_UV_ERROR_H_
|
||||
#define WPIUTIL_WPI_UV_ERROR_H_
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
namespace wpi {
|
||||
namespace uv {
|
||||
|
||||
/**
|
||||
* Error code.
|
||||
*/
|
||||
class Error {
|
||||
public:
|
||||
Error() : m_err(UV_UNKNOWN) {}
|
||||
explicit Error(int err) : m_err(err) {}
|
||||
|
||||
/**
|
||||
* Boolean conversion. Returns true if error, false if ok.
|
||||
*/
|
||||
explicit operator bool() const { return m_err < 0; }
|
||||
|
||||
/**
|
||||
* Returns the error code.
|
||||
*/
|
||||
int code() const { return m_err; }
|
||||
|
||||
/**
|
||||
* Returns the error message.
|
||||
*/
|
||||
const char* str() const { return uv_strerror(m_err); }
|
||||
|
||||
/**
|
||||
* Returns the error name.
|
||||
*/
|
||||
const char* name() const { return uv_err_name(m_err); }
|
||||
|
||||
private:
|
||||
int m_err;
|
||||
};
|
||||
|
||||
} // namespace uv
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_UV_ERROR_H_
|
||||
84
wpiutil/src/main/native/include/wpi/uv/FsEvent.h
Normal file
84
wpiutil/src/main/native/include/wpi/uv/FsEvent.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_WPI_UV_FSEVENT_H_
|
||||
#define WPIUTIL_WPI_UV_FSEVENT_H_
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "wpi/Signal.h"
|
||||
#include "wpi/Twine.h"
|
||||
#include "wpi/uv/Handle.h"
|
||||
|
||||
namespace wpi {
|
||||
namespace uv {
|
||||
|
||||
class Loop;
|
||||
|
||||
/**
|
||||
* Filesystem Event handle.
|
||||
*/
|
||||
class FsEvent final : public HandleImpl<FsEvent, uv_fs_event_t> {
|
||||
struct private_init {};
|
||||
|
||||
public:
|
||||
explicit FsEvent(const private_init&) {}
|
||||
~FsEvent() noexcept override = default;
|
||||
|
||||
/**
|
||||
* Create a filesystem event handle.
|
||||
*
|
||||
* @param loop Loop object where this handle runs.
|
||||
*/
|
||||
static std::shared_ptr<FsEvent> Create(Loop& loop);
|
||||
|
||||
/**
|
||||
* Create a filesystem event handle.
|
||||
*
|
||||
* @param loop Loop object where this handle runs.
|
||||
*/
|
||||
static std::shared_ptr<FsEvent> Create(const std::shared_ptr<Loop>& loop) {
|
||||
return Create(*loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start watching the specified path for changes.
|
||||
*
|
||||
* @param path Path to watch for changes
|
||||
* @param events Bitmask of event flags. Only UV_FS_EVENT_RECURSIVE is
|
||||
* supported (and only on OSX and Windows).
|
||||
*/
|
||||
void Start(const Twine& path, unsigned int flags = 0);
|
||||
|
||||
/**
|
||||
* Stop watching for changes.
|
||||
*/
|
||||
void Stop() { Invoke(&uv_fs_event_stop, GetRaw()); }
|
||||
|
||||
/**
|
||||
* Get the path being monitored. Signals error and returns empty string if
|
||||
* an error occurs.
|
||||
* @return Monitored path.
|
||||
*/
|
||||
std::string GetPath();
|
||||
|
||||
/**
|
||||
* Signal generated when a filesystem change occurs. The first parameter
|
||||
* is the filename (if a directory was passed to Start(), the filename is
|
||||
* relative to that directory). The second parameter is an ORed mask of
|
||||
* UV_RENAME and UV_CHANGE.
|
||||
*/
|
||||
sig::Signal<const char*, int> fsEvent;
|
||||
};
|
||||
|
||||
} // namespace uv
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_UV_FSEVENT_H_
|
||||
125
wpiutil/src/main/native/include/wpi/uv/GetAddrInfo.h
Normal file
125
wpiutil/src/main/native/include/wpi/uv/GetAddrInfo.h
Normal file
@@ -0,0 +1,125 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_WPI_UV_GETADDRINFO_H_
|
||||
#define WPIUTIL_WPI_UV_GETADDRINFO_H_
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include "wpi/Signal.h"
|
||||
#include "wpi/Twine.h"
|
||||
#include "wpi/uv/Request.h"
|
||||
|
||||
namespace wpi {
|
||||
namespace uv {
|
||||
|
||||
class Loop;
|
||||
|
||||
/**
|
||||
* GetAddrInfo request.
|
||||
* For use with `GetAddrInfo()` function family.
|
||||
*/
|
||||
class GetAddrInfoReq : public RequestImpl<GetAddrInfoReq, uv_getaddrinfo_t> {
|
||||
public:
|
||||
GetAddrInfoReq();
|
||||
|
||||
Loop& GetLoop() const { return *static_cast<Loop*>(GetRaw()->loop->data); }
|
||||
|
||||
/**
|
||||
* Resolved lookup signal.
|
||||
* Parameter is resolved address info.
|
||||
*/
|
||||
sig::Signal<const addrinfo&> resolved;
|
||||
};
|
||||
|
||||
/**
|
||||
* Asynchronous getaddrinfo(3). HandleResolvedAddress() is called on the
|
||||
* request when the resolution completes. HandleError() is called on the
|
||||
* request if any errors occur.
|
||||
*
|
||||
* Either node or service may be null (`Twine::createNull()`) but not both.
|
||||
*
|
||||
* @param loop Event loop
|
||||
* @param req request
|
||||
* @param node Either a numerical network address or a network hostname.
|
||||
* @param service Either a service name or a port number as a string.
|
||||
* @param hints Optional `addrinfo` data structure with additional address
|
||||
* type constraints.
|
||||
*/
|
||||
void GetAddrInfo(Loop& loop, const std::shared_ptr<GetAddrInfoReq>& req,
|
||||
const Twine& node, const Twine& service = Twine::createNull(),
|
||||
const addrinfo* hints = nullptr);
|
||||
|
||||
/**
|
||||
* Asynchronous getaddrinfo(3). HandleResolvedAddress() is called on the
|
||||
* request when the resolution completes. HandleError() is called on the
|
||||
* request if any errors occur.
|
||||
*
|
||||
* Either node or service may be null (`Twine::createNull()`) but not both.
|
||||
*
|
||||
* @param loop Event loop
|
||||
* @param req request
|
||||
* @param node Either a numerical network address or a network hostname.
|
||||
* @param service Either a service name or a port number as a string.
|
||||
* @param hints Optional `addrinfo` data structure with additional address
|
||||
* type constraints.
|
||||
*/
|
||||
inline void GetAddrInfo(const std::shared_ptr<Loop>& loop,
|
||||
const std::shared_ptr<GetAddrInfoReq>& req,
|
||||
const Twine& node,
|
||||
const Twine& service = Twine::createNull(),
|
||||
const addrinfo* hints = nullptr) {
|
||||
GetAddrInfo(*loop, req, node, service, hints);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronous getaddrinfo(3). The callback is called when the resolution
|
||||
* completes, and errors are forwarded to the loop. This is a convenience
|
||||
* wrapper.
|
||||
*
|
||||
* Either node or service may be null (`Twine::createNull()`) but not both.
|
||||
*
|
||||
* @param loop Event loop
|
||||
* @param callback Callback function to call when resolution completes
|
||||
* @param node Either a numerical network address or a network hostname.
|
||||
* @param service Either a service name or a port number as a string.
|
||||
* @param hints Optional `addrinfo` data structure with additional address
|
||||
* type constraints.
|
||||
*/
|
||||
void GetAddrInfo(Loop& loop, std::function<void(const addrinfo&)> callback,
|
||||
const Twine& node, const Twine& service = Twine::createNull(),
|
||||
const addrinfo* hints = nullptr);
|
||||
|
||||
/**
|
||||
* Asynchronous getaddrinfo(3). The callback is called when the resolution
|
||||
* completes, and errors are forwarded to the loop. This is a convenience
|
||||
* wrapper.
|
||||
*
|
||||
* Either node or service may be null (`Twine::createNull()`) but not both.
|
||||
*
|
||||
* @param loop Event loop
|
||||
* @param callback Callback function to call when resolution completes
|
||||
* @param node Either a numerical network address or a network hostname.
|
||||
* @param service Either a service name or a port number as a string.
|
||||
* @param hints Optional `addrinfo` data structure with additional address
|
||||
* type constraints.
|
||||
*/
|
||||
inline void GetAddrInfo(const std::shared_ptr<Loop>& loop,
|
||||
std::function<void(const addrinfo&)> callback,
|
||||
const Twine& node,
|
||||
const Twine& service = Twine::createNull(),
|
||||
const addrinfo* hints = nullptr) {
|
||||
GetAddrInfo(*loop, callback, node, service, hints);
|
||||
}
|
||||
|
||||
} // namespace uv
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_UV_GETADDRINFO_H_
|
||||
228
wpiutil/src/main/native/include/wpi/uv/GetNameInfo.h
Normal file
228
wpiutil/src/main/native/include/wpi/uv/GetNameInfo.h
Normal file
@@ -0,0 +1,228 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_WPI_UV_GETNAMEINFO_H_
|
||||
#define WPIUTIL_WPI_UV_GETNAMEINFO_H_
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include "wpi/Signal.h"
|
||||
#include "wpi/Twine.h"
|
||||
#include "wpi/uv/Request.h"
|
||||
|
||||
namespace wpi {
|
||||
namespace uv {
|
||||
|
||||
class Loop;
|
||||
|
||||
/**
|
||||
* GetNameInfo request.
|
||||
* For use with `GetNameInfo()` function family.
|
||||
*/
|
||||
class GetNameInfoReq : public RequestImpl<GetNameInfoReq, uv_getnameinfo_t> {
|
||||
public:
|
||||
GetNameInfoReq();
|
||||
|
||||
Loop& GetLoop() const { return *static_cast<Loop*>(GetRaw()->loop->data); }
|
||||
|
||||
/**
|
||||
* Resolved lookup signal.
|
||||
* Parameters are hostname and service.
|
||||
*/
|
||||
sig::Signal<const char*, const char*> resolved;
|
||||
};
|
||||
|
||||
/**
|
||||
* Asynchronous getnameinfo(3). HandleResolvedName() is called on the
|
||||
* request when the resolution completes. HandleError() is called on the
|
||||
* request if any errors occur.
|
||||
*
|
||||
* @param loop Event loop
|
||||
* @param req request
|
||||
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
|
||||
* @param flags Optional flags to modify the behavior of `getnameinfo`.
|
||||
*/
|
||||
void GetNameInfo(Loop& loop, const std::shared_ptr<GetNameInfoReq>& req,
|
||||
const sockaddr& addr, int flags = 0);
|
||||
|
||||
/**
|
||||
* Asynchronous getnameinfo(3). HandleResolvedName() is called on the
|
||||
* request when the resolution completes. HandleError() is called on the
|
||||
* request if any errors occur.
|
||||
*
|
||||
* @param loop Event loop
|
||||
* @param req request
|
||||
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
|
||||
* @param flags Optional flags to modify the behavior of `getnameinfo`.
|
||||
*/
|
||||
inline void GetNameInfo(const std::shared_ptr<Loop>& loop,
|
||||
const std::shared_ptr<GetNameInfoReq>& req,
|
||||
const sockaddr& addr, int flags = 0) {
|
||||
GetNameInfo(*loop, req, addr, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronous getnameinfo(3). The callback is called when the resolution
|
||||
* completes, and errors are forwarded to the loop.
|
||||
*
|
||||
* @param loop Event loop
|
||||
* @param callback Callback function to call when resolution completes
|
||||
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
|
||||
* @param flags Optional flags to modify the behavior of `getnameinfo`.
|
||||
*/
|
||||
void GetNameInfo(Loop& loop,
|
||||
std::function<void(const char*, const char*)> callback,
|
||||
const sockaddr& addr, int flags = 0);
|
||||
|
||||
/**
|
||||
* Asynchronous getnameinfo(3). The callback is called when the resolution
|
||||
* completes, and errors are forwarded to the loop.
|
||||
*
|
||||
* @param loop Event loop
|
||||
* @param callback Callback function to call when resolution completes
|
||||
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
|
||||
* @param flags Optional flags to modify the behavior of `getnameinfo`.
|
||||
* @return Connection object for the callback
|
||||
*/
|
||||
inline void GetNameInfo(const std::shared_ptr<Loop>& loop,
|
||||
std::function<void(const char*, const char*)> callback,
|
||||
const sockaddr& addr, int flags = 0) {
|
||||
GetNameInfo(*loop, callback, addr, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronous IPv4 getnameinfo(3). HandleResolvedName() is called on the
|
||||
* request when the resolution completes. HandleError() is called on the
|
||||
* request if any errors occur.
|
||||
*
|
||||
* @param loop Event loop
|
||||
* @param req request
|
||||
* @param ip A valid IPv4 address
|
||||
* @param port A valid port number
|
||||
* @param flags Optional flags to modify the behavior of `getnameinfo`.
|
||||
*/
|
||||
void GetNameInfo4(Loop& loop, const std::shared_ptr<GetNameInfoReq>& req,
|
||||
const Twine& ip, unsigned int port, int flags = 0);
|
||||
|
||||
/**
|
||||
* Asynchronous IPv4 getnameinfo(3). HandleResolvedName() is called on the
|
||||
* request when the resolution completes. HandleError() is called on the
|
||||
* request if any errors occur.
|
||||
*
|
||||
* @param loop Event loop
|
||||
* @param req request
|
||||
* @param ip A valid IPv4 address
|
||||
* @param port A valid port number
|
||||
* @param flags Optional flags to modify the behavior of `getnameinfo`.
|
||||
*/
|
||||
inline void GetNameInfo4(const std::shared_ptr<Loop>& loop,
|
||||
const std::shared_ptr<GetNameInfoReq>& req,
|
||||
const Twine& ip, unsigned int port, int flags = 0) {
|
||||
return GetNameInfo4(*loop, req, ip, port, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronous IPv4 getnameinfo(3). The callback is called when the resolution
|
||||
* completes, and errors are forwarded to the loop.
|
||||
*
|
||||
* @param loop Event loop
|
||||
* @param callback Callback function to call when resolution completes
|
||||
* @param ip A valid IPv4 address
|
||||
* @param port A valid port number
|
||||
* @param flags Optional flags to modify the behavior of `getnameinfo`.
|
||||
*/
|
||||
void GetNameInfo4(Loop& loop,
|
||||
std::function<void(const char*, const char*)> callback,
|
||||
const Twine& ip, unsigned int port, int flags = 0);
|
||||
|
||||
/**
|
||||
* Asynchronous IPv4 getnameinfo(3). The callback is called when the resolution
|
||||
* completes, and errors are forwarded to the loop. This is a convenience
|
||||
* wrapper.
|
||||
*
|
||||
* @param loop Event loop
|
||||
* @param ip A valid IPv4 address
|
||||
* @param port A valid port number
|
||||
* @param callback Callback function to call when resolution completes
|
||||
* @param flags Optional flags to modify the behavior of `getnameinfo`.
|
||||
*/
|
||||
inline void GetNameInfo4(const std::shared_ptr<Loop>& loop,
|
||||
std::function<void(const char*, const char*)> callback,
|
||||
const Twine& ip, unsigned int port, int flags = 0) {
|
||||
return GetNameInfo4(*loop, callback, ip, port, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronous IPv6 getnameinfo(3). HandleResolvedName() is called on the
|
||||
* request when the resolution completes. HandleError() is called on the
|
||||
* request if any errors occur.
|
||||
*
|
||||
* @param loop Event loop
|
||||
* @param req request
|
||||
* @param ip A valid IPv6 address
|
||||
* @param port A valid port number
|
||||
* @param flags Optional flags to modify the behavior of `getnameinfo`.
|
||||
*/
|
||||
void GetNameInfo6(Loop& loop, const std::shared_ptr<GetNameInfoReq>& req,
|
||||
const Twine& ip, unsigned int port, int flags = 0);
|
||||
|
||||
/**
|
||||
* Asynchronous IPv6 getnameinfo(3). HandleResolvedName() is called on the
|
||||
* request when the resolution completes. HandleError() is called on the
|
||||
* request if any errors occur.
|
||||
*
|
||||
* @param loop Event loop
|
||||
* @param req request
|
||||
* @param ip A valid IPv6 address
|
||||
* @param port A valid port number
|
||||
* @param flags Optional flags to modify the behavior of `getnameinfo`.
|
||||
*/
|
||||
inline void GetNameInfo6(const std::shared_ptr<Loop>& loop,
|
||||
const std::shared_ptr<GetNameInfoReq>& req,
|
||||
const Twine& ip, unsigned int port, int flags = 0) {
|
||||
GetNameInfo6(*loop, req, ip, port, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronous IPv6 getnameinfo(3). The callback is called when the resolution
|
||||
* completes, and errors are forwarded to the loop. This is a convenience
|
||||
* wrapper.
|
||||
*
|
||||
* @param loop Event loop
|
||||
* @param callback Callback function to call when resolution completes
|
||||
* @param ip A valid IPv6 address
|
||||
* @param port A valid port number
|
||||
* @param flags Optional flags to modify the behavior of `getnameinfo`.
|
||||
*/
|
||||
void GetNameInfo6(Loop& loop,
|
||||
std::function<void(const char*, const char*)> callback,
|
||||
const Twine& ip, unsigned int port, int flags = 0);
|
||||
|
||||
/**
|
||||
* Asynchronous IPv6 getnameinfo(3). The callback is called when the resolution
|
||||
* completes, and errors are forwarded to the loop. This is a convenience
|
||||
* wrapper.
|
||||
*
|
||||
* @param loop Event loop
|
||||
* @param callback Callback function to call when resolution completes
|
||||
* @param ip A valid IPv6 address
|
||||
* @param port A valid port number
|
||||
* @param flags Optional flags to modify the behavior of `getnameinfo`.
|
||||
*/
|
||||
inline void GetNameInfo6(const std::shared_ptr<Loop>& loop,
|
||||
std::function<void(const char*, const char*)> callback,
|
||||
const Twine& ip, unsigned int port, int flags = 0) {
|
||||
return GetNameInfo6(*loop, callback, ip, port, flags);
|
||||
}
|
||||
|
||||
} // namespace uv
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_UV_GETNAMEINFO_H_
|
||||
272
wpiutil/src/main/native/include/wpi/uv/Handle.h
Normal file
272
wpiutil/src/main/native/include/wpi/uv/Handle.h
Normal file
@@ -0,0 +1,272 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_WPI_UV_HANDLE_H_
|
||||
#define WPIUTIL_WPI_UV_HANDLE_H_
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "wpi/Signal.h"
|
||||
#include "wpi/StringRef.h"
|
||||
#include "wpi/uv/Buffer.h"
|
||||
#include "wpi/uv/Error.h"
|
||||
#include "wpi/uv/Loop.h"
|
||||
|
||||
namespace wpi {
|
||||
namespace uv {
|
||||
|
||||
/**
|
||||
* Handle.
|
||||
* Handles are not moveable or copyable and cannot be directly constructed.
|
||||
* This class provides shared_ptr ownership and shared_from_this.
|
||||
* Use the specific handle type Create() functions to create handles.
|
||||
*/
|
||||
class Handle : public std::enable_shared_from_this<Handle> {
|
||||
public:
|
||||
using Type = uv_handle_type;
|
||||
|
||||
Handle(const Handle&) = delete;
|
||||
Handle(Handle&&) = delete;
|
||||
Handle& operator=(const Handle&) = delete;
|
||||
Handle& operator=(Handle&&) = delete;
|
||||
virtual ~Handle() noexcept;
|
||||
|
||||
/**
|
||||
* Get the type of the handle.
|
||||
*
|
||||
* A base handle offers no functionality to promote it to the actual handle
|
||||
* type. By means of this function, the type of the underlying handle as
|
||||
* specified by Type is made available.
|
||||
*
|
||||
* @return The actual type of the handle.
|
||||
*/
|
||||
Type GetType() const noexcept { return m_uv_handle->type; }
|
||||
|
||||
/**
|
||||
* Get the name of the type of the handle. E.g. "pipe" for pipe handles.
|
||||
*/
|
||||
StringRef GetTypeName() const noexcept {
|
||||
return uv_handle_type_name(m_uv_handle->type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the loop where this handle runs.
|
||||
*
|
||||
* @return The loop.
|
||||
*/
|
||||
std::shared_ptr<Loop> GetLoop() const noexcept {
|
||||
return GetLoopRef().shared_from_this();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the loop where this handle runs.
|
||||
*
|
||||
* @return The loop.
|
||||
*/
|
||||
Loop& GetLoopRef() const noexcept {
|
||||
return *static_cast<Loop*>(m_uv_handle->loop->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the handle is active.
|
||||
*
|
||||
* What _active_ means depends on the type of handle:
|
||||
*
|
||||
* * An AsyncHandle handle is always active and cannot be deactivated,
|
||||
* except by closing it with uv_close().
|
||||
* * A PipeHandle, TcpHandle, UDPHandle, etc. handle - basically any handle
|
||||
* that deals with I/O - is active when it is doing something that involves
|
||||
* I/O, like reading, writing, connecting, accepting new connections, etc.
|
||||
* * A CheckHandle, IdleHandle, TimerHandle, etc. handle is active when it
|
||||
* has been started with a call to `Start()`.
|
||||
*
|
||||
* Rule of thumb: if a handle of type `FooHandle` has a `Start()` member
|
||||
* method, then it’s active from the moment that method is called. Likewise,
|
||||
* `Stop()` deactivates the handle again.
|
||||
*
|
||||
* @return True if the handle is active, false otherwise.
|
||||
*/
|
||||
bool IsActive() const noexcept { return uv_is_active(m_uv_handle) != 0; }
|
||||
|
||||
/**
|
||||
* Check if a handle is closing or closed.
|
||||
*
|
||||
* This function should only be used between the initialization of the
|
||||
* handle and the arrival of the close callback.
|
||||
*
|
||||
* @return True if the handle is closing or closed, false otherwise.
|
||||
*/
|
||||
bool IsClosing() const noexcept { return uv_is_closing(m_uv_handle) != 0; }
|
||||
|
||||
/**
|
||||
* Request handle to be closed.
|
||||
*
|
||||
* This **must** be called on each handle before memory is released.
|
||||
* In-progress requests are cancelled and this can result in error() being
|
||||
* emitted.
|
||||
*
|
||||
* The handle will emit closed() when finished.
|
||||
*/
|
||||
void Close() noexcept;
|
||||
|
||||
/**
|
||||
* Reference the given handle.
|
||||
*
|
||||
* References are idempotent, that is, if a handle is already referenced
|
||||
* calling this function again will have no effect.
|
||||
*/
|
||||
void Reference() noexcept { uv_ref(m_uv_handle); }
|
||||
|
||||
/**
|
||||
* Unreference the given handle.
|
||||
*
|
||||
* References are idempotent, that is, if a handle is not referenced calling
|
||||
* this function again will have no effect.
|
||||
*/
|
||||
void Unreference() noexcept { uv_unref(m_uv_handle); }
|
||||
|
||||
/**
|
||||
* Check if the given handle is referenced.
|
||||
* @return True if the handle is referenced, false otherwise.
|
||||
*/
|
||||
bool HasReference() const noexcept { return uv_has_ref(m_uv_handle) != 0; }
|
||||
|
||||
/**
|
||||
* Return the size of the underlying handle type.
|
||||
* @return The size of the underlying handle type.
|
||||
*/
|
||||
size_t RawSize() const noexcept { return uv_handle_size(m_uv_handle->type); }
|
||||
|
||||
/**
|
||||
* Get the underlying handle data structure.
|
||||
*
|
||||
* @return The underlying handle data structure.
|
||||
*/
|
||||
uv_handle_t* GetRawHandle() const noexcept { return m_uv_handle; }
|
||||
|
||||
/**
|
||||
* Set the functions used for allocating and releasing buffers. The size
|
||||
* passed to the allocator function is a "suggested" size--it's just an
|
||||
* indication, not related in any way to the pending data to be read. The
|
||||
* user is free to allocate the amount of memory they decide. For example,
|
||||
* applications with custom allocation schemes may decide to use a different
|
||||
* size which matches the memory chunks they already have for other purposes.
|
||||
*
|
||||
* @warning Be very careful changing the allocator after the loop has started
|
||||
* running; there are no interlocks between this and buffers currently in
|
||||
* flight.
|
||||
*
|
||||
* @param alloc Allocation function
|
||||
* @param dealloc Deallocation function
|
||||
*/
|
||||
void SetBufferAllocator(std::function<Buffer(size_t)> alloc,
|
||||
std::function<void(Buffer&)> dealloc) {
|
||||
m_allocBuf = alloc;
|
||||
m_freeBuf = dealloc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free a buffer. Uses the function provided to SetBufFree() or
|
||||
* Buffer::Deallocate by default.
|
||||
*
|
||||
* @param buf The buffer
|
||||
*/
|
||||
void FreeBuf(Buffer& buf) const noexcept { m_freeBuf(buf); }
|
||||
|
||||
/**
|
||||
* Gets user-defined data.
|
||||
* @return User-defined data if any, nullptr otherwise.
|
||||
*/
|
||||
template <typename T = void>
|
||||
std::shared_ptr<T> GetData() const {
|
||||
return std::static_pointer_cast<T>(m_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets user-defined data.
|
||||
* @param data User-defined arbitrary data.
|
||||
*/
|
||||
void SetData(std::shared_ptr<void> data) { m_data = std::move(data); }
|
||||
|
||||
/**
|
||||
* Error signal
|
||||
*/
|
||||
sig::Signal<Error> error;
|
||||
|
||||
/**
|
||||
* Closed signal
|
||||
*/
|
||||
sig::Signal<> closed;
|
||||
|
||||
/**
|
||||
* Report an error.
|
||||
* @param err Error code
|
||||
*/
|
||||
void ReportError(int err) { error(Error(err)); }
|
||||
|
||||
protected:
|
||||
explicit Handle(uv_handle_t* uv_handle) : m_uv_handle{uv_handle} {
|
||||
m_uv_handle->data = this;
|
||||
}
|
||||
|
||||
void Keep() noexcept { m_self = shared_from_this(); }
|
||||
void Release() noexcept { m_self.reset(); }
|
||||
|
||||
static void AllocBuf(uv_handle_t* handle, size_t size, uv_buf_t* buf);
|
||||
static void DefaultFreeBuf(Buffer& buf);
|
||||
|
||||
template <typename F, typename... Args>
|
||||
bool Invoke(F&& f, Args&&... args) {
|
||||
auto err = std::forward<F>(f)(std::forward<Args>(args)...);
|
||||
if (err < 0) ReportError(err);
|
||||
return err == 0;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<Handle> m_self;
|
||||
uv_handle_t* m_uv_handle;
|
||||
bool m_closed = false;
|
||||
std::function<Buffer(size_t)> m_allocBuf{&Buffer::Allocate};
|
||||
std::function<void(Buffer&)> m_freeBuf{&DefaultFreeBuf};
|
||||
std::shared_ptr<void> m_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle.
|
||||
*/
|
||||
template <typename T, typename U>
|
||||
class HandleImpl : public Handle {
|
||||
public:
|
||||
std::shared_ptr<T> shared_from_this() {
|
||||
return std::static_pointer_cast<T>(Handle::shared_from_this());
|
||||
}
|
||||
|
||||
std::shared_ptr<const T> shared_from_this() const {
|
||||
return std::static_pointer_cast<const T>(Handle::shared_from_this());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underlying handle data structure.
|
||||
*
|
||||
* @return The underlying handle data structure.
|
||||
*/
|
||||
U* GetRaw() const noexcept {
|
||||
return reinterpret_cast<U*>(this->GetRawHandle());
|
||||
}
|
||||
|
||||
protected:
|
||||
HandleImpl() : Handle{reinterpret_cast<uv_handle_t*>(new U)} {}
|
||||
};
|
||||
|
||||
} // namespace uv
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_UV_HANDLE_H_
|
||||
79
wpiutil/src/main/native/include/wpi/uv/Idle.h
Normal file
79
wpiutil/src/main/native/include/wpi/uv/Idle.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_WPI_UV_IDLE_H_
|
||||
#define WPIUTIL_WPI_UV_IDLE_H_
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "wpi/Signal.h"
|
||||
#include "wpi/uv/Handle.h"
|
||||
|
||||
namespace wpi {
|
||||
namespace uv {
|
||||
|
||||
class Loop;
|
||||
|
||||
/**
|
||||
* Idle handle.
|
||||
*
|
||||
* Idle handles will generate a signal once per loop iteration, right
|
||||
* before the Prepare handles.
|
||||
*
|
||||
* The notable difference with Prepare handles is that when there are active
|
||||
* idle handles, the loop will perform a zero timeout poll instead of blocking
|
||||
* for I/O.
|
||||
*
|
||||
* @warning Despite the name, idle handles will signal every loop iteration,
|
||||
* not when the loop is actually "idle". This also means they can easly become
|
||||
* CPU hogs.
|
||||
*/
|
||||
class Idle final : public HandleImpl<Idle, uv_idle_t> {
|
||||
struct private_init {};
|
||||
|
||||
public:
|
||||
explicit Idle(const private_init&) {}
|
||||
~Idle() noexcept override = default;
|
||||
|
||||
/**
|
||||
* Create an idle handle.
|
||||
*
|
||||
* @param loop Loop object where this handle runs.
|
||||
*/
|
||||
static std::shared_ptr<Idle> Create(Loop& loop);
|
||||
|
||||
/**
|
||||
* Create an idle handle.
|
||||
*
|
||||
* @param loop Loop object where this handle runs.
|
||||
*/
|
||||
static std::shared_ptr<Idle> Create(const std::shared_ptr<Loop>& loop) {
|
||||
return Create(*loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the handle.
|
||||
*/
|
||||
void Start();
|
||||
|
||||
/**
|
||||
* Stop the handle. The signal will no longer be generated.
|
||||
*/
|
||||
void Stop() { Invoke(&uv_idle_stop, GetRaw()); }
|
||||
|
||||
/**
|
||||
* Signal generated once per loop iteration prior to Prepare signals.
|
||||
*/
|
||||
sig::Signal<> idle;
|
||||
};
|
||||
|
||||
} // namespace uv
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_UV_IDLE_H_
|
||||
230
wpiutil/src/main/native/include/wpi/uv/Loop.h
Normal file
230
wpiutil/src/main/native/include/wpi/uv/Loop.h
Normal file
@@ -0,0 +1,230 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_WPI_UV_LOOP_H_
|
||||
#define WPIUTIL_WPI_UV_LOOP_H_
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "wpi/Signal.h"
|
||||
#include "wpi/uv/Error.h"
|
||||
|
||||
namespace wpi {
|
||||
namespace uv {
|
||||
|
||||
class Handle;
|
||||
|
||||
/**
|
||||
* Event loop.
|
||||
*
|
||||
* The event loop is the central part of uv functionality. It takes care of
|
||||
* polling for I/O and scheduling signals to be generated based on different
|
||||
* sources of events.
|
||||
*
|
||||
* The event loop is not moveable, copyable, or directly constructible. Use
|
||||
* Create() to create an event loop, or GetDefault() to get the default loop
|
||||
* if you know your program will only have a single one.
|
||||
*/
|
||||
class Loop final : public std::enable_shared_from_this<Loop> {
|
||||
struct private_init {};
|
||||
|
||||
public:
|
||||
using Time = std::chrono::duration<uint64_t, std::milli>;
|
||||
|
||||
enum Mode {
|
||||
kDefault = UV_RUN_DEFAULT,
|
||||
kOnce = UV_RUN_ONCE,
|
||||
kNoWait = UV_RUN_NOWAIT
|
||||
};
|
||||
|
||||
explicit Loop(const private_init&) noexcept;
|
||||
|
||||
Loop(const Loop&) = delete;
|
||||
Loop& operator=(const Loop&) = delete;
|
||||
Loop(Loop&& oth) = delete;
|
||||
Loop& operator=(Loop&& oth) = delete;
|
||||
|
||||
~Loop() noexcept;
|
||||
|
||||
/**
|
||||
* Create a new event loop. The created loop is not the default event loop.
|
||||
*
|
||||
* @return The newly created loop. May return nullptr if a failure occurs.
|
||||
*/
|
||||
static std::shared_ptr<Loop> Create();
|
||||
|
||||
/**
|
||||
* Create the default event loop. Only use this event loop if a single loop
|
||||
* is needed for the entire application.
|
||||
*
|
||||
* @return The newly created loop. May return nullptr if a failure occurs.
|
||||
*/
|
||||
static std::shared_ptr<Loop> GetDefault();
|
||||
|
||||
/**
|
||||
* Release all internal loop resources.
|
||||
*
|
||||
* Call this function only when the loop has finished executing and all open
|
||||
* handles and requests have been closed, or the loop will emit an error.
|
||||
*
|
||||
* error() will be emitted in case of errors.
|
||||
*/
|
||||
void Close();
|
||||
|
||||
/**
|
||||
* Run the event loop.
|
||||
*
|
||||
* Available modes are:
|
||||
*
|
||||
* * `Loop::kDefault`: Run the event loop until there are no
|
||||
* active and referenced handles or requests.
|
||||
* * `Loop::kOnce`: Run a single event loop iteration. Note that this
|
||||
* function blocksif there are no pending callbacks.
|
||||
* * `Loop::kNoWait`: Run a single event loop iteration, but don't block
|
||||
* if there are no pending callbacks.
|
||||
*
|
||||
* @return True when done, false in all other cases.
|
||||
*/
|
||||
bool Run(Mode mode = kDefault) {
|
||||
return uv_run(m_loop, static_cast<uv_run_mode>(static_cast<int>(mode))) ==
|
||||
0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there are active resources.
|
||||
*
|
||||
* @return True if there are active resources in the loop.
|
||||
*/
|
||||
bool IsAlive() const noexcept { return uv_loop_alive(m_loop) != 0; }
|
||||
|
||||
/**
|
||||
* Stop the event loop.
|
||||
*
|
||||
* This will cause Run() to end as soon as possible.
|
||||
* This will happen not sooner than the next loop iteration.
|
||||
* If this function was called before blocking for I/O, the loop won’t block
|
||||
* for I/O on this iteration.
|
||||
*/
|
||||
void Stop() noexcept { uv_stop(m_loop); }
|
||||
|
||||
/**
|
||||
* Get backend file descriptor.
|
||||
*
|
||||
* Only kqueue, epoll and event ports are supported.
|
||||
* This can be used in conjunction with `run(Loop::kNoWait)` to poll
|
||||
* in one thread and run the event loop’s callbacks in another.
|
||||
*
|
||||
* @return The backend file descriptor.
|
||||
*/
|
||||
int GetDescriptor() const noexcept { return uv_backend_fd(m_loop); }
|
||||
|
||||
/**
|
||||
* Get the poll timeout.
|
||||
*
|
||||
* @return A `std::pair` composed of a boolean value that is true in case of
|
||||
* valid timeout, false otherwise, and the timeout
|
||||
* (`std::chrono::duration<uint64_t, std::milli>`).
|
||||
*/
|
||||
std::pair<bool, Time> GetTimeout() const noexcept {
|
||||
auto to = uv_backend_timeout(m_loop);
|
||||
return std::make_pair(to == -1, Time{to});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current timestamp in milliseconds.
|
||||
*
|
||||
* The timestamp is cached at the start of the event loop tick.
|
||||
* The timestamp increases monotonically from some arbitrary point in
|
||||
* time.
|
||||
* Don’t make assumptions about the starting point, you will only get
|
||||
* disappointed.
|
||||
*
|
||||
* @return The current timestamp in milliseconds (actual type is
|
||||
* `std::chrono::duration<uint64_t, std::milli>`).
|
||||
*/
|
||||
Time Now() const noexcept { return Time{uv_now(m_loop)}; }
|
||||
|
||||
/**
|
||||
* Update the event loop’s concept of _now_.
|
||||
*
|
||||
* The current time is cached at the start of the event loop tick in order
|
||||
* to reduce the number of time-related system calls.
|
||||
* You won’t normally need to call this function unless you have callbacks
|
||||
* that block the event loop for longer periods of time, where _longer_ is
|
||||
* somewhat subjective but probably on the order of a millisecond or more.
|
||||
*/
|
||||
void UpdateTime() noexcept { uv_update_time(m_loop); }
|
||||
|
||||
/**
|
||||
* Walk the list of handles.
|
||||
*
|
||||
* The callback will be executed once for each handle that is still active.
|
||||
*
|
||||
* @param callback A function to be invoked once for each active handle.
|
||||
*/
|
||||
void Walk(std::function<void(Handle&)> callback);
|
||||
|
||||
/**
|
||||
* Reinitialize any kernel state necessary in the child process after
|
||||
* a fork(2) system call.
|
||||
*
|
||||
* Previously started watchers will continue to be started in the child
|
||||
* process.
|
||||
*
|
||||
* It is necessary to explicitly call this function on every event loop
|
||||
* created in the parent process that you plan to continue to use in the
|
||||
* child, including the default loop (even if you don’t continue to use it
|
||||
* in the parent). This function must be called before calling any API
|
||||
* function using the loop in the child. Failure to do so will result in
|
||||
* undefined behaviour, possibly including duplicate events delivered to
|
||||
* both parent and child or aborting the child process.
|
||||
*
|
||||
* When possible, it is preferred to create a new loop in the child process
|
||||
* instead of reusing a loop created in the parent. New loops created in the
|
||||
* child process after the fork should not use this function.
|
||||
*
|
||||
* Note that this function is not implemented on Windows.
|
||||
* Note also that this function is experimental in `libuv`. It may contain
|
||||
* bugs, and is subject to change or removal. API and ABI stability is not
|
||||
* guaranteed.
|
||||
*
|
||||
* error() will be emitted in case of errors.
|
||||
*/
|
||||
void Fork();
|
||||
|
||||
/**
|
||||
* Get the underlying event loop data structure.
|
||||
*
|
||||
* @return The underlying event loop data structure.
|
||||
*/
|
||||
uv_loop_t* GetRaw() const noexcept { return m_loop; }
|
||||
|
||||
/**
|
||||
* Error signal
|
||||
*/
|
||||
sig::Signal<Error> error;
|
||||
|
||||
/**
|
||||
* Reports error.
|
||||
* @param err Error code
|
||||
*/
|
||||
void ReportError(int err) { error(Error(err)); }
|
||||
|
||||
private:
|
||||
uv_loop_t* m_loop;
|
||||
uv_loop_t m_loopStruct;
|
||||
};
|
||||
|
||||
} // namespace uv
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_UV_LOOP_H_
|
||||
156
wpiutil/src/main/native/include/wpi/uv/NetworkStream.h
Normal file
156
wpiutil/src/main/native/include/wpi/uv/NetworkStream.h
Normal file
@@ -0,0 +1,156 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_WPI_UV_NETWORKSTREAM_H_
|
||||
#define WPIUTIL_WPI_UV_NETWORKSTREAM_H_
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include "wpi/Signal.h"
|
||||
#include "wpi/uv/Stream.h"
|
||||
|
||||
namespace wpi {
|
||||
namespace uv {
|
||||
|
||||
class NetworkStream;
|
||||
|
||||
/**
|
||||
* Connection request.
|
||||
*/
|
||||
class ConnectReq : public RequestImpl<ConnectReq, uv_connect_t> {
|
||||
public:
|
||||
ConnectReq();
|
||||
|
||||
NetworkStream& GetStream() const {
|
||||
return *static_cast<NetworkStream*>(GetRaw()->handle->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Connection completed signal.
|
||||
*/
|
||||
sig::Signal<> connected;
|
||||
};
|
||||
|
||||
/**
|
||||
* Network stream handle.
|
||||
* This is an abstract type; there are two network stream implementations (Tcp
|
||||
* and Pipe).
|
||||
*/
|
||||
class NetworkStream : public Stream {
|
||||
public:
|
||||
static constexpr int kDefaultBacklog = 128;
|
||||
|
||||
std::shared_ptr<NetworkStream> shared_from_this() {
|
||||
return std::static_pointer_cast<NetworkStream>(Handle::shared_from_this());
|
||||
}
|
||||
|
||||
std::shared_ptr<const NetworkStream> shared_from_this() const {
|
||||
return std::static_pointer_cast<const NetworkStream>(
|
||||
Handle::shared_from_this());
|
||||
}
|
||||
|
||||
/**
|
||||
* Start listening for incoming connections. When a new incoming connection
|
||||
* is received the connection signal is generated.
|
||||
* @param backlog the number of connections the kernel might queue, same as
|
||||
* listen(2).
|
||||
*/
|
||||
void Listen(int backlog = kDefaultBacklog);
|
||||
|
||||
/**
|
||||
* Start listening for incoming connections. This is a convenience wrapper
|
||||
* around `Listen(int)` that also connects a callback to the connection
|
||||
* signal. When a new incoming connection is received the connection signal
|
||||
* is generated (and the callback is called).
|
||||
* @param callback the callback to call when a connection is received.
|
||||
* `Accept()` should be called from this callback.
|
||||
* @param backlog the number of connections the kernel might queue, same as
|
||||
* listen(2).
|
||||
*/
|
||||
void Listen(std::function<void()> callback, int backlog = kDefaultBacklog);
|
||||
|
||||
/**
|
||||
* Accept incoming connection.
|
||||
*
|
||||
* This call is used in conjunction with `Listen()` to accept incoming
|
||||
* connections. Call this function after receiving a ListenEvent event to
|
||||
* accept the connection.
|
||||
* An error signal will be emitted in case of errors.
|
||||
*
|
||||
* When the connection signal is emitted it is guaranteed that this
|
||||
* function will complete successfully the first time. If you attempt to use
|
||||
* it more than once, it may fail.
|
||||
* It is suggested to only call this function once per connection signal.
|
||||
*
|
||||
* @return The stream handle for the accepted connection, or nullptr on error.
|
||||
*/
|
||||
std::shared_ptr<NetworkStream> Accept() {
|
||||
return DoAccept()->shared_from_this();
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept incoming connection.
|
||||
*
|
||||
* This call is used in conjunction with `Listen()` to accept incoming
|
||||
* connections. Call this function after receiving a connection signal to
|
||||
* accept the connection.
|
||||
* An error signal will be emitted in case of errors.
|
||||
*
|
||||
* When the connection signal is emitted it is guaranteed that this
|
||||
* function will complete successfully the first time. If you attempt to use
|
||||
* it more than once, it may fail.
|
||||
* It is suggested to only call this function once per connection signal.
|
||||
*
|
||||
* @param client Client stream object.
|
||||
* @return False on error.
|
||||
*/
|
||||
bool Accept(const std::shared_ptr<NetworkStream>& client) {
|
||||
return Invoke(&uv_accept, GetRawStream(), client->GetRawStream());
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal generated when an incoming connection is received.
|
||||
*/
|
||||
sig::Signal<> connection;
|
||||
|
||||
protected:
|
||||
explicit NetworkStream(uv_stream_t* uv_stream) : Stream{uv_stream} {}
|
||||
|
||||
virtual NetworkStream* DoAccept() = 0;
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
class NetworkStreamImpl : public NetworkStream {
|
||||
public:
|
||||
std::shared_ptr<T> shared_from_this() {
|
||||
return std::static_pointer_cast<T>(Handle::shared_from_this());
|
||||
}
|
||||
|
||||
std::shared_ptr<const T> shared_from_this() const {
|
||||
return std::static_pointer_cast<const T>(Handle::shared_from_this());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underlying handle data structure.
|
||||
*
|
||||
* @return The underlying handle data structure.
|
||||
*/
|
||||
U* GetRaw() const noexcept {
|
||||
return reinterpret_cast<U*>(this->GetRawHandle());
|
||||
}
|
||||
|
||||
protected:
|
||||
NetworkStreamImpl() : NetworkStream{reinterpret_cast<uv_stream_t*>(new U)} {}
|
||||
};
|
||||
|
||||
} // namespace uv
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_UV_NETWORKSTREAM_H_
|
||||
194
wpiutil/src/main/native/include/wpi/uv/Pipe.h
Normal file
194
wpiutil/src/main/native/include/wpi/uv/Pipe.h
Normal file
@@ -0,0 +1,194 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_WPI_UV_PIPE_H_
|
||||
#define WPIUTIL_WPI_UV_PIPE_H_
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "wpi/Twine.h"
|
||||
#include "wpi/uv/NetworkStream.h"
|
||||
|
||||
namespace wpi {
|
||||
namespace uv {
|
||||
|
||||
class Loop;
|
||||
class PipeConnectReq;
|
||||
|
||||
/**
|
||||
* Pipe handle.
|
||||
* Pipe handles provide an abstraction over local domain sockets on Unix and
|
||||
* named pipes on Windows.
|
||||
*/
|
||||
class Pipe final : public NetworkStreamImpl<Pipe, uv_pipe_t> {
|
||||
struct private_init {};
|
||||
|
||||
public:
|
||||
explicit Pipe(const private_init&) {}
|
||||
~Pipe() noexcept override = default;
|
||||
|
||||
/**
|
||||
* Create a pipe handle.
|
||||
*
|
||||
* @param loop Loop object where this handle runs.
|
||||
* @param ipc Indicates if this pipe will be used for handle passing between
|
||||
* processes.
|
||||
*/
|
||||
static std::shared_ptr<Pipe> Create(Loop& loop, bool ipc = false);
|
||||
|
||||
/**
|
||||
* Create a pipe handle.
|
||||
*
|
||||
* @param loop Loop object where this handle runs.
|
||||
* @param ipc Indicates if this pipe will be used for handle passing between
|
||||
* processes.
|
||||
*/
|
||||
static std::shared_ptr<Pipe> Create(const std::shared_ptr<Loop>& loop,
|
||||
bool ipc = false) {
|
||||
return Create(*loop, ipc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept incoming connection.
|
||||
*
|
||||
* This call is used in conjunction with `Listen()` to accept incoming
|
||||
* connections. Call this function after receiving a ListenEvent event to
|
||||
* accept the connection.
|
||||
* An error signal will be emitted in case of errors.
|
||||
*
|
||||
* When the connection signal is emitted it is guaranteed that this
|
||||
* function will complete successfully the first time. If you attempt to use
|
||||
* it more than once, it may fail.
|
||||
* It is suggested to only call this function once per connection signal.
|
||||
*
|
||||
* @return The stream handle for the accepted connection, or nullptr on error.
|
||||
*/
|
||||
std::shared_ptr<Pipe> Accept();
|
||||
|
||||
/**
|
||||
* Accept incoming connection.
|
||||
*
|
||||
* This call is used in conjunction with `Listen()` to accept incoming
|
||||
* connections. Call this function after receiving a connection signal to
|
||||
* accept the connection.
|
||||
* An error signal will be emitted in case of errors.
|
||||
*
|
||||
* When the connection signal is emitted it is guaranteed that this
|
||||
* function will complete successfully the first time. If you attempt to use
|
||||
* it more than once, it may fail.
|
||||
* It is suggested to only call this function once per connection signal.
|
||||
*
|
||||
* @param client Client stream object.
|
||||
* @return False on error.
|
||||
*/
|
||||
bool Accept(const std::shared_ptr<Pipe>& client) {
|
||||
return NetworkStream::Accept(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open an existing file descriptor or HANDLE as a pipe.
|
||||
*
|
||||
* @note The passed file descriptor or HANDLE is not checked for its type, but
|
||||
* it's required that it represents a valid pipe.
|
||||
*
|
||||
* @param file A valid file handle (either a file descriptor or a HANDLE).
|
||||
*/
|
||||
void Open(uv_file file) { Invoke(&uv_pipe_open, GetRaw(), file); }
|
||||
|
||||
/**
|
||||
* Bind the pipe to a file path (Unix) or a name (Windows).
|
||||
*
|
||||
* @note Paths on Unix get truncated to `sizeof(sockaddr_un.sun_path)` bytes,
|
||||
* typically between 92 and 108 bytes.
|
||||
*
|
||||
* @param name File path (Unix) or name (Windows).
|
||||
*/
|
||||
void Bind(const Twine& name);
|
||||
|
||||
/**
|
||||
* Connect to the Unix domain socket or the named pipe.
|
||||
*
|
||||
* @note Paths on Unix get truncated to `sizeof(sockaddr_un.sun_path)` bytes,
|
||||
* typically between 92 and 108 bytes.
|
||||
*
|
||||
* HandleConnected() is called on the request when the connection has been
|
||||
* established.
|
||||
* HandleError() is called on the request in case of errors during the
|
||||
* connection.
|
||||
*
|
||||
* @param name File path (Unix) or name (Windows).
|
||||
* @param req connection request
|
||||
*/
|
||||
void Connect(const Twine& name, const std::shared_ptr<PipeConnectReq>& req);
|
||||
|
||||
/**
|
||||
* Connect to the Unix domain socket or the named pipe.
|
||||
*
|
||||
* @note Paths on Unix get truncated to `sizeof(sockaddr_un.sun_path)` bytes,
|
||||
* typically between 92 and 108 bytes.
|
||||
*
|
||||
* The callback is called when the connection has been established. Errors
|
||||
* are reported to the stream error handler.
|
||||
*
|
||||
* @param name File path (Unix) or name (Windows).
|
||||
* @param callback Callback function to call when connection established
|
||||
*/
|
||||
void Connect(const Twine& name, std::function<void()> callback);
|
||||
|
||||
/**
|
||||
* Get the name of the Unix domain socket or the named pipe.
|
||||
* @return The name (will be empty if an error occurred).
|
||||
*/
|
||||
std::string GetSock();
|
||||
|
||||
/**
|
||||
* Get the name of the Unix domain socket or the named pipe to which the
|
||||
* handle is connected.
|
||||
* @return The name (will be empty if an error occurred).
|
||||
*/
|
||||
std::string GetPeer();
|
||||
|
||||
/**
|
||||
* Set the number of pending pipe instance handles when the pipe server is
|
||||
* waiting for connections.
|
||||
* @note This setting applies to Windows only.
|
||||
* @param count Number of pending handles.
|
||||
*/
|
||||
void SetPendingInstances(int count) {
|
||||
uv_pipe_pending_instances(GetRaw(), count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alters pipe permissions, allowing it to be accessed from processes run
|
||||
* by different users. Makes the pipe writable or readable by all users.
|
||||
* Mode can be UV_WRITABLE, UV_READABLE, or both. This function is blocking.
|
||||
* @param flags chmod flags
|
||||
*/
|
||||
void Chmod(int flags) { Invoke(&uv_pipe_chmod, GetRaw(), flags); }
|
||||
|
||||
private:
|
||||
Pipe* DoAccept() override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Pipe connection request.
|
||||
*/
|
||||
class PipeConnectReq : public ConnectReq {
|
||||
public:
|
||||
Pipe& GetStream() const {
|
||||
return *static_cast<Pipe*>(&ConnectReq::GetStream());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace uv
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_UV_PIPE_H_
|
||||
93
wpiutil/src/main/native/include/wpi/uv/Poll.h
Normal file
93
wpiutil/src/main/native/include/wpi/uv/Poll.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_WPI_UV_POLL_H_
|
||||
#define WPIUTIL_WPI_UV_POLL_H_
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "wpi/Signal.h"
|
||||
#include "wpi/uv/Handle.h"
|
||||
|
||||
namespace wpi {
|
||||
namespace uv {
|
||||
|
||||
class Loop;
|
||||
|
||||
/**
|
||||
* Poll handle.
|
||||
*/
|
||||
class Poll final : public HandleImpl<Poll, uv_poll_t> {
|
||||
struct private_init {};
|
||||
|
||||
public:
|
||||
explicit Poll(const private_init&) {}
|
||||
~Poll() noexcept override = default;
|
||||
|
||||
/**
|
||||
* Create a poll handle using a file descriptor.
|
||||
*
|
||||
* @param loop Loop object where this handle runs.
|
||||
* @param fd File descriptor.
|
||||
*/
|
||||
static std::shared_ptr<Poll> Create(Loop& loop, int fd);
|
||||
|
||||
/**
|
||||
* Create a poll handle using a file descriptor.
|
||||
*
|
||||
* @param loop Loop object where this handle runs.
|
||||
* @param fd File descriptor.
|
||||
*/
|
||||
static std::shared_ptr<Poll> Create(const std::shared_ptr<Loop>& loop,
|
||||
int fd) {
|
||||
return Create(*loop, fd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a poll handle using a socket descriptor.
|
||||
*
|
||||
* @param loop Loop object where this handle runs.
|
||||
* @param sock Socket descriptor.
|
||||
*/
|
||||
static std::shared_ptr<Poll> CreateSocket(Loop& loop, uv_os_sock_t sock);
|
||||
|
||||
/**
|
||||
* Create a poll handle using a socket descriptor.
|
||||
*
|
||||
* @param loop Loop object where this handle runs.
|
||||
* @param sock Socket descriptor.
|
||||
*/
|
||||
static std::shared_ptr<Poll> CreateSocket(const std::shared_ptr<Loop>& loop,
|
||||
uv_os_sock_t sock) {
|
||||
return CreateSocket(*loop, sock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start polling the file descriptor.
|
||||
*
|
||||
* @param events Bitmask of events (UV_READABLE, UV_WRITEABLE, UV_PRIORITIZED,
|
||||
* and UV_DISCONNECT).
|
||||
*/
|
||||
void Start(int events);
|
||||
|
||||
/**
|
||||
* Stop polling the file descriptor.
|
||||
*/
|
||||
void Stop() { Invoke(&uv_poll_stop, GetRaw()); }
|
||||
|
||||
/**
|
||||
* Signal generated when a poll event occurs.
|
||||
*/
|
||||
sig::Signal<int> pollEvent;
|
||||
};
|
||||
|
||||
} // namespace uv
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_UV_POLL_H_
|
||||
70
wpiutil/src/main/native/include/wpi/uv/Prepare.h
Normal file
70
wpiutil/src/main/native/include/wpi/uv/Prepare.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_WPI_UV_PREPARE_H_
|
||||
#define WPIUTIL_WPI_UV_PREPARE_H_
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "wpi/Signal.h"
|
||||
#include "wpi/uv/Handle.h"
|
||||
|
||||
namespace wpi {
|
||||
namespace uv {
|
||||
|
||||
class Loop;
|
||||
|
||||
/**
|
||||
* Prepare handle.
|
||||
* Prepare handles will generate a signal once per loop iteration, right
|
||||
* before polling for I/O.
|
||||
*/
|
||||
class Prepare final : public HandleImpl<Prepare, uv_prepare_t> {
|
||||
struct private_init {};
|
||||
|
||||
public:
|
||||
explicit Prepare(const private_init&) {}
|
||||
~Prepare() noexcept override = default;
|
||||
|
||||
/**
|
||||
* Create a prepare handle.
|
||||
*
|
||||
* @param loop Loop object where this handle runs.
|
||||
*/
|
||||
static std::shared_ptr<Prepare> Create(Loop& loop);
|
||||
|
||||
/**
|
||||
* Create a prepare handle.
|
||||
*
|
||||
* @param loop Loop object where this handle runs.
|
||||
*/
|
||||
static std::shared_ptr<Prepare> Create(const std::shared_ptr<Loop>& loop) {
|
||||
return Create(*loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the handle.
|
||||
*/
|
||||
void Start();
|
||||
|
||||
/**
|
||||
* Stop the handle. The signal will no longer be generated.
|
||||
*/
|
||||
void Stop() { Invoke(&uv_prepare_stop, GetRaw()); }
|
||||
|
||||
/**
|
||||
* Signal generated once per loop iteration prior to polling for I/O.
|
||||
*/
|
||||
sig::Signal<> prepare;
|
||||
};
|
||||
|
||||
} // namespace uv
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_UV_PREPARE_H_
|
||||
226
wpiutil/src/main/native/include/wpi/uv/Process.h
Normal file
226
wpiutil/src/main/native/include/wpi/uv/Process.h
Normal file
@@ -0,0 +1,226 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_WPI_UV_PROCESS_H_
|
||||
#define WPIUTIL_WPI_UV_PROCESS_H_
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "wpi/Signal.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/Twine.h"
|
||||
#include "wpi/uv/Handle.h"
|
||||
|
||||
namespace wpi {
|
||||
namespace uv {
|
||||
|
||||
class Loop;
|
||||
class Pipe;
|
||||
|
||||
/**
|
||||
* Process options.
|
||||
*/
|
||||
class ProcessOptions final {
|
||||
friend class Process;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Set environment variables for the subprocess. If not set or set to
|
||||
* nullptr, the parent's environment is used.
|
||||
* @param env environment variables
|
||||
*/
|
||||
ProcessOptions& SetEnv(char** env) {
|
||||
m_env = env;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current working directory for the subprocess.
|
||||
* @param cwd current working directory
|
||||
*/
|
||||
ProcessOptions& SetCwd(const Twine& cwd) {
|
||||
m_cwd = cwd.str();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the child process' user id.
|
||||
* @param uid user id
|
||||
*/
|
||||
ProcessOptions& SetUid(uv_uid_t uid) noexcept {
|
||||
m_uid = uid;
|
||||
m_flags |= UV_PROCESS_SETUID;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the child process' group id.
|
||||
* @param gid group id
|
||||
*/
|
||||
ProcessOptions& SetGid(uv_gid_t gid) noexcept {
|
||||
m_gid = gid;
|
||||
m_flags |= UV_PROCESS_SETGID;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set flags.
|
||||
* @param flags Bitmask values from uv_process_flags.
|
||||
*/
|
||||
ProcessOptions& SetFlags(unsigned int flags) noexcept {
|
||||
m_flags |= flags;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear flags.
|
||||
* @param flags Bitmask values from uv_process_flags.
|
||||
*/
|
||||
ProcessOptions& ClearFlags(unsigned int flags) noexcept {
|
||||
m_flags &= ~flags;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Explicitly ignore a stdio.
|
||||
* @param index stdio index
|
||||
*/
|
||||
ProcessOptions& StdioIgnore(size_t index);
|
||||
|
||||
/**
|
||||
* Inherit a file descriptor from the parent process.
|
||||
* @param index stdio index
|
||||
* @param fd parent file descriptor
|
||||
*/
|
||||
ProcessOptions& StdioInherit(size_t index, int fd);
|
||||
|
||||
/**
|
||||
* Inherit a pipe from the parent process.
|
||||
* @param index stdio index
|
||||
* @param pipe pipe
|
||||
*/
|
||||
ProcessOptions& StdioInherit(size_t index, Pipe& pipe);
|
||||
|
||||
/**
|
||||
* Create a pipe between the child and the parent.
|
||||
* @param index stdio index
|
||||
* @param pipe pipe
|
||||
* @param flags Some combination of UV_READABLE_PIPE, UV_WRITABLE_PIPE, and
|
||||
* UV_OVERLAPPED_PIPE (Windows only, ignored on Unix).
|
||||
*/
|
||||
ProcessOptions& StdioCreatePipe(size_t index, Pipe& pipe, unsigned int flags);
|
||||
|
||||
private:
|
||||
char** m_env = nullptr;
|
||||
std::string m_cwd;
|
||||
unsigned int m_flags = 0;
|
||||
struct StdioContainer : public uv_stdio_container_t {
|
||||
StdioContainer() {
|
||||
flags = UV_IGNORE;
|
||||
data.fd = 0;
|
||||
}
|
||||
};
|
||||
SmallVector<StdioContainer, 4> m_stdio;
|
||||
uv_uid_t m_uid = 0;
|
||||
uv_gid_t m_gid = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Process handle.
|
||||
* Process handles will spawn a new process and allow the user to control it
|
||||
* and establish communication channels with it using streams.
|
||||
*/
|
||||
class Process final : public HandleImpl<Process, uv_process_t> {
|
||||
struct private_init {};
|
||||
|
||||
public:
|
||||
explicit Process(const private_init&) {}
|
||||
~Process() noexcept override = default;
|
||||
|
||||
/**
|
||||
* Disables inheritance for file descriptors / handles that this process
|
||||
* inherited from its parent. The effect is that child processes spawned
|
||||
* by this process don't accidentally inherit these handles.
|
||||
*
|
||||
* It is recommended to call this function as early in your program as
|
||||
* possible, before the inherited file descriptors can be closed or
|
||||
* duplicated.
|
||||
*/
|
||||
static void DisableStdioInheritance() { uv_disable_stdio_inheritance(); }
|
||||
|
||||
/**
|
||||
* Starts a process. If the process is not successfully spawned, an error
|
||||
* is generated on the loop and this function returns nullptr.
|
||||
*
|
||||
* Possible reasons for failing to spawn would include (but not be limited to)
|
||||
* the file to execute not existing, not having permissions to use the setuid
|
||||
* or setgid specified, or not having enough memory to allocate for the new
|
||||
* process.
|
||||
*
|
||||
* @param loop Loop object where this handle runs.
|
||||
* @param file Path pointing to the program to be executed
|
||||
* @param args Command line arguments
|
||||
* @param options Process options
|
||||
*/
|
||||
static std::shared_ptr<Process> Spawn(
|
||||
Loop& loop, const Twine& file, char** args,
|
||||
const ProcessOptions& options = ProcessOptions{});
|
||||
|
||||
/**
|
||||
* Starts a process. If the process is not successfully spawned, an error
|
||||
* is generated on the loop and this function returns nullptr.
|
||||
*
|
||||
* Possible reasons for failing to spawn would include (but not be limited to)
|
||||
* the file to execute not existing, not having permissions to use the setuid
|
||||
* or setgid specified, or not having enough memory to allocate for the new
|
||||
* process.
|
||||
*
|
||||
* @param loop Loop object where this handle runs.
|
||||
* @param file Path pointing to the program to be executed
|
||||
* @param args Command line arguments
|
||||
* @param options Process options
|
||||
*/
|
||||
static std::shared_ptr<Process> Spawn(
|
||||
const std::shared_ptr<Loop>& loop, const Twine& file, char** args,
|
||||
const ProcessOptions& options = ProcessOptions{}) {
|
||||
return Spawn(*loop, file, args, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the specified signal to the process.
|
||||
* @param signum signal number
|
||||
*/
|
||||
void Kill(int signum) { Invoke(&uv_process_kill, GetRaw(), signum); }
|
||||
|
||||
/**
|
||||
* Sends the specified signal to the given PID.
|
||||
* @param pid process ID
|
||||
* @param signum signal number
|
||||
* @return 0 on success, otherwise error code.
|
||||
*/
|
||||
static int Kill(int pid, int signum) noexcept { return uv_kill(pid, signum); }
|
||||
|
||||
/**
|
||||
* Get the process ID.
|
||||
* @return Process ID.
|
||||
*/
|
||||
uv_pid_t GetPid() const noexcept { return GetRaw()->pid; }
|
||||
|
||||
/**
|
||||
* Signal generated when the process exits. The parameters are the exit
|
||||
* status and the signal that caused the process to terminate, if any.
|
||||
*/
|
||||
sig::Signal<int64_t, int> exited;
|
||||
};
|
||||
|
||||
} // namespace uv
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_UV_PROCESS_H_
|
||||
171
wpiutil/src/main/native/include/wpi/uv/Request.h
Normal file
171
wpiutil/src/main/native/include/wpi/uv/Request.h
Normal file
@@ -0,0 +1,171 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_WPI_UV_REQUEST_H_
|
||||
#define WPIUTIL_WPI_UV_REQUEST_H_
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include "wpi/uv/Error.h"
|
||||
|
||||
namespace wpi {
|
||||
namespace uv {
|
||||
|
||||
/**
|
||||
* Request. Requests are not moveable or copyable.
|
||||
* This class provides shared_ptr ownership and shared_from_this.
|
||||
*/
|
||||
class Request : public std::enable_shared_from_this<Request> {
|
||||
public:
|
||||
using Type = uv_req_type;
|
||||
|
||||
Request(const Request&) = delete;
|
||||
Request(Request&&) = delete;
|
||||
Request& operator=(const Request&) = delete;
|
||||
Request& operator=(Request&&) = delete;
|
||||
virtual ~Request() noexcept = default;
|
||||
|
||||
/**
|
||||
* Get the type of the request.
|
||||
*
|
||||
* A base request offers no functionality to promote it to the actual request
|
||||
* type. By means of this function, the type of the underlying request as
|
||||
* specified by Type is made available.
|
||||
*
|
||||
* @return The actual type of the request.
|
||||
*/
|
||||
Type GetType() const noexcept { return m_uv_req->type; }
|
||||
|
||||
/**
|
||||
* Get the name of the type of the request. E.g. "connect" for connect.
|
||||
*/
|
||||
const char* GetTypeName() const noexcept {
|
||||
return uv_req_type_name(m_uv_req->type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel a pending request.
|
||||
*
|
||||
* This method fails if the request is executing or has finished
|
||||
* executing.
|
||||
* It can emit an error signal in case of errors.
|
||||
*
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
bool Cancel() { return uv_cancel(m_uv_req) == 0; }
|
||||
|
||||
/**
|
||||
* Return the size of the underlying request type.
|
||||
* @return The size of the underlying request type.
|
||||
*/
|
||||
size_t RawSize() const noexcept { return uv_req_size(m_uv_req->type); }
|
||||
|
||||
/**
|
||||
* Get the underlying request data structure.
|
||||
*
|
||||
* @return The underlying request data structure.
|
||||
*/
|
||||
uv_req_t* GetRawReq() noexcept { return m_uv_req; }
|
||||
|
||||
/**
|
||||
* Get the underlying request data structure.
|
||||
*
|
||||
* @return The underlying request data structure.
|
||||
*/
|
||||
const uv_req_t* GetRawReq() const noexcept { return m_uv_req; }
|
||||
|
||||
/**
|
||||
* Keep this request in memory even if no outside shared_ptr references
|
||||
* remain. To release call Release().
|
||||
*
|
||||
* Derived classes can override this method for different memory management
|
||||
* approaches (e.g. pooled storage of requests).
|
||||
*/
|
||||
virtual void Keep() noexcept { m_self = shared_from_this(); }
|
||||
|
||||
/**
|
||||
* No longer force holding this request in memory. Does not immediately
|
||||
* destroy the object unless no outside shared_ptr references remain.
|
||||
*
|
||||
* Derived classes can override this method for different memory management
|
||||
* approaches (e.g. pooled storage of requests).
|
||||
*/
|
||||
virtual void Release() noexcept { m_self.reset(); }
|
||||
|
||||
/**
|
||||
* Error callback. By default, this is set up to report errors to the handle
|
||||
* that created this request.
|
||||
* @param err error code
|
||||
*/
|
||||
std::function<void(Error)> error;
|
||||
|
||||
/**
|
||||
* Report an error.
|
||||
* @param err Error code
|
||||
*/
|
||||
void ReportError(int err) { error(Error(err)); }
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
explicit Request(uv_req_t* uv_req) : m_uv_req{uv_req} {
|
||||
m_uv_req->data = this;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<Request> m_self;
|
||||
uv_req_t* m_uv_req;
|
||||
};
|
||||
|
||||
/**
|
||||
* Request. Requests are not moveable or copyable.
|
||||
* @tparam T CRTP derived class
|
||||
* @tparam U underlying libuv request type
|
||||
*/
|
||||
template <typename T, typename U>
|
||||
class RequestImpl : public Request {
|
||||
public:
|
||||
std::shared_ptr<T> shared_from_this() {
|
||||
return std::static_pointer_cast<T>(this->shared_from_this());
|
||||
}
|
||||
|
||||
std::shared_ptr<const T> shared_from_this() const {
|
||||
return std::static_pointer_cast<const T>(this->shared_from_this());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underlying request data structure.
|
||||
*
|
||||
* @return The underlying request data structure.
|
||||
*/
|
||||
U* GetRaw() noexcept { return &m_uv_req; }
|
||||
|
||||
/**
|
||||
* Get the underlying request data structure.
|
||||
*
|
||||
* @return The underlying request data structure.
|
||||
*/
|
||||
const U* GetRaw() const noexcept { return &m_uv_req; }
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
RequestImpl() : Request{reinterpret_cast<uv_req_t*>(&m_uv_req)} {}
|
||||
|
||||
private:
|
||||
U m_uv_req;
|
||||
};
|
||||
|
||||
} // namespace uv
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_UV_REQUEST_H_
|
||||
84
wpiutil/src/main/native/include/wpi/uv/Signal.h
Normal file
84
wpiutil/src/main/native/include/wpi/uv/Signal.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_WPI_UV_SIGNAL_H_
|
||||
#define WPIUTIL_WPI_UV_SIGNAL_H_
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "wpi/Signal.h"
|
||||
#include "wpi/uv/Handle.h"
|
||||
|
||||
namespace wpi {
|
||||
namespace uv {
|
||||
|
||||
class Loop;
|
||||
|
||||
/**
|
||||
* Signal handle.
|
||||
*/
|
||||
class Signal final : public HandleImpl<Signal, uv_signal_t> {
|
||||
struct private_init {};
|
||||
|
||||
public:
|
||||
explicit Signal(const private_init&) {}
|
||||
~Signal() noexcept override = default;
|
||||
|
||||
/**
|
||||
* Create a signal handle.
|
||||
*
|
||||
* @param loop Loop object where this handle runs.
|
||||
*/
|
||||
static std::shared_ptr<Signal> Create(Loop& loop);
|
||||
|
||||
/**
|
||||
* Create a signal handle.
|
||||
*
|
||||
* @param loop Loop object where this handle runs.
|
||||
*/
|
||||
static std::shared_ptr<Signal> Create(const std::shared_ptr<Loop>& loop) {
|
||||
return Create(*loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start watching for the given signal.
|
||||
*
|
||||
* @param signum Signal to watch for.
|
||||
*/
|
||||
void Start(int signum);
|
||||
|
||||
/**
|
||||
* Start watching for the given signal. Same as Start() but the signal
|
||||
* handler is reset the moment the signal is received.
|
||||
*
|
||||
* @param signum Signal to watch for.
|
||||
*/
|
||||
void StartOneshot(int signum);
|
||||
|
||||
/**
|
||||
* Stop watching for the signal.
|
||||
*/
|
||||
void Stop() { Invoke(&uv_signal_stop, GetRaw()); }
|
||||
|
||||
/**
|
||||
* Get the signal being monitored.
|
||||
* @return Signal number.
|
||||
*/
|
||||
int GetSignal() const { return GetRaw()->signum; }
|
||||
|
||||
/**
|
||||
* Signal generated when a signal occurs.
|
||||
*/
|
||||
sig::Signal<int> signal;
|
||||
};
|
||||
|
||||
} // namespace uv
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_UV_SIGNAL_H_
|
||||
249
wpiutil/src/main/native/include/wpi/uv/Stream.h
Normal file
249
wpiutil/src/main/native/include/wpi/uv/Stream.h
Normal file
@@ -0,0 +1,249 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_WPI_UV_STREAM_H_
|
||||
#define WPIUTIL_WPI_UV_STREAM_H_
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include "wpi/ArrayRef.h"
|
||||
#include "wpi/Signal.h"
|
||||
#include "wpi/uv/Buffer.h"
|
||||
#include "wpi/uv/Handle.h"
|
||||
#include "wpi/uv/Request.h"
|
||||
|
||||
namespace wpi {
|
||||
namespace uv {
|
||||
|
||||
class Stream;
|
||||
|
||||
/**
|
||||
* Shutdown request.
|
||||
*/
|
||||
class ShutdownReq : public RequestImpl<ShutdownReq, uv_shutdown_t> {
|
||||
public:
|
||||
ShutdownReq();
|
||||
|
||||
Stream& GetStream() const {
|
||||
return *static_cast<Stream*>(GetRaw()->handle->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown completed signal.
|
||||
*/
|
||||
sig::Signal<> complete;
|
||||
};
|
||||
|
||||
/**
|
||||
* Write request.
|
||||
*/
|
||||
class WriteReq : public RequestImpl<WriteReq, uv_write_t> {
|
||||
public:
|
||||
WriteReq();
|
||||
|
||||
Stream& GetStream() const {
|
||||
return *static_cast<Stream*>(GetRaw()->handle->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write completed signal. This is called even if an error occurred.
|
||||
* @param err error value
|
||||
*/
|
||||
sig::Signal<Error> finish;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stream handle.
|
||||
* Stream handles provide an abstraction of a duplex communication channel.
|
||||
* This is an abstract type; there are three stream implementations (Tcp,
|
||||
* Pipe, and Tty).
|
||||
*/
|
||||
class Stream : public Handle {
|
||||
public:
|
||||
std::shared_ptr<Stream> shared_from_this() {
|
||||
return std::static_pointer_cast<Stream>(Handle::shared_from_this());
|
||||
}
|
||||
|
||||
std::shared_ptr<const Stream> shared_from_this() const {
|
||||
return std::static_pointer_cast<const Stream>(Handle::shared_from_this());
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown the outgoing (write) side of a duplex stream. It waits for pending
|
||||
* write requests to complete. HandleShutdownComplete() is called on the
|
||||
* request after shutdown is complete.
|
||||
*
|
||||
* @param req shutdown request
|
||||
*/
|
||||
void Shutdown(const std::shared_ptr<ShutdownReq>& req);
|
||||
|
||||
/**
|
||||
* Shutdown the outgoing (write) side of a duplex stream. It waits for pending
|
||||
* write requests to complete. The callback is called after shutdown is
|
||||
* complete. Errors will be reported to the stream error handler.
|
||||
*
|
||||
* @param callback Callback function to call when shutdown completes
|
||||
* @return Connection object for the callback
|
||||
*/
|
||||
void Shutdown(std::function<void()> callback = nullptr);
|
||||
|
||||
/**
|
||||
* Start reading data from an incoming stream.
|
||||
*
|
||||
* A data signal will be emitted several times until there is no more
|
||||
* data to read or `StopRead()` is called.
|
||||
* An end signal will be emitted when there is no more data to read.
|
||||
*/
|
||||
void StartRead();
|
||||
|
||||
/**
|
||||
* Stop reading data from the stream.
|
||||
*
|
||||
* This function is idempotent and may be safely called on a stopped stream.
|
||||
*/
|
||||
void StopRead() { Invoke(&uv_read_stop, GetRawStream()); }
|
||||
|
||||
/**
|
||||
* Write data to the stream.
|
||||
*
|
||||
* Data are written in order. The lifetime of the data pointers passed in
|
||||
* the `bufs` parameter must exceed the lifetime of the write request.
|
||||
* An easy way to ensure this is to have the write request keep track of
|
||||
* the data and use either its Complete() function or destructor to free the
|
||||
* data.
|
||||
*
|
||||
* HandleWriteComplete() will be called on the request object when the data
|
||||
* has been written. HandleWriteComplete() is called even if an error occurs.
|
||||
* HandleError() will be called on the request object in case of errors.
|
||||
*
|
||||
* @param bufs The buffers to be written to the stream.
|
||||
* @param req write request
|
||||
*/
|
||||
void Write(ArrayRef<Buffer> bufs, const std::shared_ptr<WriteReq>& req);
|
||||
|
||||
/**
|
||||
* Write data to the stream.
|
||||
*
|
||||
* Data are written in order. The lifetime of the data pointers passed in
|
||||
* the `bufs` parameter must exceed the lifetime of the write request.
|
||||
* The callback can be used to free data after the request completes.
|
||||
*
|
||||
* The callback will be called when the data has been written. Errors will
|
||||
* be reported to the stream error handler.
|
||||
*
|
||||
* @param bufs The buffers to be written to the stream.
|
||||
* @param callback Callback function to call when the write completes
|
||||
*/
|
||||
void Write(ArrayRef<Buffer> bufs,
|
||||
std::function<void(MutableArrayRef<Buffer>, Error)> callback);
|
||||
|
||||
/**
|
||||
* Queue a write request if it can be completed immediately.
|
||||
*
|
||||
* Same as `Write()`, but won’t queue a write request if it can’t be
|
||||
* completed immediately.
|
||||
* An error signal will be emitted in case of errors.
|
||||
*
|
||||
* @param bufs The buffers to be written to the stream.
|
||||
* @return Number of bytes written.
|
||||
*/
|
||||
int TryWrite(ArrayRef<Buffer> bufs);
|
||||
|
||||
/**
|
||||
* Check if the stream is readable.
|
||||
* @return True if the stream is readable, false otherwise.
|
||||
*/
|
||||
bool IsReadable() const noexcept {
|
||||
return uv_is_readable(GetRawStream()) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if the stream is writable.
|
||||
* @return True if the stream is writable, false otherwise.
|
||||
*/
|
||||
bool IsWritable() const noexcept {
|
||||
return uv_is_writable(GetRawStream()) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable blocking mode for a stream.
|
||||
*
|
||||
* When blocking mode is enabled all writes complete synchronously. The
|
||||
* interface remains unchanged otherwise, e.g. completion or failure of the
|
||||
* operation will still be reported through events which are emitted
|
||||
* asynchronously.
|
||||
*
|
||||
* @param enable True to enable blocking mode, false otherwise.
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
bool SetBlocking(bool enable) noexcept {
|
||||
return uv_stream_set_blocking(GetRawStream(), enable) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the amount of queued bytes waiting to be sent.
|
||||
* @return Amount of queued bytes waiting to be sent.
|
||||
*/
|
||||
size_t GetWriteQueueSize() const noexcept {
|
||||
return GetRawStream()->write_queue_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underlying stream data structure.
|
||||
*
|
||||
* @return The underlying stream data structure.
|
||||
*/
|
||||
uv_stream_t* GetRawStream() const noexcept {
|
||||
return reinterpret_cast<uv_stream_t*>(GetRawHandle());
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal generated when data was read on a stream.
|
||||
*/
|
||||
sig::Signal<Buffer&, size_t> data;
|
||||
|
||||
/**
|
||||
* Signal generated when no more read data is available.
|
||||
*/
|
||||
sig::Signal<> end;
|
||||
|
||||
protected:
|
||||
explicit Stream(uv_stream_t* uv_stream)
|
||||
: Handle{reinterpret_cast<uv_handle_t*>(uv_stream)} {}
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
class StreamImpl : public Stream {
|
||||
public:
|
||||
std::shared_ptr<T> shared_from_this() {
|
||||
return std::static_pointer_cast<T>(Handle::shared_from_this());
|
||||
}
|
||||
|
||||
std::shared_ptr<const T> shared_from_this() const {
|
||||
return std::static_pointer_cast<const T>(Handle::shared_from_this());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underlying handle data structure.
|
||||
*
|
||||
* @return The underlying handle data structure.
|
||||
*/
|
||||
U* GetRaw() const noexcept {
|
||||
return reinterpret_cast<U*>(this->GetRawHandle());
|
||||
}
|
||||
|
||||
protected:
|
||||
StreamImpl() : Stream{reinterpret_cast<uv_stream_t*>(new U)} {}
|
||||
};
|
||||
|
||||
} // namespace uv
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_UV_STREAM_H_
|
||||
322
wpiutil/src/main/native/include/wpi/uv/Tcp.h
Normal file
322
wpiutil/src/main/native/include/wpi/uv/Tcp.h
Normal file
@@ -0,0 +1,322 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_WPI_UV_TCP_H_
|
||||
#define WPIUTIL_WPI_UV_TCP_H_
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include "wpi/Twine.h"
|
||||
#include "wpi/uv/NetworkStream.h"
|
||||
|
||||
namespace wpi {
|
||||
namespace uv {
|
||||
|
||||
class Loop;
|
||||
class TcpConnectReq;
|
||||
|
||||
/**
|
||||
* TCP handle.
|
||||
* TCP handles are used to represent both TCP streams and servers.
|
||||
*/
|
||||
class Tcp final : public NetworkStreamImpl<Tcp, uv_tcp_t> {
|
||||
struct private_init {};
|
||||
|
||||
public:
|
||||
using Time = std::chrono::duration<uint64_t, std::milli>;
|
||||
|
||||
explicit Tcp(const private_init&) {}
|
||||
~Tcp() noexcept override = default;
|
||||
|
||||
/**
|
||||
* Create a TCP handle.
|
||||
*
|
||||
* @param loop Loop object where this handle runs.
|
||||
* @param flags Flags
|
||||
*/
|
||||
static std::shared_ptr<Tcp> Create(Loop& loop,
|
||||
unsigned int flags = AF_UNSPEC);
|
||||
|
||||
/**
|
||||
* Create a TCP handle.
|
||||
*
|
||||
* @param loop Loop object where this handle runs.
|
||||
* @param flags Flags
|
||||
*/
|
||||
static std::shared_ptr<Tcp> Create(const std::shared_ptr<Loop>& loop,
|
||||
unsigned int flags = AF_UNSPEC) {
|
||||
return Create(*loop, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept incoming connection.
|
||||
*
|
||||
* This call is used in conjunction with `Listen()` to accept incoming
|
||||
* connections. Call this function after receiving a ListenEvent event to
|
||||
* accept the connection.
|
||||
* An error signal will be emitted in case of errors.
|
||||
*
|
||||
* When the connection signal is emitted it is guaranteed that this
|
||||
* function will complete successfully the first time. If you attempt to use
|
||||
* it more than once, it may fail.
|
||||
* It is suggested to only call this function once per connection signal.
|
||||
*
|
||||
* @return The stream handle for the accepted connection, or nullptr on error.
|
||||
*/
|
||||
std::shared_ptr<Tcp> Accept();
|
||||
|
||||
/**
|
||||
* Accept incoming connection.
|
||||
*
|
||||
* This call is used in conjunction with `Listen()` to accept incoming
|
||||
* connections. Call this function after receiving a connection signal to
|
||||
* accept the connection.
|
||||
* An error signal will be emitted in case of errors.
|
||||
*
|
||||
* When the connection signal is emitted it is guaranteed that this
|
||||
* function will complete successfully the first time. If you attempt to use
|
||||
* it more than once, it may fail.
|
||||
* It is suggested to only call this function once per connection signal.
|
||||
*
|
||||
* @param client Client stream object.
|
||||
* @return False on error.
|
||||
*/
|
||||
bool Accept(const std::shared_ptr<Tcp>& client) {
|
||||
return NetworkStream::Accept(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open an existing file descriptor or SOCKET as a TCP handle.
|
||||
*
|
||||
* @note The passed file descriptor or SOCKET is not checked for its type, but
|
||||
* it's required that it represents a valid stream socket.
|
||||
*
|
||||
* @param sock A valid socket handle (either a file descriptor or a SOCKET).
|
||||
*/
|
||||
void Open(uv_os_sock_t sock) { Invoke(&uv_tcp_open, GetRaw(), sock); }
|
||||
|
||||
/**
|
||||
* Enable/Disable Nagle's algorithm.
|
||||
* @param enable True to enable it, false otherwise.
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
bool SetNoDelay(bool enable) { return uv_tcp_nodelay(GetRaw(), enable) == 0; }
|
||||
|
||||
/**
|
||||
* Enable/Disable TCP keep-alive.
|
||||
* @param enable True to enable it, false otherwise.
|
||||
* @param time Initial delay in seconds (use
|
||||
* `std::chrono::duration<unsigned int>`).
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
bool SetKeepAlive(bool enable, Time time = Time{0}) {
|
||||
return uv_tcp_keepalive(GetRaw(), enable, time.count()) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/Disable simultaneous asynchronous accept requests.
|
||||
*
|
||||
* Enable/Disable simultaneous asynchronous accept requests that are
|
||||
* queued by the operating system when listening for new TCP
|
||||
* connections.
|
||||
* This setting is used to tune a TCP server for the desired performance.
|
||||
* Having simultaneous accepts can significantly improve the rate of
|
||||
* accepting connections (which is why it is enabled by default) but may
|
||||
* lead to uneven load distribution in multi-process setups.
|
||||
*
|
||||
* @param enable True to enable it, false otherwise.
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
bool SetSimultaneousAccepts(bool enable) {
|
||||
return uv_tcp_simultaneous_accepts(GetRaw(), enable) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind the handle to an IPv4 or IPv6 address and port.
|
||||
*
|
||||
* A successful call to this function does not guarantee that the call to
|
||||
* `Listen()` or `Connect()` will work properly.
|
||||
* An error signal can be emitted because of either this function or the
|
||||
* ones mentioned above.
|
||||
*
|
||||
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
|
||||
* @param flags Optional additional flags.
|
||||
*/
|
||||
void Bind(const sockaddr& addr, unsigned int flags = 0) {
|
||||
Invoke(&uv_tcp_bind, GetRaw(), &addr, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind the handle to an IPv4 address and port.
|
||||
*
|
||||
* A successful call to this function does not guarantee that the call to
|
||||
* `Listen()` or `Connect()` will work properly.
|
||||
* An error signal can be emitted because of either this function or the
|
||||
* ones mentioned above.
|
||||
*
|
||||
* Available flags are:
|
||||
*
|
||||
* @param ip The address to which to bind.
|
||||
* @param port The port to which to bind.
|
||||
* @param flags Optional additional flags.
|
||||
*/
|
||||
void Bind(const Twine& ip, unsigned int port, unsigned int flags = 0);
|
||||
|
||||
/**
|
||||
* Bind the handle to an IPv6 address and port.
|
||||
*
|
||||
* A successful call to this function does not guarantee that the call to
|
||||
* `Listen()` or `Connect()` will work properly.
|
||||
* An error signal can be emitted because of either this function or the
|
||||
* ones mentioned above.
|
||||
*
|
||||
* Available flags are:
|
||||
*
|
||||
* @param ip The address to which to bind.
|
||||
* @param port The port to which to bind.
|
||||
* @param flags Optional additional flags.
|
||||
*/
|
||||
void Bind6(const Twine& ip, unsigned int port, unsigned int flags = 0);
|
||||
|
||||
/**
|
||||
* Get the current address to which the handle is bound.
|
||||
* @return The address (will be zeroed if an error occurred).
|
||||
*/
|
||||
sockaddr_storage GetSock();
|
||||
|
||||
/**
|
||||
* Get the address of the peer connected to the handle.
|
||||
* @return The address (will be zeroed if an error occurred).
|
||||
*/
|
||||
sockaddr_storage GetPeer();
|
||||
|
||||
/**
|
||||
* Establish an IPv4 or IPv6 TCP connection.
|
||||
*
|
||||
* On Windows if the addr is initialized to point to an unspecified address
|
||||
* (`0.0.0.0` or `::`) it will be changed to point to localhost. This is
|
||||
* done to match the behavior of Linux systems.
|
||||
*
|
||||
* HandleConnected() is called on the request when the connection has been
|
||||
* established.
|
||||
* HandleError() is called on the request in case of errors during the
|
||||
* connection.
|
||||
*
|
||||
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
|
||||
* @param req connection request
|
||||
*/
|
||||
void Connect(const sockaddr& addr, const std::shared_ptr<TcpConnectReq>& req);
|
||||
|
||||
/**
|
||||
* Establish an IPv4 or IPv6 TCP connection.
|
||||
*
|
||||
* On Windows if the addr is initialized to point to an unspecified address
|
||||
* (`0.0.0.0` or `::`) it will be changed to point to localhost. This is
|
||||
* done to match the behavior of Linux systems.
|
||||
*
|
||||
* The callback is called when the connection has been established. Errors
|
||||
* are reported to the stream error handler.
|
||||
*
|
||||
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
|
||||
* @param callback Callback function to call when connection established
|
||||
*/
|
||||
void Connect(const sockaddr& addr, std::function<void()> callback);
|
||||
|
||||
/**
|
||||
* Establish an IPv4 TCP connection.
|
||||
*
|
||||
* On Windows if the addr is initialized to point to an unspecified address
|
||||
* (`0.0.0.0` or `::`) it will be changed to point to localhost. This is
|
||||
* done to match the behavior of Linux systems.
|
||||
*
|
||||
* HandleConnected() is called on the request when the connection has been
|
||||
* established.
|
||||
* HandleError() is called on the request in case of errors during the
|
||||
* connection.
|
||||
*
|
||||
* @param ip The address to which to connect to.
|
||||
* @param port The port to which to connect to.
|
||||
* @param req connection request
|
||||
*/
|
||||
void Connect(const Twine& ip, unsigned int port,
|
||||
const std::shared_ptr<TcpConnectReq>& req);
|
||||
|
||||
/**
|
||||
* Establish an IPv4 TCP connection.
|
||||
*
|
||||
* On Windows if the addr is initialized to point to an unspecified address
|
||||
* (`0.0.0.0` or `::`) it will be changed to point to localhost. This is
|
||||
* done to match the behavior of Linux systems.
|
||||
*
|
||||
* The callback is called when the connection has been established. Errors
|
||||
* are reported to the stream error handler.
|
||||
*
|
||||
* @param ip The address to which to connect to.
|
||||
* @param port The port to which to connect to.
|
||||
* @param callback Callback function to call when connection established
|
||||
*/
|
||||
void Connect(const Twine& ip, unsigned int port,
|
||||
std::function<void()> callback);
|
||||
|
||||
/**
|
||||
* Establish an IPv6 TCP connection.
|
||||
*
|
||||
* On Windows if the addr is initialized to point to an unspecified address
|
||||
* (`0.0.0.0` or `::`) it will be changed to point to localhost. This is
|
||||
* done to match the behavior of Linux systems.
|
||||
*
|
||||
* HandleConnected() is called on the request when the connection has been
|
||||
* established.
|
||||
* HandleError() is called on the request in case of errors during the
|
||||
* connection.
|
||||
*
|
||||
* @param ip The address to which to connect to.
|
||||
* @param port The port to which to connect to.
|
||||
* @param req connection request
|
||||
*/
|
||||
void Connect6(const Twine& ip, unsigned int port,
|
||||
const std::shared_ptr<TcpConnectReq>& req);
|
||||
|
||||
/**
|
||||
* Establish an IPv6 TCP connection.
|
||||
*
|
||||
* On Windows if the addr is initialized to point to an unspecified address
|
||||
* (`0.0.0.0` or `::`) it will be changed to point to localhost. This is
|
||||
* done to match the behavior of Linux systems.
|
||||
*
|
||||
* The callback is called when the connection has been established. Errors
|
||||
* are reported to the stream error handler.
|
||||
*
|
||||
* @param ip The address to which to connect to.
|
||||
* @param port The port to which to connect to.
|
||||
* @param callback Callback function to call when connection established
|
||||
*/
|
||||
void Connect6(const Twine& ip, unsigned int port,
|
||||
std::function<void()> callback);
|
||||
|
||||
private:
|
||||
Tcp* DoAccept() override;
|
||||
};
|
||||
|
||||
/**
|
||||
* TCP connection request.
|
||||
*/
|
||||
class TcpConnectReq : public ConnectReq {
|
||||
public:
|
||||
Tcp& GetStream() const {
|
||||
return *static_cast<Tcp*>(&ConnectReq::GetStream());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace uv
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_UV_TCP_H_
|
||||
139
wpiutil/src/main/native/include/wpi/uv/Timer.h
Normal file
139
wpiutil/src/main/native/include/wpi/uv/Timer.h
Normal file
@@ -0,0 +1,139 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_WPI_UV_TIMER_H_
|
||||
#define WPIUTIL_WPI_UV_TIMER_H_
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include "wpi/Signal.h"
|
||||
#include "wpi/uv/Handle.h"
|
||||
|
||||
namespace wpi {
|
||||
namespace uv {
|
||||
|
||||
class Loop;
|
||||
|
||||
/**
|
||||
* Timer handle.
|
||||
* Timer handles are used to schedule signals to be called in the future.
|
||||
*/
|
||||
class Timer final : public HandleImpl<Timer, uv_timer_t> {
|
||||
struct private_init {};
|
||||
|
||||
public:
|
||||
using Time = std::chrono::duration<uint64_t, std::milli>;
|
||||
|
||||
explicit Timer(const private_init&) {}
|
||||
~Timer() noexcept override = default;
|
||||
|
||||
/**
|
||||
* Create a timer handle.
|
||||
*
|
||||
* @param loop Loop object where this handle runs.
|
||||
*/
|
||||
static std::shared_ptr<Timer> Create(Loop& loop);
|
||||
|
||||
/**
|
||||
* Create a timer handle.
|
||||
*
|
||||
* @param loop Loop object where this handle runs.
|
||||
*/
|
||||
static std::shared_ptr<Timer> Create(const std::shared_ptr<Loop>& loop) {
|
||||
return Create(*loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a timer that calls a functor after a given time interval.
|
||||
*
|
||||
* @param loop Loop object where the timer should run.
|
||||
* @param timeout Time interval
|
||||
* @param func Functor
|
||||
*/
|
||||
static void SingleShot(Loop& loop, Time timeout, std::function<void()> func);
|
||||
|
||||
/**
|
||||
* Create a timer that calls a functor after a given time interval.
|
||||
*
|
||||
* @param loop Loop object where the timer should run.
|
||||
* @param timeout Time interval
|
||||
* @param func Functor
|
||||
*/
|
||||
static void SingleShot(const std::shared_ptr<Loop>& loop, Time timeout,
|
||||
std::function<void()> func) {
|
||||
return SingleShot(*loop, timeout, func);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the timer.
|
||||
*
|
||||
* If timeout is zero, an event is emitted on the next event loop
|
||||
* iteration. If repeat is non-zero, an event is emitted first
|
||||
* after timeout milliseconds and then repeatedly after repeat milliseconds.
|
||||
*
|
||||
* @param timeout Milliseconds before to emit an event (use
|
||||
* `std::chrono::duration<uint64_t, std::milli>`).
|
||||
* @param repeat Milliseconds between successive events (use
|
||||
* `std::chrono::duration<uint64_t, std::milli>`).
|
||||
*/
|
||||
void Start(Time timeout, Time repeat = Time{0});
|
||||
|
||||
/**
|
||||
* Stop the timer.
|
||||
*/
|
||||
void Stop() { Invoke(&uv_timer_stop, GetRaw()); }
|
||||
|
||||
/**
|
||||
* Stop the timer and restart it if it was repeating.
|
||||
*
|
||||
* Stop the timer, and if it is repeating restart it using the repeat value
|
||||
* as the timeout.
|
||||
* If the timer has never been started before it emits sigError.
|
||||
*/
|
||||
void Again() { Invoke(&uv_timer_again, GetRaw()); }
|
||||
|
||||
/**
|
||||
* Set the repeat interval value.
|
||||
*
|
||||
* The timer will be scheduled to run on the given interval and will follow
|
||||
* normal timer semantics in the case of a time-slice overrun.
|
||||
* For example, if a 50ms repeating timer first runs for 17ms, it will be
|
||||
* scheduled to run again 33ms later. If other tasks consume more than the
|
||||
* 33ms following the first timer event, then another event will be emitted
|
||||
* as soon as possible.
|
||||
*
|
||||
* If the repeat value is set from a listener bound to an event, it does
|
||||
* not immediately take effect. If the timer was non-repeating before, it
|
||||
* will have been stopped. If it was repeating, then the old repeat value
|
||||
* will have been used to schedule the next timeout.
|
||||
*
|
||||
* @param repeat Repeat interval in milliseconds (use
|
||||
* `std::chrono::duration<uint64_t, std::milli>`).
|
||||
*/
|
||||
void SetRepeat(Time repeat) { uv_timer_set_repeat(GetRaw(), repeat.count()); }
|
||||
|
||||
/**
|
||||
* Get the timer repeat value.
|
||||
* @return Timer repeat value in milliseconds (as a
|
||||
* `std::chrono::duration<uint64_t, std::milli>`).
|
||||
*/
|
||||
Time GetRepeat() const { return Time{uv_timer_get_repeat(GetRaw())}; }
|
||||
|
||||
/**
|
||||
* Signal generated when the timeout event occurs.
|
||||
*/
|
||||
sig::Signal<> timeout;
|
||||
};
|
||||
|
||||
} // namespace uv
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_UV_TIMER_H_
|
||||
88
wpiutil/src/main/native/include/wpi/uv/Tty.h
Normal file
88
wpiutil/src/main/native/include/wpi/uv/Tty.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_WPI_UV_TTY_H_
|
||||
#define WPIUTIL_WPI_UV_TTY_H_
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "wpi/uv/Stream.h"
|
||||
|
||||
namespace wpi {
|
||||
namespace uv {
|
||||
|
||||
class Loop;
|
||||
class Tty;
|
||||
|
||||
/**
|
||||
* TTY handle.
|
||||
* TTY handles represent a stream for the console.
|
||||
*/
|
||||
class Tty final : public StreamImpl<Tty, uv_tty_t> {
|
||||
struct private_init {};
|
||||
|
||||
public:
|
||||
explicit Tty(const private_init&) {}
|
||||
~Tty() noexcept override = default;
|
||||
|
||||
/**
|
||||
* Create a TTY handle.
|
||||
*
|
||||
* @param loop Loop object where this handle runs.
|
||||
* @param fd File descriptor, usually 0=stdin, 1=stdout, 2=stderr
|
||||
* @param readable Specifies if you plan on calling StartRead(). stdin is
|
||||
* readable, stdout is not.
|
||||
*/
|
||||
static std::shared_ptr<Tty> Create(Loop& loop, uv_file fd, bool readable);
|
||||
|
||||
/**
|
||||
* Create a TTY handle.
|
||||
*
|
||||
* @param loop Loop object where this handle runs.
|
||||
* @param fd File descriptor, usually 0=stdin, 1=stdout, 2=stderr
|
||||
* @param readable Specifies if you plan on calling StartRead(). stdin is
|
||||
* readable, stdout is not.
|
||||
*/
|
||||
static std::shared_ptr<Tty> Create(const std::shared_ptr<Loop>& loop,
|
||||
uv_file fd, bool readable) {
|
||||
return Create(*loop, fd, readable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the TTY using the specified terminal mode.
|
||||
*
|
||||
* @param mode terminal mode
|
||||
*/
|
||||
void SetMode(uv_tty_mode_t mode) {
|
||||
int err = uv_tty_set_mode(GetRaw(), mode);
|
||||
if (err < 0) ReportError(err);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset TTY settings to default values for the next process to take over.
|
||||
* Typically called when the program exits.
|
||||
*/
|
||||
void ResetMode() { Invoke(&uv_tty_reset_mode); }
|
||||
|
||||
/**
|
||||
* Gets the current window size.
|
||||
* @return Window size (pair of width and height).
|
||||
*/
|
||||
std::pair<int, int> GetWindowSize() {
|
||||
int width = 0, height = 0;
|
||||
Invoke(&uv_tty_get_winsize, GetRaw(), &width, &height);
|
||||
return std::make_pair(width, height);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace uv
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_UV_TTY_H_
|
||||
266
wpiutil/src/main/native/include/wpi/uv/Udp.h
Normal file
266
wpiutil/src/main/native/include/wpi/uv/Udp.h
Normal file
@@ -0,0 +1,266 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_WPI_UV_UDP_H_
|
||||
#define WPIUTIL_WPI_UV_UDP_H_
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include "wpi/ArrayRef.h"
|
||||
#include "wpi/Signal.h"
|
||||
#include "wpi/Twine.h"
|
||||
#include "wpi/uv/Handle.h"
|
||||
#include "wpi/uv/Request.h"
|
||||
|
||||
namespace wpi {
|
||||
namespace uv {
|
||||
|
||||
class Loop;
|
||||
class Udp;
|
||||
|
||||
/**
|
||||
* UDP send request.
|
||||
*/
|
||||
class UdpSendReq : public RequestImpl<UdpSendReq, uv_udp_send_t> {
|
||||
public:
|
||||
UdpSendReq();
|
||||
|
||||
Udp& GetUdp() const { return *static_cast<Udp*>(GetRaw()->handle->data); }
|
||||
|
||||
/**
|
||||
* Send completed signal. This is called even if an error occurred.
|
||||
* @param err error value
|
||||
*/
|
||||
sig::Signal<Error> complete;
|
||||
};
|
||||
|
||||
/**
|
||||
* UDP handle.
|
||||
* UDP handles encapsulate UDP communication for both clients and servers.
|
||||
*/
|
||||
class Udp final : public HandleImpl<Udp, uv_udp_t> {
|
||||
struct private_init {};
|
||||
|
||||
public:
|
||||
explicit Udp(const private_init&) {}
|
||||
~Udp() noexcept override = default;
|
||||
|
||||
/**
|
||||
* Create a UDP handle.
|
||||
*
|
||||
* @param loop Loop object where this handle runs.
|
||||
* @param flags Flags
|
||||
*/
|
||||
static std::shared_ptr<Udp> Create(Loop& loop,
|
||||
unsigned int flags = AF_UNSPEC);
|
||||
|
||||
/**
|
||||
* Create a UDP handle.
|
||||
*
|
||||
* @param loop Loop object where this handle runs.
|
||||
* @param flags Flags
|
||||
*/
|
||||
static std::shared_ptr<Udp> Create(const std::shared_ptr<Loop>& loop,
|
||||
unsigned int flags = AF_UNSPEC) {
|
||||
return Create(*loop, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open an existing file descriptor or SOCKET as a UDP handle.
|
||||
*
|
||||
* @param sock A valid socket handle (either a file descriptor or a SOCKET).
|
||||
*/
|
||||
void Open(uv_os_sock_t sock) { Invoke(&uv_udp_open, GetRaw(), sock); }
|
||||
|
||||
/**
|
||||
* Bind the handle to an IPv4 or IPv6 address and port.
|
||||
*
|
||||
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
|
||||
* @param flags Optional additional flags.
|
||||
*/
|
||||
void Bind(const sockaddr& addr, unsigned int flags = 0) {
|
||||
Invoke(&uv_udp_bind, GetRaw(), &addr, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind the handle to an IPv4 address and port.
|
||||
*
|
||||
* @param ip The address to which to bind.
|
||||
* @param port The port to which to bind.
|
||||
* @param flags Optional additional flags.
|
||||
*/
|
||||
void Bind(const Twine& ip, unsigned int port, unsigned int flags = 0);
|
||||
|
||||
/**
|
||||
* Bind the handle to an IPv6 address and port.
|
||||
*
|
||||
* @param ip The address to which to bind.
|
||||
* @param port The port to which to bind.
|
||||
* @param flags Optional additional flags.
|
||||
*/
|
||||
void Bind6(const Twine& ip, unsigned int port, unsigned int flags = 0);
|
||||
|
||||
/**
|
||||
* Get the current address to which the handle is bound.
|
||||
* @return The address (will be zeroed if an error occurred).
|
||||
*/
|
||||
sockaddr_storage GetSock();
|
||||
|
||||
/**
|
||||
* Set membership for a multicast address.
|
||||
*
|
||||
* @param multicastAddr Multicast address to set membership for
|
||||
* @param interfaceAddr Interface address
|
||||
* @param membership Should be UV_JOIN_GROUP or UV_LEAVE_GROUP
|
||||
*/
|
||||
void SetMembership(const Twine& multicastAddr, const Twine& interfaceAddr,
|
||||
uv_membership membership);
|
||||
|
||||
/**
|
||||
* Set IP multicast loop flag. Makes multicast packets loop back to local
|
||||
* sockets.
|
||||
*
|
||||
* @param enabled True for enabled, false for disabled
|
||||
*/
|
||||
void SetMulticastLoop(bool enabled) {
|
||||
Invoke(&uv_udp_set_multicast_loop, GetRaw(), enabled ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the multicast TTL.
|
||||
*
|
||||
* @param ttl Time to live (1-255)
|
||||
*/
|
||||
void SetMulticastTtl(int ttl) {
|
||||
Invoke(&uv_udp_set_multicast_ttl, GetRaw(), ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the multicast interface to send or receive data on.
|
||||
*
|
||||
* @param interfaceAddr Interface address
|
||||
*/
|
||||
void SetMulticastInterface(const Twine& interfaceAddr);
|
||||
|
||||
/**
|
||||
* Set broadcast on or off.
|
||||
*
|
||||
* @param enabled True for enabled, false for disabled
|
||||
*/
|
||||
void SetBroadcast(bool enabled) {
|
||||
Invoke(&uv_udp_set_broadcast, GetRaw(), enabled ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time to live (TTL).
|
||||
*
|
||||
* @param ttl Time to live (1-255)
|
||||
*/
|
||||
void SetTtl(int ttl) { Invoke(&uv_udp_set_ttl, GetRaw(), ttl); }
|
||||
|
||||
/**
|
||||
* Send data over the UDP socket. If the socket has not previously been bound
|
||||
* with Bind() it will be bound to 0.0.0.0 (the "all interfaces" IPv4 address)
|
||||
* and a random port number.
|
||||
*
|
||||
* Data are written in order. The lifetime of the data pointers passed in
|
||||
* the `bufs` parameter must exceed the lifetime of the send request.
|
||||
* The callback can be used to free data after the request completes.
|
||||
*
|
||||
* HandleSendComplete() will be called on the request object when the data
|
||||
* has been written. HandleSendComplete() is called even if an error occurs.
|
||||
* HandleError() will be called on the request object in case of errors.
|
||||
*
|
||||
* @param addr sockaddr_in or sockaddr_in6 with the address and port of the
|
||||
* remote peer.
|
||||
* @param bufs The buffers to be written to the stream.
|
||||
* @param req write request
|
||||
*/
|
||||
void Send(const sockaddr& addr, ArrayRef<Buffer> bufs,
|
||||
const std::shared_ptr<UdpSendReq>& req);
|
||||
|
||||
/**
|
||||
* Send data over the UDP socket. If the socket has not previously been bound
|
||||
* with Bind() it will be bound to 0.0.0.0 (the "all interfaces" IPv4 address)
|
||||
* and a random port number.
|
||||
*
|
||||
* Data are written in order. The lifetime of the data pointers passed in
|
||||
* the `bufs` parameter must exceed the lifetime of the send request.
|
||||
* The callback can be used to free data after the request completes.
|
||||
*
|
||||
* The callback will be called when the data has been sent. Errors will
|
||||
* be reported via the error signal.
|
||||
*
|
||||
* @param addr sockaddr_in or sockaddr_in6 with the address and port of the
|
||||
* remote peer.
|
||||
* @param bufs The buffers to be sent.
|
||||
* @param callback Callback function to call when the data has been sent.
|
||||
*/
|
||||
void Send(const sockaddr& addr, ArrayRef<Buffer> bufs,
|
||||
std::function<void(MutableArrayRef<Buffer>, Error)> callback);
|
||||
|
||||
/**
|
||||
* Same as Send(), but won't queue a send request if it can't be completed
|
||||
* immediately.
|
||||
*
|
||||
* @param addr sockaddr_in or sockaddr_in6 with the address and port of the
|
||||
* remote peer.
|
||||
* @param bufs The buffers to be send.
|
||||
* @return Number of bytes sent.
|
||||
*/
|
||||
int TrySend(const sockaddr& addr, ArrayRef<Buffer> bufs) {
|
||||
int val = uv_udp_try_send(GetRaw(), bufs.data(), bufs.size(), &addr);
|
||||
if (val < 0) {
|
||||
this->ReportError(val);
|
||||
return 0;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare for receiving data. If the socket has not previously been bound
|
||||
* with Bind() it is bound to 0.0.0.0 (the "all interfaces" IPv4 address) and
|
||||
* a random port number.
|
||||
*
|
||||
* A received signal will be emitted for each received data packet until
|
||||
* `StopRecv()` is called.
|
||||
*/
|
||||
void StartRecv();
|
||||
|
||||
/**
|
||||
* Stop listening for incoming datagrams.
|
||||
*/
|
||||
void StopRecv() { Invoke(&uv_udp_recv_stop, GetRaw()); }
|
||||
|
||||
/**
|
||||
* Gets the amount of queued bytes waiting to be sent.
|
||||
* @return Amount of queued bytes waiting to be sent.
|
||||
*/
|
||||
size_t GetSendQueueSize() const noexcept { return GetRaw()->send_queue_size; }
|
||||
|
||||
/**
|
||||
* Gets the amount of queued packets waiting to be sent.
|
||||
* @return Amount of queued packets waiting to be sent.
|
||||
*/
|
||||
size_t GetSendQueueCount() const noexcept {
|
||||
return GetRaw()->send_queue_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal generated for each incoming datagram. Parameters are the buffer,
|
||||
* the number of bytes received, the address of the sender, and flags.
|
||||
*/
|
||||
sig::Signal<Buffer&, size_t, const sockaddr&, unsigned> received;
|
||||
};
|
||||
|
||||
} // namespace uv
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_UV_UDP_H_
|
||||
97
wpiutil/src/main/native/include/wpi/uv/Work.h
Normal file
97
wpiutil/src/main/native/include/wpi/uv/Work.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_WPI_UV_WORK_H_
|
||||
#define WPIUTIL_WPI_UV_WORK_H_
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include "wpi/Signal.h"
|
||||
#include "wpi/uv/Request.h"
|
||||
|
||||
namespace wpi {
|
||||
namespace uv {
|
||||
|
||||
class Loop;
|
||||
|
||||
/**
|
||||
* Work request.
|
||||
* For use with `QueueWork()` function family.
|
||||
*/
|
||||
class WorkReq : public RequestImpl<WorkReq, uv_work_t> {
|
||||
public:
|
||||
WorkReq();
|
||||
|
||||
Loop& GetLoop() const { return *static_cast<Loop*>(GetRaw()->loop->data); }
|
||||
|
||||
/**
|
||||
* Function(s) that will be run on the thread pool.
|
||||
*/
|
||||
sig::Signal<> work;
|
||||
|
||||
/**
|
||||
* Function(s) that will be run on the loop thread after the work on the
|
||||
* thread pool has been completed by the work callback.
|
||||
*/
|
||||
sig::Signal<> afterWork;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes a work request which will run on the thread pool.
|
||||
*
|
||||
* @param loop Event loop
|
||||
* @param req request
|
||||
*/
|
||||
void QueueWork(Loop& loop, const std::shared_ptr<WorkReq>& req);
|
||||
|
||||
/**
|
||||
* Initializes a work request which will run on the thread pool.
|
||||
*
|
||||
* @param loop Event loop
|
||||
* @param req request
|
||||
*/
|
||||
inline void QueueWork(const std::shared_ptr<Loop>& loop,
|
||||
const std::shared_ptr<WorkReq>& req) {
|
||||
QueueWork(*loop, req);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a work request which will run on the thread pool. The work
|
||||
* callback will be run on a thread from the thread pool, and the afterWork
|
||||
* callback will be called on the loop thread after the work completes. Any
|
||||
* errors are forwarded to the loop.
|
||||
*
|
||||
* @param loop Event loop
|
||||
* @param work Work callback (called from separate thread)
|
||||
* @param afterWork After work callback (called on loop thread)
|
||||
*/
|
||||
void QueueWork(Loop& loop, std::function<void()> work,
|
||||
std::function<void()> afterWork);
|
||||
|
||||
/**
|
||||
* Initializes a work request which will run on the thread pool. The work
|
||||
* callback will be run on a thread from the thread pool, and the afterWork
|
||||
* callback will be called on the loop thread after the work completes. Any
|
||||
* errors are forwarded to the loop.
|
||||
*
|
||||
* @param loop Event loop
|
||||
* @param work Work callback (called from separate thread)
|
||||
* @param afterWork After work callback (called on loop thread)
|
||||
*/
|
||||
inline void QueueWork(const std::shared_ptr<Loop>& loop,
|
||||
std::function<void()> work,
|
||||
std::function<void()> afterWork) {
|
||||
QueueWork(*loop, work, afterWork);
|
||||
}
|
||||
|
||||
} // namespace uv
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_UV_WORK_H_
|
||||
131
wpiutil/src/main/native/include/wpi/uv/util.h
Normal file
131
wpiutil/src/main/native/include/wpi/uv/util.h
Normal file
@@ -0,0 +1,131 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_WPI_UV_UTIL_H_
|
||||
#define WPIUTIL_WPI_UV_UTIL_H_
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "wpi/Twine.h"
|
||||
|
||||
namespace wpi {
|
||||
namespace uv {
|
||||
|
||||
/**
|
||||
* Convert a binary structure containing an IPv4 address to a string.
|
||||
* @param addr Binary structure
|
||||
* @param ip Output string (any type that has `assign(char*, char*)`)
|
||||
* @param port Output port number
|
||||
* @return Error (same as `uv_ip4_name()`).
|
||||
*/
|
||||
template <typename T>
|
||||
int AddrToName(const sockaddr_in& addr, T* ip, unsigned int* port) {
|
||||
char name[128];
|
||||
int err = uv_ip4_name(&addr, name, 128);
|
||||
if (err == 0) {
|
||||
ip->assign(name, name + std::strlen(name));
|
||||
*port = ntohs(addr.sin_port);
|
||||
} else {
|
||||
ip->assign(name, name);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a binary structure containing an IPv6 address to a string.
|
||||
* @param addr Binary structure
|
||||
* @param ip Output string (any type that has `assign(char*, char*)`)
|
||||
* @param port Output port number
|
||||
* @return Error (same as `uv_ip6_name()`).
|
||||
*/
|
||||
template <typename T>
|
||||
int AddrToName(const sockaddr_in6& addr, T* ip, unsigned int* port) {
|
||||
char name[128];
|
||||
int err = uv_ip6_name(&addr, name, 128);
|
||||
if (err == 0) {
|
||||
ip->assign(name, name + std::strlen(name));
|
||||
*port = ntohs(addr.sin6_port);
|
||||
} else {
|
||||
ip->assign(name, name);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a binary IPv4 address to a string.
|
||||
* @param addr Binary address
|
||||
* @param ip Output string (any type that has `assign(char*, char*)`)
|
||||
* @return Error (same as `uv_inet_ntop()`).
|
||||
*/
|
||||
template <typename T>
|
||||
int AddrToName(const in_addr& addr, T* ip) {
|
||||
char name[128];
|
||||
int err = uv_inet_ntop(AF_INET, &addr, name, 128);
|
||||
if (err == 0)
|
||||
ip->assign(name, name + std::strlen(name));
|
||||
else
|
||||
ip->assign(name, name);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a binary IPv6 address to a string.
|
||||
* @param addr Binary address
|
||||
* @param ip Output string (any type that has `assign(char*, char*)`)
|
||||
* @return Error (same as `uv_inet_ntop()`).
|
||||
*/
|
||||
template <typename T>
|
||||
int AddrToName(const in6_addr& addr, T* ip) {
|
||||
char name[128];
|
||||
int err = uv_inet_ntop(AF_INET6, &addr, name, 128);
|
||||
if (err == 0)
|
||||
ip->assign(name, name + std::strlen(name));
|
||||
else
|
||||
ip->assign(name, name);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a string containing an IPv4 address to a binary structure.
|
||||
* @param ip IPv4 address string
|
||||
* @param port Port number
|
||||
* @param addr Output binary structure
|
||||
* @return Error (same as `uv_ip4_addr()`).
|
||||
*/
|
||||
int NameToAddr(const Twine& ip, unsigned int port, sockaddr_in* addr);
|
||||
|
||||
/**
|
||||
* Convert a string containing an IPv6 address to a binary structure.
|
||||
* @param ip IPv6 address string
|
||||
* @param port Port number
|
||||
* @param addr Output binary structure
|
||||
* @return Error (same as `uv_ip6_addr()`).
|
||||
*/
|
||||
int NameToAddr(const Twine& ip, unsigned int port, sockaddr_in6* addr);
|
||||
|
||||
/**
|
||||
* Convert a string containing an IPv4 address to binary format.
|
||||
* @param ip IPv4 address string
|
||||
* @param addr Output binary
|
||||
* @return Error (same as `uv_inet_pton()`).
|
||||
*/
|
||||
int NameToAddr(const Twine& ip, in_addr* addr);
|
||||
|
||||
/**
|
||||
* Convert a string containing an IPv6 address to binary format.
|
||||
* @param ip IPv6 address string
|
||||
* @param addr Output binary
|
||||
* @return Error (same as `uv_inet_pton()`).
|
||||
*/
|
||||
int NameToAddr(const Twine& ip, in6_addr* addr);
|
||||
|
||||
} // namespace uv
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_UV_UTIL_H_
|
||||
Reference in New Issue
Block a user