├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── debian ├── changelog ├── compat ├── control ├── docs ├── libuvpp1-dev.dirs ├── rules └── source │ └── format ├── include └── uvpp │ ├── async.hpp │ ├── callback.hpp │ ├── error.hpp │ ├── file.hpp │ ├── fsevent.hpp │ ├── fspoll.hpp │ ├── handle.hpp │ ├── idle.hpp │ ├── loop.hpp │ ├── make_unique_define.h │ ├── net.hpp │ ├── pipe.hpp │ ├── poll.hpp │ ├── request.hpp │ ├── resolver.hpp │ ├── signal.hpp │ ├── stream.hpp │ ├── tcp.hpp │ ├── timer.hpp │ ├── tty.hpp │ ├── uvpp.hpp │ └── work.hpp └── test ├── CMakeLists.txt ├── Server.cpp ├── Server.h ├── TcpConnection.cpp ├── TcpConnection.h └── main.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | 6 | # Compiled Dynamic libraries 7 | *.so 8 | *.dylib 9 | 10 | # Compiled Static libraries 11 | *.lai 12 | *.la 13 | *.a 14 | 15 | build/ 16 | .vscode/ -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8) 2 | 3 | PROJECT(libuvpp) 4 | 5 | # Test app 6 | # ADD_SUBDIRECTORY(test) 7 | 8 | INSTALL( 9 | DIRECTORY include/ 10 | DESTINATION include 11 | COMPONENT dev 12 | ) 13 | 14 | IF(UNIX OR CYGWIN) 15 | SET(SHARE_DIR share/${CMAKE_PROJECT_NAME}) 16 | ELSEIF (WIN32) 17 | SET(SHARE_DIR bin) 18 | ENDIF() 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2012 Daniel Kang. 4 | Copyright (c) 2014 Pedro Larroy 5 | Copyright (c) 2015 German Osin 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | this software and associated documentation files (the "Software"), to deal in 9 | the Software without restriction, including without limitation the rights to 10 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | the Software, and to permit persons to whom the Software is furnished to do so, 12 | subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | uvpp 2 | ==== 3 | 4 | C++11 libuv wrapper 5 | 6 | 7 | Originally Based on "node.native" C++11 libuv wrappers 8 | 9 | 10 | Example of use: 11 | 12 | https://github.com/larroy/clearskies_core/blob/master/src/cs/daemon/daemon.cpp 13 | 14 | 15 | # Documentation 16 | 17 | http://nikhilm.github.io/uvbook/index.html 18 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | libuvpp (1.7.5ubuntu2) utopic; urgency=medium 2 | 3 | * Version bump for Jenkins repair 4 | 5 | -- shilkin Mon, 02 Nov 2015 18:11:34 +0300 6 | 7 | libuvpp (1.7.5ubuntu1) utopic; urgency=medium 8 | 9 | * Dependency project libuv was updated to v1.7.5 10 | 11 | -- Autobuilder Mon, 02 Nov 2015 16:20:10 +0300 12 | 13 | libuvpp (1.7.5ubuntu0) utopic; urgency=medium 14 | 15 | * Dependency project libuv was updated to v1.7.5 16 | 17 | -- Autobuilder Tue, 20 Oct 2015 19:04:46 +0300 18 | 19 | libuvpp (1.6.1ubuntu5) utopic; urgency=medium 20 | 21 | * Version bump for Jenkins test 22 | 23 | -- Vitaly Isaev Tue, 29 Sep 2015 11:29:17 +0300 24 | 25 | libuvpp (1.6.1ubuntu4) utopic; urgency=medium 26 | 27 | * Dependency project libuv was updated to v1.7.0-32-ga39acd6 28 | 29 | -- Autobuilder Tue, 18 Aug 2015 18:28:30 +0300 30 | 31 | libuvpp (1.6.1ubuntu3) utopic; urgency=medium 32 | 33 | * Add description in debian/control 34 | 35 | -- shilkin Tue, 28 Jul 2015 18:31:49 +0300 36 | 37 | libuvpp (1.6.1ubuntu2) utopic; urgency=medium 38 | 39 | * Version bump 40 | 41 | -- Vitaly Isaev Fri, 03 Jul 2015 16:17:02 +0300 42 | 43 | libuvpp (1.6.1ubuntu0) utopic; urgency=medium 44 | 45 | [ Vitaly Isaev ] 46 | * Переход на CPack 47 | * Явное указание версии libuv 48 | * Update CMakeLists.txt 49 | * Package name and deps change 50 | 51 | [ shilkin ] 52 | * resolver added: uv_getaddrinfo_t handler 53 | * add subdirectory in root CMakeLists.txt 54 | * added DNS resolver: uv_getaddrinfo_t handler 55 | * temporary exclude test application from build 56 | * Resolver callback changed: added address family info 57 | * Fix mistyping in error message 58 | * Check res == 0, free addrinfo resource 59 | * Добавлен функционал резолвинга 60 | 61 | [ Autobuilder ] 62 | 63 | -- Autobuilder Fri, 03 Jul 2015 15:59:42 +0300 64 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 9 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: libuvpp 2 | Priority: optional 3 | Maintainer: Autobuilder 4 | Build-Depends: debhelper (>= 9), cmake, libuv1-dev (>= 1.5.0) 5 | Standards-Version: 3.9.5 6 | Section: libs 7 | Homepage: https://github.com/shilkin/uvpp.git 8 | 9 | Package: libuvpp1-dev 10 | Section: libdevel 11 | Architecture: any 12 | Depends: ${shlibs:Depends}, ${misc:Depends} 13 | Description: libuv c++ wrapper 14 | libuv c++ wrapper 15 | -------------------------------------------------------------------------------- /debian/docs: -------------------------------------------------------------------------------- 1 | README.md 2 | -------------------------------------------------------------------------------- /debian/libuvpp1-dev.dirs: -------------------------------------------------------------------------------- 1 | usr/include 2 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # See debhelper(7) (uncomment to enable) 3 | # output every command that modifies files on the build system. 4 | #DH_VERBOSE = 1 5 | 6 | # see EXAMPLES in dpkg-buildflags(1) and read /usr/share/dpkg/* 7 | DPKG_EXPORT_BUILDFLAGS = 1 8 | include /usr/share/dpkg/default.mk 9 | 10 | # see FEATURE AREAS in dpkg-buildflags(1) 11 | #export DEB_BUILD_MAINT_OPTIONS = hardening=+all 12 | 13 | # see ENVIRONMENT in dpkg-buildflags(1) 14 | # package maintainers to append CFLAGS 15 | #export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic 16 | # package maintainers to append LDFLAGS 17 | #export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed 18 | 19 | 20 | # main packaging script based on dh7 syntax 21 | %: 22 | dh $@ 23 | 24 | # override_dh_auto_configure: 25 | # cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr 26 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (native) 2 | -------------------------------------------------------------------------------- /include/uvpp/async.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "handle.hpp" 4 | #include "error.hpp" 5 | #include "loop.hpp" 6 | 7 | namespace uvpp { 8 | class Async : public handle 9 | { 10 | public: 11 | Async(loop &l, Callback callback): handle(), loop_(l.get()) 12 | { 13 | init(callback); 14 | } 15 | 16 | Async(Callback callback): handle(), loop_(uv_default_loop()) 17 | { 18 | init(callback); 19 | } 20 | 21 | error send() 22 | { 23 | return error(uv_async_send(get())); 24 | } 25 | 26 | private: 27 | 28 | error init(Callback callback) 29 | { 30 | callbacks::store(get()->data, internal::uv_cid_async, callback); 31 | 32 | return error(uv_async_init(loop_, get(), [](uv_async_t* handle) 33 | { 34 | callbacks::invoke(handle->data, internal::uv_cid_async); 35 | })); 36 | } 37 | 38 | uv_loop_t *loop_; 39 | 40 | }; 41 | } -------------------------------------------------------------------------------- /include/uvpp/callback.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "error.hpp" 7 | 8 | namespace uvpp { 9 | typedef std::function Callback; 10 | typedef std::function CallbackWithResult; 11 | 12 | namespace internal { 13 | enum uv_callback_id 14 | { 15 | uv_cid_close = 0, 16 | uv_cid_listen, 17 | uv_cid_read_start, 18 | uv_cid_write, 19 | uv_cid_shutdown, 20 | uv_cid_connect, 21 | uv_cid_connect6, 22 | uv_cid_work, 23 | uv_cid_after_work, 24 | uv_cid_timer, 25 | uv_cid_poll, 26 | uv_cid_signal, 27 | uv_cid_async, 28 | uv_cid_idle, 29 | uv_cid_fs_open, 30 | uv_cid_fs_read, 31 | uv_cid_fs_write, 32 | uv_cid_fs_close, 33 | uv_cid_fs_unlink, 34 | uv_cid_fs_stats, 35 | uv_cid_fs_fsync, 36 | uv_cid_fs_rename, 37 | uv_cid_fs_sendfile, 38 | uv_cid_fs_poll, 39 | uv_cid_fs_event, 40 | uv_cid_fs_scandir, 41 | uv_cid_resolve, 42 | uv_cid_max 43 | }; 44 | 45 | class callback_object_base 46 | { 47 | public: 48 | callback_object_base(void* data): 49 | m_data(data) 50 | { 51 | } 52 | 53 | callback_object_base(callback_object_base&&) = default; 54 | callback_object_base& operator=(callback_object_base&&) = default; 55 | callback_object_base(const callback_object_base&) = default; 56 | callback_object_base& operator=(const callback_object_base&) = default; 57 | 58 | virtual ~callback_object_base() 59 | { 60 | } 61 | 62 | void* get_data() const 63 | { 64 | return m_data; 65 | } 66 | 67 | private: 68 | void* m_data; 69 | }; 70 | 71 | template 72 | class callback_object : public callback_object_base 73 | { 74 | public: 75 | callback_object(const callback_t& callback, void* data=nullptr) 76 | : callback_object_base(data) 77 | , m_callback(callback) 78 | { 79 | } 80 | 81 | public: 82 | template 83 | typename std::result_of::type invoke(A&& ... args) 84 | { 85 | return m_callback(std::forward(args)...); 86 | } 87 | 88 | private: 89 | callback_t m_callback; 90 | }; 91 | } // end ns internals 92 | 93 | typedef std::unique_ptr callback_object_ptr; 94 | 95 | /** 96 | * Class that allows to install callback objects for each uv_callback_id value taking ownership 97 | * of the callback object which is copied. 98 | */ 99 | class callbacks 100 | { 101 | public: 102 | callbacks(): 103 | m_lut(internal::uv_cid_max) 104 | { 105 | } 106 | 107 | callbacks(int max): 108 | m_lut(max) 109 | { 110 | } 111 | 112 | template 113 | static void store(void* target, int cid, const callback_t& callback, void* data=nullptr) 114 | { 115 | reinterpret_cast(target)->m_lut[cid] = callback_object_ptr(new internal::callback_object(callback, data)); 116 | } 117 | 118 | template 119 | static void* get_data(void* target, int cid) 120 | { 121 | return reinterpret_cast(target)->m_lut[cid]->get_data(); 122 | } 123 | 124 | template 125 | static typename std::result_of::type invoke(void* target, int cid, A&& ... args) 126 | { 127 | auto x = dynamic_cast*>(reinterpret_cast(target)->m_lut[cid].get()); 128 | assert(x); 129 | return x->invoke(std::forward(args)...); 130 | } 131 | 132 | private: 133 | std::vector m_lut; 134 | }; 135 | } 136 | 137 | -------------------------------------------------------------------------------- /include/uvpp/error.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace uvpp { 9 | class exception: public std::runtime_error 10 | { 11 | public: 12 | exception(const std::string& message): 13 | std::runtime_error(message) 14 | {} 15 | }; 16 | 17 | class error 18 | { 19 | public: 20 | error(int c): 21 | m_error(c) 22 | { 23 | } 24 | 25 | public: 26 | explicit operator bool() const 27 | { 28 | return m_error != 0; 29 | } 30 | 31 | const char* str() const 32 | { 33 | return uv_strerror(m_error); 34 | } 35 | 36 | private: 37 | int m_error; 38 | }; 39 | } 40 | 41 | -------------------------------------------------------------------------------- /include/uvpp/file.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "request.hpp" 4 | #include "error.hpp" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace uvpp { 12 | 13 | struct Stats 14 | { 15 | int dev = 0; 16 | int mode = 0; 17 | int nlink = 0; 18 | int uid = 0; 19 | int gid = 0; 20 | int rdev = 0; 21 | double size = 0; 22 | double ino = 0; 23 | double atime = 0; 24 | double mtime = 0; 25 | double ctime = 0; 26 | }; 27 | 28 | #define STAT_GET_DOUBLE(name) \ 29 | static_cast(s->st_##name) 30 | 31 | #define STAT_GET_DATE(name) \ 32 | (static_cast(s->st_##name.tv_sec) * 1000) + \ 33 | (static_cast(s->st_##name.tv_nsec / 1000000)) 34 | 35 | 36 | inline Stats statsFromUV(const uv_stat_t *s) 37 | { 38 | Stats stats; 39 | stats.dev = s->st_dev; 40 | stats.mode = s->st_mode; 41 | stats.nlink = s->st_nlink; 42 | stats.uid = s->st_uid; 43 | stats.gid = s->st_gid; 44 | stats.rdev = s->st_rdev; 45 | stats.size = STAT_GET_DOUBLE(size); 46 | stats.ino = STAT_GET_DOUBLE(ino); 47 | stats.atime = STAT_GET_DATE(atim); 48 | stats.mtime = STAT_GET_DATE(mtim); 49 | stats.ctime = STAT_GET_DATE(ctim); 50 | 51 | return stats; 52 | } 53 | 54 | struct ReadOptions 55 | { 56 | int flags = O_CREAT | O_RDWR; 57 | int mode = S_IRUSR | S_IWUSR; 58 | }; 59 | 60 | struct WriteOptions 61 | { 62 | int flags = O_WRONLY | O_CREAT; 63 | int mode = S_IRUSR | S_IWUSR; 64 | }; 65 | 66 | class File : public request 67 | { 68 | public: 69 | 70 | class Entry 71 | { 72 | friend class File; 73 | public: 74 | const std::string &name() 75 | { 76 | return name_; 77 | } 78 | 79 | const std::string fullPath() 80 | { 81 | return fullPath_; 82 | } 83 | 84 | uv_dirent_type_t type() 85 | { 86 | return ent_.type; 87 | } 88 | 89 | File file() 90 | { 91 | return File(fullPath()); 92 | } 93 | 94 | const std::string typeString() 95 | { 96 | switch (ent_.type) 97 | { 98 | case UV_DIRENT_FILE: 99 | return "FILE"; 100 | break; 101 | case UV_DIRENT_DIR: 102 | return "DIR"; 103 | break; 104 | case UV_DIRENT_LINK: 105 | return "LINK"; 106 | break; 107 | case UV_DIRENT_FIFO: 108 | return "FIFO"; 109 | break; 110 | case UV_DIRENT_SOCKET: 111 | return "SOCKET"; 112 | break; 113 | case UV_DIRENT_CHAR: 114 | return "CHAR"; 115 | break; 116 | case UV_DIRENT_BLOCK: 117 | return "CHAR"; 118 | break; 119 | default: 120 | return "UNKNONW"; 121 | } 122 | } 123 | 124 | 125 | private: 126 | Entry(File *file, uv_dirent_t dir) : file_(file), ent_(dir) 127 | { 128 | name_ = std::string(ent_.name); 129 | if (ent_.type == UV_DIRENT_DIR) 130 | fullPath_ = file_->path_ + name_ + "/"; 131 | else 132 | fullPath_ = file_->path_ + name_; 133 | }; 134 | File *file_; 135 | uv_dirent_t ent_; 136 | std::string name_; 137 | std::string fullPath_; 138 | }; 139 | 140 | File(const std::string &path) : request(), loop_(uv_default_loop()), path_(path) 141 | { 142 | 143 | } 144 | 145 | File(loop &l, const std::string &path) : request(), loop_(l.get()), path_(path) 146 | { 147 | 148 | } 149 | 150 | error open(int flags, int mode, CallbackWithResult callback) 151 | { 152 | 153 | auto openCallback = [this, callback](error err, uv_file file) 154 | { 155 | if (!err) 156 | this->file_ = file; 157 | callback(err); 158 | }; 159 | 160 | callbacks::store(get()->data, internal::uv_cid_fs_open, openCallback); 161 | 162 | return error(uv_fs_open(loop_.get(), get(), path_.c_str(), flags, mode, [](uv_fs_t* req) 163 | { 164 | auto result = req->result; 165 | uv_fs_req_cleanup(req); 166 | 167 | if (result<0) 168 | { 169 | callbacks::invoke(req->data, internal::uv_cid_fs_open, error(result), result); 170 | } 171 | else 172 | { 173 | callbacks::invoke(req->data, internal::uv_cid_fs_open, error(0), result); 174 | } 175 | })); 176 | } 177 | 178 | error read(int64_t bytes, int64_t offset, std::function callback) 179 | { 180 | 181 | if (!file_) return error(UV_EIO); 182 | 183 | uv_buf_t buffer; 184 | buffer.base = new char[bytes]; 185 | buffer.len = bytes; 186 | 187 | auto readCallback = [this, callback, buffer](ssize_t result) 188 | { 189 | std::shared_ptr baseHolder(buffer.base, std::default_delete()); 190 | 191 | if (!result) 192 | { 193 | callback(nullptr, result); 194 | } 195 | else 196 | { 197 | callback(buffer.base, result); 198 | } 199 | }; 200 | 201 | callbacks::store(get()->data, internal::uv_cid_fs_read, readCallback); 202 | 203 | return error(uv_fs_read(loop_.get(), get(), file_, &buffer, 1, offset, [](uv_fs_t* req) 204 | { 205 | auto result = req->result; 206 | uv_fs_req_cleanup(req); 207 | callbacks::invoke(req->data, internal::uv_cid_fs_read, result); 208 | })); 209 | } 210 | 211 | error write(const char* buf, int len, int offset, CallbackWithResult callback) 212 | { 213 | 214 | if (!file_) return error(UV_EIO); 215 | 216 | callbacks::store(get()->data, internal::uv_cid_fs_write, callback); 217 | 218 | uv_buf_t bufs[] = { uv_buf_t { const_cast(buf), static_cast(len) } }; 219 | 220 | return error(uv_fs_write(loop_.get(), get(), file_, bufs, 1, offset, [](uv_fs_t* req) 221 | { 222 | auto result = req->result; 223 | uv_fs_req_cleanup(req); 224 | if (result < 0) 225 | { 226 | callbacks::invoke(req->data, internal::uv_cid_fs_write, error(result)); 227 | } 228 | else 229 | { 230 | callbacks::invoke(req->data, internal::uv_cid_fs_write, error(0)); 231 | } 232 | })); 233 | } 234 | 235 | error close(std::function callback) 236 | { 237 | 238 | if (!file_) return error(UV_EIO); 239 | 240 | callbacks::store(get()->data, internal::uv_cid_fs_close, callback); 241 | 242 | return error(uv_fs_close(loop_.get(), get(), file_, [](uv_fs_t* req) 243 | { 244 | uv_fs_req_cleanup(req); 245 | callbacks::invoke(req->data, internal::uv_cid_fs_close); 246 | })); 247 | } 248 | 249 | error close() 250 | { 251 | 252 | if (!file_) return error(UV_EIO); 253 | 254 | return error(uv_fs_close(loop_.get(), get(), file_, nullptr)); 255 | } 256 | 257 | error unlink(CallbackWithResult callback) 258 | { 259 | 260 | if (!file_) return error(UV_EIO); 261 | 262 | callbacks::store(get()->data, internal::uv_cid_fs_unlink, callback); 263 | 264 | return error(uv_fs_close(loop_.get(), get(), file_, [](uv_fs_t* req) 265 | { 266 | int result = req->result; 267 | uv_fs_req_cleanup(req); 268 | if (result < 0) 269 | { 270 | callbacks::invoke(req->data, internal::uv_cid_fs_unlink, error(result)); 271 | } 272 | else 273 | { 274 | callbacks::invoke(req->data, internal::uv_cid_fs_unlink, error(0)); 275 | } 276 | })); 277 | } 278 | 279 | error unlink() 280 | { 281 | 282 | if (!file_) return error(UV_EIO); 283 | 284 | return error(uv_fs_close(loop_.get(), get(), file_, nullptr)); 285 | } 286 | 287 | error stats(std::function callback) 288 | { 289 | callbacks::store(get()->data, internal::uv_cid_fs_stats, callback); 290 | 291 | return error( 292 | uv_fs_stat(loop_.get(), get(), path_.c_str(), [](uv_fs_t* req) 293 | { 294 | int result = req->result; 295 | Stats stats; 296 | 297 | if (result >= 0) 298 | { 299 | 300 | auto s = static_cast(req->ptr); 301 | 302 | stats = statsFromUV(s); 303 | } 304 | 305 | uv_fs_req_cleanup(req); 306 | 307 | if (result < 0) 308 | { 309 | callbacks::invoke(req->data, internal::uv_cid_fs_stats, error(result), stats); 310 | } 311 | else 312 | { 313 | callbacks::invoke(req->data, internal::uv_cid_fs_stats, error(0), stats); 314 | } 315 | 316 | }) 317 | ); 318 | } 319 | 320 | Stats stats() 321 | { 322 | int err = uv_fs_stat(loop_.get(), get(), path_.c_str(), nullptr); 323 | 324 | if (err>=0) 325 | { 326 | Stats stats; 327 | auto s = static_cast(get()->ptr); 328 | stats = statsFromUV(s); 329 | uv_fs_req_cleanup(get()); 330 | return stats; 331 | } 332 | else 333 | { 334 | uv_fs_req_cleanup(get()); 335 | throw exception(error(err).str()); 336 | } 337 | } 338 | 339 | error fsync(CallbackWithResult callback) 340 | { 341 | 342 | if (!file_) return error(UV_EIO); 343 | 344 | callbacks::store(get()->data, internal::uv_cid_fs_fsync, callback); 345 | 346 | return error( 347 | uv_fs_fsync(loop_.get(), get(), file_, [](uv_fs_t* req) 348 | { 349 | int result = req->result; 350 | 351 | uv_fs_req_cleanup(req); 352 | 353 | if (result < 0) 354 | { 355 | callbacks::invoke(req->data, internal::uv_cid_fs_fsync, error(result)); 356 | } 357 | else 358 | { 359 | callbacks::invoke(req->data, internal::uv_cid_fs_fsync, error(0)); 360 | } 361 | }) 362 | ); 363 | } 364 | 365 | error rename(const std::string &newName, CallbackWithResult callback) 366 | { 367 | 368 | callbacks::store(get()->data, internal::uv_cid_fs_rename, callback); 369 | 370 | return error( 371 | uv_fs_rename(loop_.get(), get(), path_.c_str(), newName.c_str(), [](uv_fs_t* req) 372 | { 373 | int result = req->result; 374 | 375 | uv_fs_req_cleanup(req); 376 | 377 | if (result < 0) 378 | { 379 | callbacks::invoke(req->data, internal::uv_cid_fs_rename, error(result)); 380 | } 381 | else 382 | { 383 | callbacks::invoke(req->data, internal::uv_cid_fs_rename, error(0)); 384 | } 385 | }) 386 | ); 387 | } 388 | 389 | error sendfile(const File &out, int64_t in_offset, size_t length, CallbackWithResult callback) 390 | { 391 | 392 | if (!file_) return error(UV_EIO); 393 | if (!out.file_) return error(UV_EIO); 394 | 395 | callbacks::store(get()->data, internal::uv_cid_fs_sendfile, callback); 396 | 397 | return error( 398 | uv_fs_sendfile(loop_.get(), get(), file_, out.file_, in_offset, length, [](uv_fs_t* req) 399 | { 400 | int result = req->result; 401 | 402 | uv_fs_req_cleanup(req); 403 | 404 | if (result < 0) 405 | { 406 | callbacks::invoke(req->data, internal::uv_cid_fs_sendfile, error(result)); 407 | } 408 | else 409 | { 410 | callbacks::invoke(req->data, internal::uv_cid_fs_sendfile, error(0)); 411 | } 412 | }) 413 | ); 414 | } 415 | 416 | error scandir(std::function files)> callback) 417 | { 418 | 419 | auto scanDirCallback = [this, callback](int result) 420 | { 421 | std::list files; 422 | if (result < 0) 423 | { 424 | uv_fs_req_cleanup(this->get()); 425 | callback(error(result), files); 426 | } 427 | else 428 | { 429 | uv_dirent_t ent; 430 | for (int i=0; iget(), &ent)); 433 | if (!err) 434 | { 435 | files.push_back(Entry(this,ent)); 436 | } 437 | } 438 | uv_fs_req_cleanup(this->get()); 439 | callback(error(0), files); 440 | } 441 | }; 442 | 443 | callbacks::store(get()->data, internal::uv_cid_fs_scandir, scanDirCallback); 444 | 445 | return error( 446 | uv_fs_scandir(loop_.get(), get(), path_.c_str(), 0, [](uv_fs_t* req) 447 | { 448 | callbacks::invoke(req->data, internal::uv_cid_fs_scandir, req->result); 449 | }) 450 | ); 451 | } 452 | 453 | std::list scandir() 454 | { 455 | int err = uv_fs_scandir(loop_.get(), get(), path_.c_str(), 0, nullptr); 456 | if (err >= 0) 457 | { 458 | std::list files; 459 | uv_dirent_t ent; 460 | int r; 461 | while ( (r = uv_fs_scandir_next(get(), &ent))!= UV_EOF ) 462 | { 463 | files.push_back(Entry(this, ent)); 464 | } 465 | uv_fs_req_cleanup(get()); 466 | return files; 467 | } 468 | else 469 | { 470 | throw exception(error(err).str()); 471 | } 472 | } 473 | 474 | 475 | 476 | private: 477 | const std::string path_; 478 | loop loop_; 479 | uv_file file_=0; 480 | }; 481 | 482 | 483 | } -------------------------------------------------------------------------------- /include/uvpp/fsevent.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "handle.hpp" 4 | #include "error.hpp" 5 | #include "file.hpp" 6 | #include 7 | 8 | namespace uvpp { 9 | 10 | inline bool fileExists(const char *path) 11 | { 12 | struct stat buffer; 13 | return (stat (path, &buffer) == 0); 14 | } 15 | 16 | class FsEvent : public handle 17 | { 18 | public: 19 | 20 | enum Type 21 | { 22 | NONE, 23 | CHANGED, 24 | CREATED, 25 | DELETED 26 | }; 27 | 28 | FsEvent(): 29 | handle() 30 | { 31 | uv_fs_event_init(uv_default_loop(), get()); 32 | } 33 | 34 | FsEvent(loop& l): 35 | handle() 36 | { 37 | uv_fs_event_init(l.get(), get()); 38 | } 39 | 40 | ~FsEvent() 41 | { 42 | if (started_) stop(); 43 | } 44 | 45 | error start(const std::string &path, unsigned int flags, std::function callback) 46 | { 47 | 48 | auto fsEventCallback = [this,path,callback](const char* filename, int events, int status) 49 | { 50 | if (status<0) 51 | callback(error(status), std::string(filename), status, NONE); 52 | else 53 | { 54 | 55 | if (events & UV_CHANGE) 56 | { 57 | callback(error(status), std::string(filename), status, CHANGED); 58 | } 59 | 60 | if (events & UV_RENAME) 61 | { 62 | std::string fullPath = path; 63 | fullPath += filename; 64 | 65 | if (fileExists(fullPath.c_str())) 66 | { 67 | callback(error(status), std::string(filename), status, CREATED); 68 | } 69 | else 70 | { 71 | callback(error(status), std::string(filename), status, DELETED); 72 | } 73 | } 74 | } 75 | }; 76 | 77 | callbacks::store(get()->data, internal::uv_cid_fs_event, fsEventCallback); 78 | 79 | started_ = true; 80 | return error(uv_fs_event_start(get(), 81 | [](uv_fs_event_t* handle, const char* filename, int events, int status) 82 | { 83 | callbacks::invoke(handle->data, internal::uv_cid_fs_event, filename, events,status); 84 | }, path.c_str(), flags 85 | )); 86 | } 87 | 88 | error stop() 89 | { 90 | return error(uv_fs_event_stop(get())); 91 | } 92 | 93 | private: 94 | bool started_ = false; 95 | 96 | }; 97 | } -------------------------------------------------------------------------------- /include/uvpp/fspoll.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "handle.hpp" 4 | #include "error.hpp" 5 | #include "file.hpp" 6 | 7 | namespace uvpp { 8 | 9 | class FsPoll : public handle 10 | { 11 | public: 12 | FsPoll(): 13 | handle() 14 | { 15 | uv_fs_poll_init(uv_default_loop(), get()); 16 | } 17 | 18 | FsPoll(loop& l): 19 | handle() 20 | { 21 | uv_fs_poll_init(l.get(), get()); 22 | } 23 | 24 | error start(const std::string &path, unsigned int interval, std::function callback) 25 | { 26 | 27 | callbacks::store(get()->data, internal::uv_cid_fs_poll, callback); 28 | 29 | return error(uv_fs_poll_start(get(), 30 | [](uv_fs_poll_t* handle, int status, const uv_stat_t* prev, const uv_stat_t* curr) 31 | { 32 | Stats back,current; 33 | if (status<0) 34 | callbacks::invoke(handle->data, internal::uv_cid_fs_poll, error(status), status, back, current); 35 | else 36 | { 37 | back = statsFromUV(prev); 38 | current = statsFromUV(curr); 39 | callbacks::invoke(handle->data, internal::uv_cid_fs_poll, error(0), status, back, current); 40 | } 41 | }, path.c_str(), interval 42 | )); 43 | } 44 | 45 | error stop() 46 | { 47 | return error(uv_fs_poll_stop(get())); 48 | } 49 | }; 50 | } -------------------------------------------------------------------------------- /include/uvpp/handle.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "callback.hpp" 4 | #include "error.hpp" 5 | 6 | namespace uvpp { 7 | namespace { 8 | template 9 | inline void free_handle(HANDLE_T** h) 10 | { 11 | if (*h == nullptr) 12 | return; 13 | 14 | if ((*h)->data) 15 | { 16 | delete reinterpret_cast((*h)->data); 17 | (*h)->data = nullptr; 18 | } 19 | 20 | switch ((*h)->type) 21 | { 22 | case UV_TCP: 23 | delete reinterpret_cast(*h); 24 | break; 25 | 26 | case UV_UDP: 27 | delete reinterpret_cast(*h); 28 | break; 29 | 30 | case UV_NAMED_PIPE: 31 | delete reinterpret_cast(*h); 32 | break; 33 | 34 | case UV_TTY: 35 | delete reinterpret_cast(*h); 36 | break; 37 | 38 | case UV_TIMER: 39 | delete reinterpret_cast(*h); 40 | break; 41 | 42 | case UV_SIGNAL: 43 | delete reinterpret_cast(*h); 44 | break; 45 | 46 | case UV_POLL: 47 | delete reinterpret_cast(*h); 48 | break; 49 | 50 | case UV_ASYNC: 51 | delete reinterpret_cast(*h); 52 | break; 53 | 54 | case UV_IDLE: 55 | delete reinterpret_cast(*h); 56 | break; 57 | 58 | case UV_FS_EVENT: 59 | delete reinterpret_cast(*h); 60 | break; 61 | 62 | default: 63 | assert(0); 64 | throw std::runtime_error("free_handle can't handle this type"); 65 | break; 66 | *h = nullptr; 67 | } 68 | } 69 | 70 | } 71 | 72 | /** 73 | * Wraps a libuv's uv_handle_t, or derived such as uv_stream_t, uv_tcp_t etc. 74 | * 75 | * Resources are released on the close call as mandated by libuv and NOT on the dtor 76 | */ 77 | template 78 | class handle 79 | { 80 | protected: 81 | handle(): 82 | m_uv_handle(new HANDLE_T()) 83 | , m_will_close(false) 84 | { 85 | assert(m_uv_handle); 86 | m_uv_handle->data = new callbacks(); 87 | assert(m_uv_handle->data); 88 | } 89 | 90 | handle(handle&& other): 91 | m_uv_handle(other.m_uv_handle) 92 | , m_will_close(other.m_will_close) 93 | { 94 | other.m_uv_handle = nullptr; 95 | other.m_will_close = false; 96 | } 97 | 98 | handle& operator=(handle&& other) 99 | { 100 | if (this == &other) 101 | return *this; 102 | m_uv_handle = other.m_uv_handle; 103 | m_will_close = other.m_will_close; 104 | other.m_uv_handle = nullptr; 105 | other.m_will_close = false; 106 | return *this; 107 | } 108 | 109 | virtual ~handle() 110 | { 111 | if (! m_will_close) 112 | free_handle(&m_uv_handle); 113 | } 114 | 115 | handle(const handle&) = delete; 116 | handle& operator=(const handle&) = delete; 117 | 118 | public: 119 | template 120 | T* get() 121 | { 122 | return reinterpret_cast(m_uv_handle); 123 | } 124 | 125 | template 126 | const T* get() const 127 | { 128 | return reinterpret_cast(m_uv_handle); 129 | } 130 | 131 | bool is_active() const 132 | { 133 | return uv_is_active(reinterpret_cast(m_uv_handle)) != 0; 134 | } 135 | 136 | void close(Callback callback = [] {}) 137 | { 138 | if (uv_is_closing(get())) 139 | { 140 | return; // prevent assertion on double close 141 | } 142 | 143 | callbacks::store(get()->data, internal::uv_cid_close, callback); 144 | m_will_close = true; 145 | uv_close(get(), 146 | [](uv_handle_t* h) 147 | { 148 | callbacks::invoke(h->data, internal::uv_cid_close); 149 | free_handle(&h); 150 | }); 151 | } 152 | 153 | protected: 154 | HANDLE_T* m_uv_handle; 155 | bool m_will_close; 156 | }; 157 | 158 | } 159 | 160 | -------------------------------------------------------------------------------- /include/uvpp/idle.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "request.hpp" 4 | #include "error.hpp" 5 | #include "loop.hpp" 6 | 7 | namespace uvpp { 8 | class Idle : public handle 9 | { 10 | public: 11 | Idle(Callback callback): 12 | handle(), loop_(uv_default_loop()) 13 | { 14 | init(loop_, callback); 15 | } 16 | 17 | Idle(loop& l, Callback callback): 18 | handle(), loop_(l.get()) 19 | { 20 | init(loop_, callback); 21 | } 22 | 23 | error start() 24 | { 25 | return error(uv_idle_start(get(), [](uv_idle_t* req) 26 | { 27 | callbacks::invoke(req->data, internal::uv_cid_idle); 28 | })); 29 | 30 | } 31 | 32 | error stop() 33 | { 34 | return error(uv_idle_stop(get())); 35 | } 36 | 37 | private: 38 | 39 | void init(uv_loop_t *loop, Callback callback) 40 | { 41 | callbacks::store(get()->data, internal::uv_cid_idle, callback); 42 | uv_idle_init(loop, get()); 43 | } 44 | 45 | uv_loop_t *loop_; 46 | }; 47 | } 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /include/uvpp/loop.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "error.hpp" 4 | 5 | #include 6 | #include 7 | 8 | namespace uvpp { 9 | /** 10 | * Class that represents the uv_loop instance. 11 | */ 12 | class loop 13 | { 14 | public: 15 | /** 16 | * Default constructor 17 | * @param use_default indicates whether to use default loop or create a new loop. 18 | */ 19 | loop(bool use_default=false) 20 | : default_loop(use_default) 21 | , m_uv_loop(use_default ? uv_default_loop() : new uv_loop_t 22 | , [this](uv_loop_t *loop) 23 | { 24 | destroy(loop); 25 | }) 26 | { 27 | if (!default_loop && uv_loop_init(m_uv_loop.get())) 28 | { 29 | throw std::runtime_error("uv_loop_init error"); 30 | } 31 | } 32 | 33 | /** 34 | * Destructor 35 | */ 36 | ~loop() 37 | { 38 | if (m_uv_loop.get()) 39 | { 40 | // no matter default loop or not: http://nikhilm.github.io/uvbook/basics.html#event-loops 41 | uv_loop_close(m_uv_loop.get()); 42 | } 43 | } 44 | 45 | loop(const loop&) = delete; 46 | loop& operator=(const loop&) = delete; 47 | loop(loop&& other) 48 | : m_uv_loop(std::forward(other.m_uv_loop)) 49 | { 50 | 51 | } 52 | 53 | loop& operator=(loop&& other) 54 | { 55 | if (this != &other) 56 | { 57 | m_uv_loop = std::forward(other.m_uv_loop); 58 | } 59 | return *this; 60 | } 61 | 62 | /** 63 | * Returns internal handle for libuv functions. 64 | */ 65 | uv_loop_t* get() 66 | { 67 | return m_uv_loop.get(); 68 | } 69 | 70 | /** 71 | * Starts the loop. 72 | */ 73 | bool run() 74 | { 75 | return uv_run(m_uv_loop.get(), UV_RUN_DEFAULT) == 0; 76 | } 77 | 78 | /** 79 | * Polls for new events once. Blocks if there are no pending events. 80 | */ 81 | bool run_once() 82 | { 83 | return uv_run(m_uv_loop.get(), UV_RUN_ONCE) == 0; 84 | } 85 | 86 | /** 87 | * Polls for new events once without blocking. 88 | */ 89 | bool run_nowait() 90 | { 91 | return uv_run(m_uv_loop.get(), UV_RUN_NOWAIT) == 0; 92 | } 93 | 94 | /** 95 | * ... 96 | * Internally, this function just calls uv_update_time() function. 97 | */ 98 | void update_time() 99 | { 100 | uv_update_time(m_uv_loop.get()); 101 | } 102 | 103 | /** 104 | * ... 105 | * Internally, this function just calls uv_now() function. 106 | */ 107 | int64_t now() 108 | { 109 | return uv_now(m_uv_loop.get()); 110 | } 111 | 112 | /** 113 | * Stops the loop 114 | */ 115 | void stop() 116 | { 117 | uv_stop(m_uv_loop.get()); 118 | } 119 | 120 | private: 121 | 122 | // Custom deleter 123 | typedef std::function Deleter; 124 | void destroy(uv_loop_t *loop) const 125 | { 126 | if (!default_loop) 127 | { 128 | delete loop; 129 | } 130 | } 131 | 132 | bool default_loop; 133 | std::unique_ptr m_uv_loop; 134 | }; 135 | 136 | /** 137 | * Starts the default loop. 138 | */ 139 | inline int run() 140 | { 141 | return uv_run(uv_default_loop(), UV_RUN_DEFAULT); 142 | } 143 | 144 | /** 145 | * Polls for new events for the default loop once. 146 | * Blocks only if there are no pending events. 147 | */ 148 | inline int run_once() 149 | { 150 | return uv_run(uv_default_loop(), UV_RUN_ONCE); 151 | } 152 | 153 | /** 154 | * Polls for new events for the default loop once. 155 | * Non-blocking. 156 | */ 157 | inline int run_nowait() 158 | { 159 | return uv_run(uv_default_loop(), UV_RUN_NOWAIT); 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /include/uvpp/make_unique_define.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if (__cplusplus >= 201402L) || (defined(_MSC_VER) && _MSC_VER >= 1800) 4 | #else 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace std { 11 | template struct _Unique_if { 12 | typedef unique_ptr _Single_object; 13 | }; 14 | 15 | template struct _Unique_if { 16 | typedef unique_ptr _Unknown_bound; 17 | }; 18 | 19 | template struct _Unique_if { 20 | typedef void _Known_bound; 21 | }; 22 | 23 | template 24 | typename _Unique_if::_Single_object 25 | make_unique(Args&&... args) { 26 | return unique_ptr(new T(std::forward(args)...)); 27 | } 28 | 29 | template 30 | typename _Unique_if::_Unknown_bound 31 | make_unique(size_t n) { 32 | typedef typename remove_extent::type U; 33 | return unique_ptr(new U[n]()); 34 | } 35 | 36 | template 37 | typename _Unique_if::_Known_bound 38 | make_unique(Args&&...) = delete; 39 | } 40 | #endif 41 | 42 | -------------------------------------------------------------------------------- /include/uvpp/net.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | //#include "../src/cs/config.hpp" 6 | #include "make_unique_define.h" 7 | 8 | 9 | /// Formatted string, allows to use stream operators and returns a std::string with the resulting format 10 | #define fs(x) \ 11 | (static_cast(((*std::make_unique().get()) << x)).str ()) 12 | 13 | namespace uvpp { 14 | typedef sockaddr_in ip4_addr; 15 | typedef sockaddr_in6 ip6_addr; 16 | 17 | inline ip4_addr to_ip4_addr(const std::string& ip, int port) 18 | { 19 | ip4_addr result; 20 | int res = 0; 21 | if ((res = uv_ip4_addr(ip.c_str(), port, &result)) != 0) 22 | throw exception(fs("uv_ip4_addr error: " << error(res).str())); 23 | return result; 24 | } 25 | 26 | inline ip6_addr to_ip6_addr(const std::string& ip, int port) 27 | { 28 | ip6_addr result; 29 | int res = 0; 30 | if ((res = uv_ip6_addr(ip.c_str(), port, &result)) != 0) 31 | throw exception(fs("uv_ip6_addr error: " << error(res).str())); 32 | return result; 33 | } 34 | 35 | inline bool from_ip4_addr(ip4_addr* src, std::string& ip, int& port) 36 | { 37 | char dest[16]; 38 | if (uv_ip4_name(src, dest, 16) == 0) 39 | { 40 | ip = dest; 41 | port = static_cast(ntohs(src->sin_port)); 42 | return true; 43 | } 44 | return false; 45 | } 46 | 47 | inline bool from_ip6_addr(ip6_addr* src, std::string& ip, int& port) 48 | { 49 | char dest[46]; 50 | if (uv_ip6_name(src, dest, 46) == 0) 51 | { 52 | ip = dest; 53 | port = static_cast(ntohs(src->sin6_port)); 54 | return true; 55 | } 56 | return false; 57 | } 58 | } 59 | #undef fs 60 | -------------------------------------------------------------------------------- /include/uvpp/pipe.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "stream.hpp" 4 | #include "loop.hpp" 5 | 6 | namespace uvpp { 7 | class Pipe : public stream 8 | { 9 | public: 10 | Pipe(const bool fd_pass = false): 11 | stream() 12 | { 13 | uv_pipe_init(uv_default_loop(), get(), fd_pass ? 1 : 0); 14 | } 15 | 16 | Pipe(loop& l, const bool fd_pass = false): 17 | stream() 18 | { 19 | uv_pipe_init(l.get(), get(), fd_pass ? 1 : 0); 20 | } 21 | 22 | bool bind(const std::string& name) 23 | { 24 | return uv_pipe_bind(get(), name.c_str()) == 0; 25 | } 26 | 27 | void connect(const std::string& name, CallbackWithResult callback) 28 | { 29 | callbacks::store(get()->data, internal::uv_cid_connect, callback); 30 | uv_pipe_connect(new uv_connect_t, get(), name.c_str(), [](uv_connect_t* req, int status) 31 | { 32 | std::unique_ptr reqHolder(req); 33 | callbacks::invoke(req->handle->data, internal::uv_cid_connect, error(status)); 34 | }); 35 | } 36 | 37 | bool getsockname(std::string& name) 38 | { 39 | std::vector buf(100); 40 | size_t buf_size = buf.size(); 41 | int r = uv_pipe_getsockname(get(), buf.data(), &buf_size); 42 | if (r == UV_ENOBUFS) { 43 | buf.resize(buf_size); 44 | r = uv_pipe_getsockname(get(), buf.data(), &buf_size); 45 | } 46 | 47 | if (r == 0) 48 | { 49 | name = std::string(buf.data(), buf_size); 50 | return true; 51 | } 52 | return false; 53 | } 54 | 55 | bool getpeername(std::string& name) 56 | { 57 | std::vector buf(100); 58 | size_t buf_size = buf.size(); 59 | int r = uv_pipe_getpeername(get(), buf.data(), &buf_size); 60 | if (r == UV_ENOBUFS) { 61 | buf.resize(buf_size); 62 | r = uv_pipe_getpeername(get(), buf.data(), &buf_size); 63 | } 64 | 65 | if (r == 0) 66 | { 67 | name = std::string(buf.data(), buf_size); 68 | return true; 69 | } 70 | return false; 71 | } 72 | 73 | int pending_count() 74 | { 75 | return uv_pipe_pending_count(get()); 76 | } 77 | 78 | uv_handle_type pending_type() 79 | { 80 | return uv_pipe_pending_type(get()); 81 | } 82 | }; 83 | } 84 | -------------------------------------------------------------------------------- /include/uvpp/poll.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "handle.hpp" 4 | #include "error.hpp" 5 | 6 | namespace uvpp { 7 | 8 | class Poll : public handle 9 | { 10 | public: 11 | Poll(int fd): 12 | handle() 13 | { 14 | uv_poll_init(uv_default_loop(), get(),fd); 15 | } 16 | 17 | Poll(loop& l, int fd): 18 | handle() 19 | { 20 | uv_poll_init(l.get(), get(), fd); 21 | } 22 | 23 | error start( int events, std::function callback) 24 | { 25 | callbacks::store(get()->data, internal::uv_cid_poll, callback); 26 | return error(uv_poll_start(get(), events, 27 | [](uv_poll_t* handle, int status, int events) 28 | { 29 | callbacks::invoke(handle->data, internal::uv_cid_poll, status, events); 30 | } 31 | )); 32 | } 33 | 34 | error stop() 35 | { 36 | return error(uv_poll_stop(get())); 37 | } 38 | }; 39 | } -------------------------------------------------------------------------------- /include/uvpp/request.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "callback.hpp" 4 | #include "error.hpp" 5 | 6 | namespace uvpp { 7 | namespace { 8 | template 9 | inline void free_request(REQUEST_T** h) 10 | { 11 | if (*h == nullptr) 12 | return; 13 | 14 | if ((*h)->data) 15 | { 16 | delete reinterpret_cast((*h)->data); 17 | (*h)->data = nullptr; 18 | } 19 | 20 | switch ((*h)->type) 21 | { 22 | 23 | case UV_WORK: 24 | delete reinterpret_cast(*h); 25 | break; 26 | 27 | case UV_FS: 28 | delete reinterpret_cast(*h); 29 | break; 30 | 31 | case UV_GETADDRINFO: 32 | delete reinterpret_cast(*h); 33 | break; 34 | 35 | default: 36 | assert(0); 37 | throw std::runtime_error("free_request can't handle this type"); 38 | break; 39 | *h = nullptr; 40 | } 41 | } 42 | 43 | } 44 | 45 | /** 46 | * Wraps a libuv's uv_handle_t, or derived such as uv_stream_t, uv_tcp_t etc. 47 | * 48 | * Resources are released on the close call as mandated by libuv and NOT on the dtor 49 | */ 50 | template 51 | class request 52 | { 53 | protected: 54 | request(): 55 | m_uv_request(new REQUEST_T()) 56 | , m_will_close(false) 57 | { 58 | assert(m_uv_request); 59 | m_uv_request->data = new callbacks(); 60 | assert(m_uv_request->data); 61 | } 62 | 63 | request(request&& other): 64 | m_uv_request(other.m_uv_request) 65 | , m_will_close(other.m_will_close) 66 | { 67 | other.m_uv_request = nullptr; 68 | other.m_will_close = false; 69 | } 70 | 71 | request& operator=(request&& other) 72 | { 73 | if (this == &other) 74 | return *this; 75 | m_uv_request = other.m_uv_request; 76 | m_will_close = other.m_will_close; 77 | other.m_uv_request = nullptr; 78 | other.m_will_close = false; 79 | return *this; 80 | } 81 | 82 | ~request() 83 | { 84 | if (! m_will_close) 85 | free_request(&m_uv_request); 86 | } 87 | 88 | request(const request&) = delete; 89 | request& operator=(const request&) = delete; 90 | 91 | public: 92 | template 93 | T* get() 94 | { 95 | return reinterpret_cast(m_uv_request); 96 | } 97 | 98 | template 99 | const T* get() const 100 | { 101 | return reinterpret_cast(m_uv_request); 102 | } 103 | 104 | int cancel() 105 | { 106 | return uv_cancel((uv_req_t*)get()); 107 | } 108 | 109 | protected: 110 | REQUEST_T* m_uv_request; 111 | bool m_will_close; 112 | }; 113 | 114 | } -------------------------------------------------------------------------------- /include/uvpp/resolver.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "request.hpp" 4 | #include "error.hpp" 5 | #include "loop.hpp" 6 | 7 | namespace uvpp { 8 | 9 | class Resolver : public request 10 | { 11 | public: 12 | typedef std::function Callback; // status, is_ip4, addr 13 | Resolver(loop& l) : request(), loop_(l.get()) 14 | { 15 | 16 | } 17 | bool resolve(const std::string& addr, Callback callback) 18 | { 19 | callbacks::store(get()->data, internal::uv_cid_resolve, callback); 20 | return (uv_getaddrinfo(loop_ 21 | , get() 22 | , [](uv_getaddrinfo_t* req, int status, struct addrinfo* res) 23 | { 24 | std::shared_ptr resHolder(res, [](addrinfo* res) 25 | { 26 | uv_freeaddrinfo(res); 27 | }); 28 | char addr[128] = {'\0'}; // address text buffer 29 | if (status == 0) 30 | { 31 | if (res->ai_family == AF_INET6) 32 | { 33 | uv_ip6_name(reinterpret_cast(res->ai_addr), addr, res->ai_addrlen); 34 | } else if (res->ai_family == AF_INET) 35 | { 36 | uv_ip4_name(reinterpret_cast(res->ai_addr), addr, res->ai_addrlen); 37 | } else 38 | { 39 | callbacks::invoke(req->data, internal::uv_cid_resolve 40 | , error(EAI_ADDRFAMILY) 41 | , false 42 | , addr); 43 | return; 44 | } 45 | } 46 | bool ip4 = res ? res->ai_family == AF_INET : false; 47 | callbacks::invoke(req->data, internal::uv_cid_resolve, error(status), ip4, addr); 48 | } 49 | , addr.c_str(), 0, 0) == 0); 50 | } 51 | private: 52 | uv_loop_t *loop_; 53 | }; 54 | 55 | } // uvpp 56 | 57 | -------------------------------------------------------------------------------- /include/uvpp/signal.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "handle.hpp" 4 | #include "error.hpp" 5 | 6 | namespace uvpp { 7 | 8 | class Signal : public handle 9 | { 10 | public: 11 | 12 | typedef std::function SignalHandler; 13 | 14 | Signal(): 15 | handle() 16 | { 17 | uv_signal_init(uv_default_loop(), get()); 18 | } 19 | 20 | Signal(loop& l): 21 | handle() 22 | { 23 | uv_signal_init(l.get(), get()); 24 | } 25 | 26 | 27 | error start(int signum, SignalHandler callback) 28 | { 29 | callbacks::store(get()->data, internal::uv_cid_signal, callback); 30 | return error(uv_signal_start(get(), 31 | [](uv_signal_t* handle, int signum) 32 | { 33 | callbacks::invoke(handle->data, internal::uv_cid_signal, signum); 34 | }, 35 | signum)); 36 | } 37 | 38 | error stop() 39 | { 40 | return error(uv_signal_stop(get())); 41 | } 42 | }; 43 | } 44 | -------------------------------------------------------------------------------- /include/uvpp/stream.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "handle.hpp" 4 | #include "error.hpp" 5 | #include 6 | #include 7 | 8 | namespace uvpp { 9 | template 10 | class stream : public handle 11 | { 12 | protected: 13 | stream(): 14 | handle() 15 | {} 16 | 17 | public: 18 | bool listen(CallbackWithResult callback, int backlog=128) 19 | { 20 | callbacks::store(handle::get()->data, uvpp::internal::uv_cid_listen, callback); 21 | return uv_listen(handle::template get(), backlog, [](uv_stream_t* s, int status) 22 | { 23 | callbacks::invoke(s->data, uvpp::internal::uv_cid_listen, error(status)); 24 | }) == 0; 25 | } 26 | 27 | bool accept(stream& client) 28 | { 29 | return uv_accept(handle::template get(), client.handle::template get()) == 0; 30 | } 31 | 32 | bool read_start(std::function callback) 33 | { 34 | return read_start<0>(callback); 35 | } 36 | 37 | template 38 | bool read_start(std::function callback) 39 | { 40 | callbacks::store(handle::get()->data, uvpp::internal::uv_cid_read_start, callback); 41 | 42 | return uv_read_start(handle::template get(), 43 | [](uv_handle_t*, size_t suggested_size, uv_buf_t* buf) 44 | { 45 | assert(buf); 46 | auto size = std::max(suggested_size, max_alloc_size); 47 | buf->base = new char[size]; 48 | buf->len = size; 49 | }, 50 | [](uv_stream_t* s, ssize_t nread, const uv_buf_t* buf) 51 | { 52 | // handle callback throwing exception: hold data in unique_ptr 53 | std::shared_ptr baseHolder(buf->base, std::default_delete()); 54 | 55 | if (nread < 0) 56 | { 57 | // FIXME error has nread set to -errno, handle failure 58 | // assert(nread == UV_EOF); ??? 59 | callbacks::invoke(s->data, uvpp::internal::uv_cid_read_start, nullptr, nread); 60 | } 61 | else if (nread >= 0) 62 | { 63 | callbacks::invoke(s->data, uvpp::internal::uv_cid_read_start, buf->base, nread); 64 | } 65 | }) == 0; 66 | } 67 | 68 | bool read_stop() 69 | { 70 | return uv_read_stop(handle::template get()) == 0; 71 | } 72 | 73 | bool write(const char* buf, int len, CallbackWithResult callback) 74 | { 75 | uv_buf_t bufs[] = { uv_buf_t { const_cast(buf), static_cast(len) } }; 76 | callbacks::store(handle::get()->data, uvpp::internal::uv_cid_write, callback); 77 | return uv_write(new uv_write_t, handle::template get(), bufs, 1, [](uv_write_t* req, int status) 78 | { 79 | std::unique_ptr reqHolder(req); 80 | callbacks::invoke(req->handle->data, uvpp::internal::uv_cid_write, error(status)); 81 | }) == 0; 82 | } 83 | 84 | bool write(const std::string& buf, CallbackWithResult callback) 85 | { 86 | uv_buf_t bufs[] = { uv_buf_t { const_cast(buf.c_str()), buf.length()} }; 87 | callbacks::store(handle::get()->data, uvpp::internal::uv_cid_write, callback); 88 | return uv_write(new uv_write_t, handle::template get(), bufs, 1, [](uv_write_t* req, int status) 89 | { 90 | std::unique_ptr reqHolder(req); 91 | callbacks::invoke(req->handle->data, uvpp::internal::uv_cid_write, error(status)); 92 | }) == 0; 93 | } 94 | 95 | bool write(const std::vector& buf, CallbackWithResult callback) 96 | { 97 | uv_buf_t bufs[] = { uv_buf_t { const_cast(&buf[0]), buf.size() } }; 98 | callbacks::store(handle::get()->data, uvpp::internal::uv_cid_write, callback); 99 | return uv_write(new uv_write_t, handle::template get(), bufs, 1, [](uv_write_t* req, int status) 100 | { 101 | std::unique_ptr reqHolder(req); 102 | callbacks::invoke(req->handle->data, uvpp::internal::uv_cid_write, error(status)); 103 | }) == 0; 104 | } 105 | 106 | bool shutdown(CallbackWithResult callback) 107 | { 108 | callbacks::store(handle::get()->data, uvpp::internal::uv_cid_shutdown, callback); 109 | return uv_shutdown(new uv_shutdown_t, handle::template get(), [](uv_shutdown_t* req, int status) 110 | { 111 | std::unique_ptr reqHolder(req); 112 | callbacks::invoke(req->handle->data, uvpp::internal::uv_cid_shutdown, error(status)); 113 | }) == 0; 114 | } 115 | }; 116 | } 117 | -------------------------------------------------------------------------------- /include/uvpp/tcp.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "stream.hpp" 4 | #include "net.hpp" 5 | #include "loop.hpp" 6 | 7 | namespace uvpp { 8 | class Tcp : public stream 9 | { 10 | public: 11 | Tcp(): 12 | stream() 13 | { 14 | uv_tcp_init(uv_default_loop(), get()); 15 | } 16 | 17 | Tcp(loop& l): 18 | stream() 19 | { 20 | uv_tcp_init(l.get(), get()); 21 | } 22 | 23 | bool nodelay(bool enable) 24 | { 25 | return uv_tcp_nodelay(get(), enable ? 1 : 0) == 0; 26 | } 27 | 28 | bool keepalive(bool enable, unsigned int delay) 29 | { 30 | return uv_tcp_keepalive(get(), enable ? 1 : 0, delay) == 0; 31 | } 32 | 33 | bool simultanious_accepts(bool enable) 34 | { 35 | return uv_tcp_simultaneous_accepts(get(), enable ? 1 : 0) == 0; 36 | } 37 | 38 | // FIXME: refactor with getaddrinfo 39 | bool bind(const std::string& ip, int port) 40 | { 41 | ip4_addr addr = to_ip4_addr(ip, port); 42 | return uv_tcp_bind(get(), reinterpret_cast(&addr), 0) == 0; 43 | } 44 | 45 | bool bind6(const std::string& ip, int port) 46 | { 47 | ip6_addr addr = to_ip6_addr(ip, port); 48 | return uv_tcp_bind(get(), reinterpret_cast(&addr), 0) == 0; 49 | } 50 | 51 | bool connect(const std::string& ip, int port, CallbackWithResult callback) 52 | { 53 | callbacks::store(get()->data, internal::uv_cid_connect, callback); 54 | ip4_addr addr = to_ip4_addr(ip, port); 55 | return uv_tcp_connect(new uv_connect_t, get(), reinterpret_cast(&addr), [](uv_connect_t* req, int status) 56 | { 57 | std::unique_ptr reqHolder(req); 58 | callbacks::invoke(req->handle->data, internal::uv_cid_connect, error(status)); 59 | }) == 0; 60 | } 61 | 62 | bool connect6(const std::string& ip, int port, CallbackWithResult callback) 63 | { 64 | callbacks::store(get()->data, internal::uv_cid_connect6, callback); 65 | ip6_addr addr = to_ip6_addr(ip, port); 66 | return uv_tcp_connect(new uv_connect_t, get(), reinterpret_cast(&addr), [](uv_connect_t* req, int status) 67 | { 68 | std::unique_ptr reqHolder(req); 69 | callbacks::invoke(req->handle->data, internal::uv_cid_connect6, error(status)); 70 | }) == 0; 71 | } 72 | 73 | bool getsockname(bool& ip4, std::string& ip, int& port) 74 | { 75 | struct sockaddr_storage addr; 76 | int len = sizeof(addr); 77 | if (uv_tcp_getsockname(get(), reinterpret_cast(&addr), &len) == 0) 78 | { 79 | ip4 = (addr.ss_family == AF_INET); 80 | if (ip4) return from_ip4_addr(reinterpret_cast(&addr), ip, port); 81 | else return from_ip6_addr(reinterpret_cast(&addr), ip, port); 82 | } 83 | return false; 84 | } 85 | 86 | bool getpeername(bool& ip4, std::string& ip, int& port) 87 | { 88 | struct sockaddr_storage addr; 89 | int len = sizeof(addr); 90 | if (uv_tcp_getpeername(get(), reinterpret_cast(&addr), &len) == 0) 91 | { 92 | ip4 = (addr.ss_family == AF_INET); 93 | if (ip4) return from_ip4_addr(reinterpret_cast(&addr), ip, port); 94 | else return from_ip6_addr(reinterpret_cast(&addr), ip, port); 95 | } 96 | return false; 97 | } 98 | }; 99 | } 100 | -------------------------------------------------------------------------------- /include/uvpp/timer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "handle.hpp" 4 | #include "error.hpp" 5 | #include 6 | 7 | namespace uvpp { 8 | class Timer : public handle 9 | { 10 | public: 11 | Timer(): 12 | handle() 13 | { 14 | uv_timer_init(uv_default_loop(), get()); 15 | } 16 | 17 | Timer(loop& l): 18 | handle() 19 | { 20 | uv_timer_init(l.get(), get()); 21 | } 22 | 23 | error start(std::function callback, const std::chrono::duration &timeout, const std::chrono::duration &repeat) 24 | { 25 | callbacks::store(get()->data, internal::uv_cid_timer, callback); 26 | return error(uv_timer_start(get(), 27 | [](uv_timer_t* handle) 28 | { 29 | callbacks::invoke(handle->data, internal::uv_cid_timer); 30 | }, 31 | timeout.count(), 32 | repeat.count() 33 | )); 34 | } 35 | 36 | error start(std::function callback, const std::chrono::duration &timeout) 37 | { 38 | callbacks::store(get()->data, internal::uv_cid_timer, callback); 39 | return error(uv_timer_start(get(), 40 | [](uv_timer_t* handle) 41 | { 42 | callbacks::invoke(handle->data, internal::uv_cid_timer); 43 | }, 44 | timeout.count(), 45 | 0 46 | )); 47 | } 48 | 49 | error stop() 50 | { 51 | return error(uv_timer_stop(get())); 52 | } 53 | 54 | error again() 55 | { 56 | return error(uv_timer_again(get())); 57 | } 58 | }; 59 | } -------------------------------------------------------------------------------- /include/uvpp/tty.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "handle.hpp" 4 | #include "error.hpp" 5 | 6 | namespace uvpp { 7 | class TTY : public stream 8 | { 9 | public: 10 | 11 | enum Type 12 | { 13 | STDIN, 14 | STDOUT, 15 | STDERR 16 | }; 17 | 18 | TTY(Type type, bool readable): 19 | stream(), type_(type) 20 | { 21 | uv_tty_init(uv_default_loop(), get(), static_cast(type_), static_cast(readable)); 22 | } 23 | 24 | TTY(loop& l, Type type, bool readable): 25 | stream(), type_(type) 26 | { 27 | uv_tty_init(l.get(), get(), static_cast(type_), static_cast(readable)); 28 | } 29 | private: 30 | Type type_; 31 | }; 32 | } -------------------------------------------------------------------------------- /include/uvpp/uvpp.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tcp.hpp" 3 | #include "timer.hpp" 4 | #include "tty.hpp" 5 | #include "work.hpp" 6 | #include "file.hpp" 7 | #include "poll.hpp" 8 | #include "fspoll.hpp" 9 | #include "fsevent.hpp" 10 | #include "pipe.hpp" 11 | -------------------------------------------------------------------------------- /include/uvpp/work.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "request.hpp" 4 | #include "error.hpp" 5 | #include "loop.hpp" 6 | 7 | namespace uvpp { 8 | class Work : public request 9 | { 10 | public: 11 | Work(loop& l) : request(), loop_(l.get()) 12 | { 13 | 14 | } 15 | 16 | bool execute(Callback callback, CallbackWithResult afterCallback) 17 | { 18 | 19 | 20 | callbacks::store(get()->data, internal::uv_cid_work, callback); 21 | callbacks::store(get()->data, internal::uv_cid_after_work, afterCallback); 22 | 23 | return ( 24 | uv_queue_work(loop_, get(), 25 | [](uv_work_t* req) 26 | { 27 | callbacks::invoke(req->data, internal::uv_cid_work); 28 | }, 29 | [](uv_work_t* req, int status) 30 | { 31 | callbacks::invoke(req->data, internal::uv_cid_after_work, error(status)); 32 | }) == 0 33 | ); 34 | } 35 | private: 36 | uv_loop_t *loop_; 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8) 2 | PROJECT(test-uvpp) 3 | 4 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wall -Wextra -pedantic -pthread -std=c++11 -Wl,--no-as-needed") 5 | SET(CMAKE_BUILD_TYPE Debug) 6 | 7 | INCLUDE_DIRECTORIES( 8 | ../include 9 | ${PROJECT_SOURCE_DIR} 10 | ) 11 | 12 | ADD_EXECUTABLE(${PROJECT_NAME} main.cpp Server.cpp TcpConnection.cpp) 13 | 14 | TARGET_LINK_LIBRARIES(${PROJECT_NAME} uv) 15 | -------------------------------------------------------------------------------- /test/Server.cpp: -------------------------------------------------------------------------------- 1 | #include "Server.h" 2 | #include "uvpp/make_unique_define.h" 3 | #include 4 | 5 | using namespace std; 6 | 7 | Server::Server() : m_running(false), m_port(0), m_loop(), m_tcp_listen_conn(m_loop), m_async(m_loop, bind(&Server::on_async, this)), m_on_close(), m_on_connect() 8 | { 9 | } 10 | 11 | Server::~Server() 12 | { 13 | } 14 | 15 | void Server::set_port(int port) 16 | { 17 | if (m_running) 18 | throw std::runtime_error("Daemon::set_port can't change while running"); 19 | m_port = port; 20 | } 21 | 22 | void Server::start() 23 | { 24 | m_tcp_listen_conn.bind("0.0.0.0", 12345); 25 | m_tcp_listen_conn.listen(std::bind(&Server::on_tcp_connect, this, placeholders::_1)); 26 | m_running = true; 27 | m_loop.run(); 28 | } 29 | 30 | void Server::stop() 31 | { 32 | m_running = false; 33 | } 34 | 35 | void Server::send(const string &peer, const string &msg) 36 | { 37 | std::lock_guard l(m_send_lock); 38 | m_sendBuf.push_back(msg_buf(peer, msg)); 39 | m_async.send(); 40 | } 41 | 42 | void Server::on_async() 43 | { 44 | std::lock_guard l(m_send_lock); 45 | while (!m_sendBuf.empty()) 46 | { 47 | const msg_buf &buf = m_sendBuf.front(); 48 | auto iter = m_connections.find(buf.peer); 49 | if (iter != m_connections.end()) 50 | { 51 | iter->second->send_msg(move(buf.msg)); 52 | } 53 | m_sendBuf.pop_front(); 54 | } 55 | } 56 | 57 | void Server::on_tcp_connect(uvpp::error error) 58 | { 59 | auto tcp_conn_ptr = make_unique(m_loop); 60 | TcpConnection &tcp_conn = *tcp_conn_ptr; 61 | m_tcp_listen_conn.accept(tcp_conn.m_tcp); 62 | 63 | string peer_ip; 64 | int port; 65 | bool ip4; 66 | const bool getpeername_ok = tcp_conn.m_tcp.getpeername(ip4, peer_ip, port); 67 | assert(getpeername_ok); 68 | (void)getpeername_ok; 69 | ostringstream os; 70 | os << "tcp://" << peer_ip << ":" << port; 71 | string peer_ = os.str(); 72 | 73 | tcp_conn.set_peer_name(peer_); 74 | 75 | auto res = m_connections.emplace(piecewise_construct, 76 | forward_as_tuple(move(peer_)), 77 | forward_as_tuple(move(tcp_conn_ptr))); 78 | 79 | assert(res.second); 80 | const string &peer = res.first->first; // reference that will stay valid 81 | 82 | if (m_on_connect) 83 | { 84 | m_on_connect(peer); 85 | } 86 | 87 | cout << "receive new connect:" << peer << " size = " << m_connections.size() << endl; 88 | 89 | auto close_cb = [this, &peer]() { 90 | if (m_on_close) 91 | m_on_close(peer); 92 | m_connections.erase(peer); 93 | }; 94 | 95 | // write finished callback 96 | auto write_cb = [&tcp_conn, close_cb](uvpp::error error) { 97 | if (!error) 98 | { 99 | tcp_conn.on_write_finished(); 100 | } 101 | else 102 | { 103 | tcp_conn.m_tcp.close(close_cb); 104 | } 105 | }; 106 | 107 | // function to be called when the the protocol needs to write 108 | auto do_write = [&tcp_conn, write_cb](const char *buff, size_t sz) { 109 | tcp_conn.m_tcp.write(buff, sz, write_cb); 110 | }; 111 | 112 | auto read_cb = [&tcp_conn, &peer, close_cb](const char *buff, ssize_t len) { 113 | if (len < 0) 114 | { 115 | cerr << "TCP client read error: " << peer << endl; 116 | tcp_conn.m_tcp.close(close_cb); 117 | } 118 | else 119 | { 120 | tcp_conn.input(buff, static_cast(len)); 121 | } 122 | }; 123 | 124 | tcp_conn.set_write_fun(do_write); 125 | 126 | tcp_conn.m_tcp.read_start(read_cb); 127 | } 128 | -------------------------------------------------------------------------------- /test/Server.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "TcpConnection.h" 3 | #include 4 | #include 5 | #include "uvpp/async.hpp" 6 | #include 7 | #include 8 | 9 | struct msg_buf 10 | { 11 | msg_buf(std::string p, std::string m) : peer(p), msg(m) 12 | { 13 | } 14 | 15 | std::string peer; 16 | std::string msg; 17 | }; 18 | 19 | class Server 20 | { 21 | public: 22 | typedef std::function on_close_t; 23 | typedef std::function on_connect_t; 24 | Server(); 25 | ~Server(); 26 | 27 | void set_port(int port); 28 | void start(); 29 | void stop(); 30 | 31 | void send(const std::string &peer, const std::string &msg); 32 | 33 | private: 34 | void on_tcp_connect(uvpp::error error); 35 | void on_async(); 36 | 37 | private: 38 | int m_port; 39 | bool m_running; 40 | uvpp::loop m_loop; 41 | uvpp::Tcp m_tcp_listen_conn; 42 | 43 | on_close_t m_on_close; 44 | on_connect_t m_on_connect; 45 | 46 | uvpp::Async m_async; 47 | std::mutex m_send_lock; 48 | std::deque m_sendBuf; 49 | 50 | /// connection identifier to Connection 51 | std::map> m_connections; 52 | }; 53 | -------------------------------------------------------------------------------- /test/TcpConnection.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "TcpConnection.h" 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | void TcpConnection::set_peer_name(std::string &peer_name) 9 | { 10 | m_peerName = peer_name; 11 | } 12 | 13 | /** 14 | * Check if we have a full message then decode it and handle, otherwise wait for more data, same for 15 | * payload. 16 | */ 17 | void TcpConnection::input(const char *data, size_t len) 18 | { 19 | string buf; 20 | buf.resize(len); 21 | memcpy(&buf[0], data, len); 22 | buf.push_back('\0'); 23 | cout << m_peerName << ":" << buf << " len:" << len << endl; 24 | } 25 | 26 | void TcpConnection::send_msg(const std::string &&msg) 27 | { 28 | const bool do_write = m_output_buff.empty() == true; 29 | m_output_buff.emplace_back(move(msg)); 30 | if (do_write) 31 | write_next_buff(); 32 | } 33 | 34 | void TcpConnection::write_next_buff() 35 | { 36 | assert(!m_write_in_progress); 37 | assert(!m_output_buff.empty()); 38 | const string &buf = m_output_buff.front(); 39 | m_do_write(buf.c_str(), buf.size()); 40 | m_write_in_progress = true; 41 | } 42 | 43 | void TcpConnection::on_write_finished() 44 | { 45 | m_write_in_progress = false; 46 | assert(!m_output_buff.empty()); 47 | m_output_buff.pop_front(); 48 | if (!m_output_buff.empty()) 49 | write_next_buff(); 50 | } -------------------------------------------------------------------------------- /test/TcpConnection.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "uvpp/loop.hpp" 3 | #include "uvpp/tcp.hpp" 4 | #include 5 | 6 | class TcpConnection 7 | { 8 | public: 9 | /// type of callback for writing data 10 | typedef std::function do_write_t; 11 | 12 | /// when the protocol can't make sense of the data we should probably close the connection 13 | typedef std::function handle_error_t; 14 | 15 | 16 | TcpConnection(uvpp::loop &loop) : 17 | r_loop(loop) 18 | , m_tcp(loop) 19 | , m_write_in_progress(false) 20 | { 21 | 22 | }; 23 | 24 | void set_peer_name(std::string& peer_name); 25 | 26 | void set_write_fun(do_write_t do_write) 27 | { 28 | m_do_write = do_write; 29 | } 30 | 31 | void input(const std::string& s) 32 | { 33 | input(s.c_str(), s.size()); 34 | } 35 | /** 36 | * feed input data, for example from socket IO 37 | * Once a full message is read, handle_message is called 38 | * 39 | * to be called by the event library on read 40 | */ 41 | void input(const char* data, size_t len); 42 | 43 | 44 | /// to be called by the event library on write when the last write finished 45 | void on_write_finished(); 46 | 47 | /** 48 | * will write the next output buffer by calling the write function @sa m_do_write 49 | * @post m_write_in_progress will be true 50 | */ 51 | void write_next_buff(); 52 | 53 | void send_msg(const std::string&& msg); 54 | 55 | private: 56 | /// internal input buffer accumulating data until it can be processed 57 | std::string m_input_buff; 58 | /// queue of buffers to write, we write from front to back, new appended to back, when wrote, 59 | /// removed from front. 60 | std::deque m_output_buff; 61 | 62 | std::string m_peerName; 63 | 64 | public: 65 | uvpp::loop &r_loop; 66 | uvpp::Tcp m_tcp; 67 | do_write_t m_do_write; 68 | 69 | bool m_write_in_progress; 70 | 71 | handle_error_t m_handle_error; 72 | }; 73 | 74 | -------------------------------------------------------------------------------- /test/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "Server.h" 5 | 6 | using namespace std; 7 | 8 | int main() 9 | { 10 | Server s; 11 | 12 | s.set_port(12345); 13 | s.start(); 14 | 15 | return 0; 16 | } --------------------------------------------------------------------------------