fpagliughi / sockpp Goto Github PK
View Code? Open in Web Editor NEWModern C++ socket library.
License: BSD 3-Clause "New" or "Revised" License
Modern C++ socket library.
License: BSD 3-Clause "New" or "Revised" License
so far the best socket-c-api wrapper I found for c++, hope it will have a stable release soon. Thanks!
I was able to create a static library in both Windows and Linux (using ArchLinux) following the README. Two files were generated:
Then I need to use the static library in another program, which is built using a Makefile.
In Linux no issue occurs, while in Windows with minGW-x64 I received multiple errors like
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/12.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\msys64\tmp\ccvvpJbH.o:tcp6echo.cpp:(.text+0x176): undefined reference to `sockpp::operator<<(std::ostream&, sockpp::inet6_address const&)'
To reproduce the issue with the example tcp6echo (assuming headers in ./include and static library in ./lib):
g++ -I./include -o tcp6echo tcp6echo.cpp -L./lib -lsockpp
g++ -I./include -o tcp6echo tcp6echo.cpp -L./lib -l:sockpp-static.lib
I've been trying to integrate your code with MS Visual Studio 2019 for quite awhile now and I've come up with many errors. Currently the one I can not figure out is all these unresolved external symbols that I'm getting. I'm new to integrating libraries with Visual Studio, or anything for that matter. I'll walk you through what I've done.
I used CMake to build the binaries for a static library then in the .sln file it produced I built the solution.
After building it I placed the sockpp-static.lib and sockpp-obj.lib in a dependencies folder in the repo of the project I was testing it with. I pointed the linker at both of these files and then added the include and library directories.
It threw some weird runtime errors that I had to fix and some weird iterator debug errors that I fixed and now I'm at this point where it throws all these unresolved external symbol errors based off the sockpp-static.lib file.
It looks like this:
https://i.imgur.com/NImylP6.png
It does this after I use anything to do with sockpp.
For example:
in_port_t port = 5050;
socket_initializer sockInit;
return 0;
will throw a bunch of errors. However if it's only in_port_t port;
then it won't throw the errors.
I've tried messing with the runtime library it uses and some preprocessor settings as well. I even tried adding each of the .obj files that are generated by CMake to the Additional Directories but all that does is make it so the file that is causing the issue is no longer "sockpp-static.lib(socket.obj)" but it's "socket.obj" that's causing the problem.
Forgive me, I'm new to this. I have no clue what could be causing all these errors.
Lines 227 to 230 in d8c86c0
optlen is set after the return statement
For performance reasons it's good to be able to read or write multiple discontiguous byte ranges in one system call. The generic system calls for this are writev
and readv
; the socket-specific ones are sendmsg
and recvmsg
.
The C++ methods for these would probably take a const std::vector<iovec>&
parameter.
A failure in connector::connect()
or acceptor::open
now leaves the last_error
property at 0 instead of an actual error code.
This is a side effect of the fix of #23. socket::close
now overwrites last_error
with the status of the ::close
call, which is almost always 0.
I installed Doxygen and Graphiz (because it first said "doxygen missing components: dot") and I'm trying this on Windows:
mkdir build
cd build
cmake ..
cmake -D SOCKPP_BUILD_DOCUMENTATION=ON --build .
But no HTML files are appearing anywhere in the build directory. How does this work?
My output is:
-- Building for: Visual Studio 16 2019
-- Selecting Windows SDK version 10.0.18362.0 to target Windows 10.0.17763.
-- The C compiler identification is MSVC 19.24.28314.0
-- The CXX compiler identification is MSVC 19.24.28314.0
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/BuildTools/VC/Tools/MSVC/14.24.28314/bin/Hostx64/x64/cl.exe
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/BuildTools/VC/Tools/MSVC/14.24.28314/bin/Hostx64/x64/cl.exe -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/BuildTools/VC/Tools/MSVC/14.24.28314/bin/Hostx64/x64/cl.exe
-- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/BuildTools/VC/Tools/MSVC/14.24.28314/bin/Hostx64/x64/cl.exe -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Creating static library: sockpp-static
-- Configuring done
-- Generating done
-- Build files have been written to: C:/software/sockpp/build
-- Selecting Windows SDK version 10.0.18362.0 to target Windows 10.0.17763.
-- Creating static library: sockpp-static
-- Found Doxygen: C:/Program Files/doxygen/bin/doxygen.exe (found version "1.8.17 (b5fa3cd1c6e6240e20d3b80a70e3f04040b32021*)") found components: doxygen dot
-- Configuring done
-- Generating done
-- Build files have been written to: C:/software/sockpp/build
I discovered that I could simply run doxygen
to generate the documentation, but that should be in the README file. (or putting the documentation online, that would be better)
Get the datagram/UDP sockets working for all the address families and make sure it works on Windows as well.
Per the UTF-8 Everywhere Manifesto, it's best to not rely on the legacy ANSI .vs UNICODE macros for Win32 functions that take strings. Since you explicitly use an ANSI string for the call to LoadLibrary
you should explicitly use the LoadLibraryA
method.
This causes problems when trying to build your library using vcpkg manager when the setup adds the recommended UNICODE _UNICODE defines.
In exception.cpp use FormatMessageA
instead of FormatMessage
.
Great library! Any interest in integrating select
?
If so, I'm interested in working on that, but I'm curious what your thoughts are on how it would best fit into the library / future plans you might have.
Hi there. I found useful to have such a place to get answers to some questions related to the library. So, hopefully, this does the job.
At least I have a little list of questions that I want to ask you before continuing to work on my project.
sockpp::tcp_socket
ensure that the packets will be transferred for 100% (I mean if there is not a full connection lost, but some packets were dropped) and in the correct order?Thanks in advance.
In the stream_socket
class, the calls to read_timeout()
and write_timeout()
are empty for Windows. I can't remember if Windows doesn't support this, or if I was just too lazy to look up how.
@borrrden Do you know?
bool stream_socket::read_timeout(const microseconds& to)
{
#if !defined(_WIN32)
timeval tv = to_timeval(to);
return set_option(SOL_SOCKET, SO_RCVTIMEO, tv);
#else
return false;
#endif
}
Since I can use clone() to copy a tcp_socket
or tcp_connect
, I want to do the same for udp_socket
For example, I want to have one thread to read from a udp_socket and another thread to write to this udp_socket
Here is a demo:
const int BUF_SIZE = 512;
const string host = "";//the target
const in_port_t port = 12345;
void listener(sockpp::udp_socket sock) {
string s;
s.resize(BUF_SIZE);
while (true) {
int n = sock.recv(&s[0], BUF_SIZE);
cout << s.substr(0, n) << endl;
}
}
void sender(sockpp::udp_socket sock) {
string s;
while (true) {
cin >> s;
sock.send_to(s, {host, port});
}
}
int main() {
sockpp::initialize();
sockpp::udp_socket sock;
sock.connect({host, port});
std::thread thr(listener, sock.clone());
sender(std::move(sock));
}
But this example fails to compile. In order to make it work, I consult stream_socket.h and modified datagram_socket.h.
Specifically, I tried adding a function like below in class datagram_socket:
datagram_socket clone() const {
auto h = base::clone().release();
return datagram_socket(h);
}
And a function below in class datagram_socket_tmpl:
datagram_socket_tmpl(datagram_socket&& sock)
: base(std::move(sock)) {}
It seems to work fine under Windows, but I didn't do a rigorous test. Is there a bug in this method, and is there a better way to deal with the problem?
There are a number of glitches in the doc-comments, especially @param
directives, like name mismatches and empty descriptions. They're flagged as warnings by Doxygen, and by Clang if -Wdocumentation
is on.
Not a big deal, except that the project I work on builds with -Wdocumentation -Werror
(because it's a library with its own API and doc-comments), so when I include sockpp headers they break the build.
I can work around this by wrapping all the includes with #pragma clang diagnostic push / ignored / pop
, but it's a pain and it'd be nice if these were cleaned up along with the other header-file work that's acknowledged in the README :)
That's what I get for not pulling the dusty old Windows laptop out of the closet.
The latest 'master' has the fixes.
Using: g++ (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
Examples: tcp echo client /server and unix echo client/server.
I consistently get errors with non- static reference made to run_echo().
when I comment out the call to run_echo(); I get undefined references
`sockpp::inet_address::inet_address(std::__cxx11::basic_string<char, std::char_traits, std::allocator > const&, unsigned short)':|
Windows is now reporting:
...\sockpp\src\socket.cpp(192): error C3861: 'strerror_r': identifier not found [...\sockpp\build\src\sockpp-objs.vcxproj]
One of my tests keeps crashing with uncaught exception of type sockpp::sys_error
. The exception is expected (the test tries to connect to a nonexistent hostname) but my catch(const std::exception &x) { ... }
is being ignored.
I finally realized the problem: sys_error
is not compatible with type std::exception
because it doesn't publicly inherit from it. Its declaration needs to be changed to
class sys_error : public std::runtime_error
i.e. adding public
after the colon.
With this fix, my test works as expected.
First off, thanks for writing sockcpp
! It's almost exactly what I was looking for in a modernized C++ sockets library.
I've been digging through the code, and I'm confused about why you've preferred to implement and use sock_address_ref
over using C++ references to sock_address
.
It would be useful to support non-blocking I/O on sockets, and non-blocking connect
and accept
. This allows a lot more flexibility with threading, instead of having to devote one or two threads to every socket. It also seems like the only way to control the timeout of connect
.
I've implemented this and will try to put a PR together today.
I tried to set the read timeout using read_timeout function in stream_socket.h but it failed. I got "Bad file descriptor" error message.
Is there a way to set the timeout or changing the default timout if that's possible ?
Hi fpagliughi,
Would you happen to know how to compile a sockpp included CPP file properly with G++? I've tried many including:
g++ main.cpp -o main -I "sockpp/include/" -L "sockpp/build/Debug/sockpp-static.lib"
Including both the path and the linker file location. The program compiles properly when I have the actual include statement (example: #include <sockpp/tcp_connector.h>) only - but when trying to add a TCP connector (example: sockpp::tcp_connector conn({"localhost", 12345});) - it fails to compile.
I was able to make it compile and run. The hardest part, actually, was fighting with CMake since Catch2 is not something I normally "install" since it's just one (or two) headers. Some CMake patching took care of that though, and the only thing left is the following issues (on Windows) in the unit tests causing 7 test and 8 assertion failures:
AF_INET
)sock.last_error() == EAFNOSUPPORT
needs to be sock.last_error() == WSAEAFNOSUPPORT
). Also, often these codes are WSAEINVAL
or WSAENOTSOCK
instead.socket::pair
not implemented for Windows, so its corresponding test failsto_timeval
is not implemented on Windows, causing compilation failuresAll of the above are pretty easily fixable though.
EDIT OH I forgot, initialize()
is never called during the tests so a lot of tests initially failed with the "not initialized" error. I fixed that by not auto generating the catch main function (GOTCHA: Include socket platform.h before catch.hpp to avoid odd errors from including headers in the wrong order)
Originally posted by @borrrden in #25 (comment)
I am developing a library, which uses come 3rd party libraries including this one. For the other libraries, I was able to include them using the following CMakeLists.txt
code:
find_package(package_name REQUIRED)
target_link_libraries(my_target_name PRIVATE package_name::package_name)
but for this one, it says the following:
Could not find a package configuration file provided by "sockpp-static" with any of the following names:
sockpp-staticConfig.cmake
sockpp-static-config.cmake
git clone https://github.com/fpagliughi/sockpp
Visual Studio 2019 Developer Command Prompt v16.5.4
cmake .. -G"NMake Makefiles" -DSOCKPP_BUILD_STATIC=SOCKPP_BUILD_STATIC -DCMAKE_CXX_FLAGS_RELEASE=/MT -DCMAKE_BUILD_TYPE=Release
examples/tcp/tcpecho.cpp
1>main.obj : error LNK2001: unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __stdcall sockpp::operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class sockpp::inet_address const &)" (??6sockpp@@YGAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV12@ABVinet_address@0@@Z)
1>main.obj : error LNK2001: unresolved external symbol "public: static class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __stdcall sockpp::socket::error_str(int)" (?error_str@socket@sockpp@@SG?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@H@Z)
1>main.obj : error LNK2001: unresolved external symbol "public: static void __stdcall sockpp::socket::destroy(void)" (?destroy@socket@sockpp@@SGXXZ)
1>main.obj : error LNK2001: unresolved external symbol "public: static void __stdcall sockpp::socket::initialize(void)" (?initialize@socket@sockpp@@SGXXZ)
A characteristic of earlier UNIX systems was that if a process caught a singal while the process was blocked in a "slow" system call, the system call was interrupted. The system call returned an error and
errno
was set toEINTR
. ... The problem with interrupted system calls is that we now have to handle the error return explicitly.
โStevens & Rago, Advanced Programming In The UNIX Environment, 3rd ed., sec. 10.5
This is annoying because you have to wrap some calls in a do...while
loop, and confusing because the behavior has changed over time, is different on different platforms, and there are workarounds to make it less annoying that don't (to me) seem to help.
It appears that the calls used by sockpp that are affected are connect
, accept
, send
, recv
. The man
pages for these all list EINTR
among the possible errors. All these need to be wrapped like:
int result;
do {
result = SYSTEMCALL();
} while (result < 0 && last_error_code() == EINTR);
I have no idea whether any of this applies to Windows. I don't think Windows even has the notion of "signals" in the same sense as Unix. (@borrrden ?)
Hi, I'm just wondering but is there any mechanism in this repository that can simply be able to receive data from another endpoint without knowing the length of it and be able to receive it all properly? For example, if I send an image on the server side to the client, is there any way I can receive the full image which one simple line to store it all in an array without sending the length of the data first then the actual data?
Hi,
I am developing a project and I want to use your library. I manage my dependencies as git submodules and add them with add_subdirectory. I want it to be built with the rest of my code using my configuration etc.
Would it be possible to add such an option to CMake?
Or add check:
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
add decide to install based on that.
Hi,
I've been trying to check if my socket that I have connected to a server is active in which it obviously is because I am able to send data back and forth, but is there any way I can check because I've been trying to use "socket.is_connected()" but it seems to be returning the same value no matter if it is connected or not. Currently using TCP sockets.
Hi,
When you are running thousands of client are you seeing any delay of messages between the packets?
Thanks,
Kushal
Would be nice to have a package for conan to easily add this to a project.
C:\For_CMake\source\sockpp-0.7.1\src\inet_address.cpp: In member function 'std::__cxx11::string sockpp::inet_address::to_string() const':
C:\For_CMake\source\sockpp-0.7.1\src\inet_address.cpp:107:13: error: 'inet_ntop' was not declared in this scope
auto str = inet_ntop(AF_INET, (void*) &(addr_.sin_addr), buf, INET_ADDRSTRLEN);
^~~~~~~~~
C:\For_CMake\source\sockpp-0.7.1\src\inet_address.cpp:107:13: note: suggested alternative: 'inet_ntoa'
auto str = inet_ntop(AF_INET, (void*) &(addr_.sin_addr), buf, INET_ADDRSTRLEN);
^~~~~~~~~
inet_ntoa
C:\For_CMake\source\sockpp-0.7.1\src\inet_address.cpp: In function 'std::ostream& sockpp::operator<<(std::ostream&, const sockpp::inet_address&)':
C:\For_CMake\source\sockpp-0.7.1\src\inet_address.cpp:117:13: error: 'inet_ntop' was not declared in this scope
auto str = inet_ntop(AF_INET, (void*) &(addr.sockaddr_in_ptr()->sin_addr),
^~~~~~~~~
C:\For_CMake\source\sockpp-0.7.1\src\inet_address.cpp:117:13: note: suggested alternative: 'inet_ntoa'
auto str = inet_ntop(AF_INET, (void*) &(addr.sockaddr_in_ptr()->sin_addr),
^~~~~~~~~
inet_ntoa
mingw32-make[2]: *** [src\CMakeFiles\sockpp-objs.dir\build.make:138: src/CMakeFiles/sockpp-objs.dir/inet_address.cpp.obj] Error 1
mingw32-make[1]: *** [CMakeFiles\Makefile2:141: src/CMakeFiles/sockpp-objs.dir/all] Error 2
mingw32-make: *** [Makefile:148: all] Error 2
When I try to cross-compile for use on an SH4 Linux system, I get a compile error.
After configuring with cmake as follows :
$ cmake -Bbuild -DSOCKPP_BUILD_SHARED=OFF -DSOCKPP_BUILD_STATIC=ON -DCMAKE_CXX_COMPILER="sh4-linux-g++" -DCMAKE_CXX_FLAGS="-Os -Wno-missing-field-intializers -DSO_REUSEPORT=2"
-- The C compiler identification is GNU 10.3.0
-- The CXX compiler identification is GNU 10.3.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /work/buildroot/output/host/usr/bin/sh4-linux-gcc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /work/buildroot/output/host/usr/bin/sh4-linux-g++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Creating static library: sockpp-static
-- Configuring done
-- Generating done
-- Build files have been written to: /home/habu/sockpp/build
The following error message appears when performing a build.
[ 10%] Building CXX object src/CMakeFiles/sockpp-objs.dir/acceptor.cpp.o
In file included from /home/habu/sockpp/include/sockpp/stream_socket.h:50,
from /home/habu/sockpp/include/sockpp/acceptor.h:49,
from /home/habu/sockpp/src/acceptor.cpp:38:
/home/habu/sockpp/include/sockpp/socket.h:70:1: error: 'timeval' does not name a type
70 | timeval to_timeval(const std::chrono::microseconds& dur);
| ^~~~~~~
/home/habu/sockpp/include/sockpp/socket.h:78:1: error: 'timeval' does not name a type
78 | timeval to_timeval(const std::chrono::duration<Rep,Period>& dur) {
| ^~~~~~~
/home/habu/sockpp/include/sockpp/socket.h:87:52: error: 'timeval' does not name a type
87 | inline std::chrono::microseconds to_duration(const timeval& tv)
| ^~~~~~~
/home/habu/sockpp/include/sockpp/socket.h: In function 'std::chrono::microseconds sockpp::to_duration(const int&)':
/home/habu/sockpp/include/sockpp/socket.h:89:40: error: request for member 'tv_sec' in 'tv', which is of non-class type 'const int'
89 | auto dur = std::chrono::seconds{tv.tv_sec}
| ^~~~~~
/home/habu/sockpp/include/sockpp/socket.h:89:46: error: no matching function for call to 'std::chrono::duration<long long int>::duration(<brace-enclosed initializer list>)'
89 | auto dur = std::chrono::seconds{tv.tv_sec}
| ^
In file included from /home/habu/sockpp/include/sockpp/socket.h:51,
from /home/habu/sockpp/include/sockpp/stream_socket.h:50,
from /home/habu/sockpp/include/sockpp/acceptor.h:49,
from /home/habu/sockpp/src/acceptor.cpp:38:
/mnt/wsl/work/buildroot/output/host/opt/ext-toolchain/sh4-buildroot-linux-musl/include/c++/10.3.0/chrono:478:14: note: candidate: 'template<class _Rep2, class _Period2, class> constexpr std::chrono::duration<_Rep, _Period>::duration(const std::chrono::duration<_Rep, _Period>&) [with _Rep2 = _Rep2; _Period2 = _Period2; <template-parameter-2-3> = <template-parameter-1-3>; _Rep = long long int; _Period = std::ratio<1>]'
478 | constexpr duration(const duration<_Rep2, _Period2>& __d)
| ^~~~~~~~
/mnt/wsl/work/buildroot/output/host/opt/ext-toolchain/sh4-buildroot-linux-musl/include/c++/10.3.0/chrono:478:14: note: template argument deduction/substitution failed:
/mnt/wsl/work/buildroot/output/host/opt/ext-toolchain/sh4-buildroot-linux-musl/include/c++/10.3.0/chrono:470:23: note: candidate: 'template<class _Rep2, class> constexpr std::chrono::duration<_Rep, _Period>::duration(const _Rep2&) [with _Rep2 = _Rep2; <template-parameter-2-2> = <template-parameter-1-2>; _Rep = long long int; _Period = std::ratio<1>]'
470 | constexpr explicit duration(const _Rep2& __rep)
| ^~~~~~~~
/mnt/wsl/work/buildroot/output/host/opt/ext-toolchain/sh4-buildroot-linux-musl/include/c++/10.3.0/chrono:470:23: note: template argument deduction/substitution failed:
/mnt/wsl/work/buildroot/output/host/opt/ext-toolchain/sh4-buildroot-linux-musl/include/c++/10.3.0/chrono:463:2: note: candidate: 'constexpr std::chrono::duration<_Rep, _Period>::duration(const std::chrono::duration<_Rep, _Period>&) [with _Rep = long long int; _Period = std::ratio<1>]'
463 | duration(const duration&) = default;
| ^~~~~~~~
/mnt/wsl/work/buildroot/output/host/opt/ext-toolchain/sh4-buildroot-linux-musl/include/c++/10.3.0/chrono:463:2: note: conversion of argument 1 would be ill-formed:
/mnt/wsl/work/buildroot/output/host/opt/ext-toolchain/sh4-buildroot-linux-musl/include/c++/10.3.0/chrono:461:12: note: candidate: 'std::chrono::duration<_Rep, _Period>::duration() [with _Rep = long long int; _Period = std::ratio<1>]'
461 | constexpr duration() = default;
| ^~~~~~~~
/mnt/wsl/work/buildroot/output/host/opt/ext-toolchain/sh4-buildroot-linux-musl/include/c++/10.3.0/chrono:461:12: note: candidate expects 0 arguments, 1 provided
In file included from /home/habu/sockpp/include/sockpp/stream_socket.h:50,
from /home/habu/sockpp/include/sockpp/acceptor.h:49,
from /home/habu/sockpp/src/acceptor.cpp:38:
/home/habu/sockpp/include/sockpp/socket.h:90:36: error: request for member 'tv_usec' in 'tv', which is of non-class type 'const int'
90 | + std::chrono::microseconds{tv.tv_usec};
| ^~~~~~~
/home/habu/sockpp/include/sockpp/socket.h:90:43: error: no matching function for call to 'std::chrono::duration<long long int, std::ratio<1, 1000000> >::duration(<brace-enclosed initializer list>)'
90 | + std::chrono::microseconds{tv.tv_usec};
| ^
In file included from /home/habu/sockpp/include/sockpp/socket.h:51,
from /home/habu/sockpp/include/sockpp/stream_socket.h:50,
from /home/habu/sockpp/include/sockpp/acceptor.h:49,
from /home/habu/sockpp/src/acceptor.cpp:38:
/mnt/wsl/work/buildroot/output/host/opt/ext-toolchain/sh4-buildroot-linux-musl/include/c++/10.3.0/chrono:478:14: note: candidate: 'template<class _Rep2, class _Period2, class> constexpr std::chrono::duration<_Rep, _Period>::duration(const std::chrono::duration<_Rep, _Period>&) [with _Rep2 = _Rep2; _Period2 = _Period2; <template-parameter-2-3> = <template-parameter-1-3>; _Rep = long long int; _Period = std::ratio<1, 1000000>]'
478 | constexpr duration(const duration<_Rep2, _Period2>& __d)
| ^~~~~~~~
/mnt/wsl/work/buildroot/output/host/opt/ext-toolchain/sh4-buildroot-linux-musl/include/c++/10.3.0/chrono:478:14: note: template argument deduction/substitution failed:
/mnt/wsl/work/buildroot/output/host/opt/ext-toolchain/sh4-buildroot-linux-musl/include/c++/10.3.0/chrono:470:23: note: candidate: 'template<class _Rep2, class> constexpr std::chrono::duration<_Rep, _Period>::duration(const _Rep2&) [with _Rep2 = _Rep2; <template-parameter-2-2> = <template-parameter-1-2>; _Rep = long long int; _Period = std::ratio<1, 1000000>]'
470 | constexpr explicit duration(const _Rep2& __rep)
| ^~~~~~~~
/mnt/wsl/work/buildroot/output/host/opt/ext-toolchain/sh4-buildroot-linux-musl/include/c++/10.3.0/chrono:470:23: note: template argument deduction/substitution failed:
/mnt/wsl/work/buildroot/output/host/opt/ext-toolchain/sh4-buildroot-linux-musl/include/c++/10.3.0/chrono:463:2: note: candidate: 'constexpr std::chrono::duration<_Rep, _Period>::duration(const std::chrono::duration<_Rep, _Period>&) [with _Rep = long long int; _Period = std::ratio<1, 1000000>]'
463 | duration(const duration&) = default;
| ^~~~~~~~
/mnt/wsl/work/buildroot/output/host/opt/ext-toolchain/sh4-buildroot-linux-musl/include/c++/10.3.0/chrono:463:2: note: conversion of argument 1 would be ill-formed:
/mnt/wsl/work/buildroot/output/host/opt/ext-toolchain/sh4-buildroot-linux-musl/include/c++/10.3.0/chrono:461:12: note: candidate: 'std::chrono::duration<_Rep, _Period>::duration() [with _Rep = long long int; _Period = std::ratio<1, 1000000>]'
461 | constexpr duration() = default;
| ^~~~~~~~
/mnt/wsl/work/buildroot/output/host/opt/ext-toolchain/sh4-buildroot-linux-musl/include/c++/10.3.0/chrono:461:12: note: candidate expects 0 arguments, 1 provided
In file included from /home/habu/sockpp/include/sockpp/stream_socket.h:50,
from /home/habu/sockpp/include/sockpp/acceptor.h:49,
from /home/habu/sockpp/src/acceptor.cpp:38:
/home/habu/sockpp/include/sockpp/socket.h: At global scope:
/home/habu/sockpp/include/sockpp/socket.h:99:65: error: 'timeval' does not name a type
99 | inline std::chrono::system_clock::time_point to_timepoint(const timeval& tv)
| ^~~~~~~
cc1plus: note: unrecognized command-line option '-Wno-missing-field-intializers' may have been intended to silence earlier diagnostics
gmake[2]: *** [src/CMakeFiles/sockpp-objs.dir/build.make:76: src/CMakeFiles/sockpp-objs.dir/acceptor.cpp.o] Error 1
gmake[1]: *** [CMakeFiles/Makefile2:126: src/CMakeFiles/sockpp-objs.dir/all] Error 2
gmake: *** [Makefile:136: all] Error 2
According to the error, the definition of the timeval type seems to be missing, so adding the following sys/time.h include near the beginning of include/sockpp/socket.h will enable compilation.
#include "sockpp/sock_address.h"
#include <sys/time.h> // <-- add
#include <chrono>
#include <string>
#include <tuple>
This should solve the problem on Linux-based systems, but I am not sure if this is a reasonable solution on non-Linux systems.
The GNU Makefiles are broken and will be removed in favor of the CMake build.
I have getting below error while building your library
build/Debug/GNU-Linux/NativeTCP.o:(.data.rel.ro._ZTVN6sockpp13tcp_connectorE[_ZTVN6sockpp13tcp_connectorE]+0x20): undefined reference to `sockpp::stream_socket::read(void*, unsigned long)'
I want to use CMake to compile this library for IOS, but I tried and got errors. Can I implement that?
`
Creating symlinks
/Applications/CMake.app/Contents/bin/cmake -E cmake_symlink_library /Users/wujiahang/Project/EdgeTileIOS/deps/build/sockpp/Release-iphoneos/libsockpp.0.7.0.dylib /Users/wujiahang/Project/EdgeTileIOS/deps/build/sockpp/Release-iphoneos/libsockpp.0.dylib /Users/wujiahang/Project/EdgeTileIOS/deps/build/sockpp/Release-iphoneos/libsockpp.dylib
CMake Error: failed to create symbolic link '/Users/wujiahang/Project/EdgeTileIOS/deps/build/sockpp/Release-iphoneos/libsockpp.0.dylib': no such file or directory
CMake Error: cmake_symlink_library: System Error: No such file or directory
CMake Error: failed to create symbolic link '/Users/wujiahang/Project/EdgeTileIOS/deps/build/sockpp/Release-iphoneos/libsockpp.dylib': no such file or directory
CMake Error: cmake_symlink_library: System Error: No such file or directory
make: *** [sockpp_buildpart_0] Error 1
** BUILD FAILED **
`
Thank you for building this awesome library. I'm seeing this weird issue where if we start Simultaneous 2 TCP connections to the server, the sever issue RSTs and close the TCP connections, but this doesn't happen if we open like more than 2 simultaneous TCP connections at same time.
I'm using Ubuntu OS. I observe the same issue on the evpp library, but I don't think this is library specific.
I did compile with these flags too
-Wpedantic -Wthread-safety -Wall -Wextra -g -fsanitize=undefined -fsanitize=address -fsanitize=leak
But they detected nothing, and so is Valgrind
The following NodeJS script is used to send Simultaneous TCP connections. You don't need to write a HTTP server stack to test this, just the usual TCP code with do nothing while loop to keep socket from destructuring. I'm using 5 threads in the C++ server.
const request = require('request-promise');
async function main() {
try {
// 2 requests at same time fails
const urls = [
"https://YOUR_IP:PORT",
"https://YOUR_IP:PORT",
]
const requests = [];
for(const url of urls) {
requests.push(request.get(url));
}
let res = await Promise.race(requests);
} catch (e) {
console.log(e);
}
}
main();
Please do let me know if you need the threaded wrapper that I wrote around your low level lib.
Hello!
I was attempting to roll my own socket library before I discovered sockpp (which is excellent, btw). One thing that stumped me in my own design was how to handle the case where close(2)
is called from within a destructor, but returns an error.
I see below that you opted not to handle a bad response from close
:
Line 262 in e5466fa
Do you think such a response is unlikely, or not applicable with this kind of file descriptor? Or do you expect that users would have a way to know within their application that close failed? The situation described in the (macOS) man page is that close could return an error if there were unreported problems with the previous write(2)
, but I have not been able to trigger that in practice.
Thank you for clarifying, I was super stumped by this one.
The definition of the struct
struct sockaddr_un
{
__SOCKADDR_COMMON (sun_);
char sun_path[108]; /* Path name. */
};
Allows a path with up to 108 characters. If all chars are used, there is no null termination. So all accessors of this path should check for the size:
--- a/sockpp/include/sockpp/unix_address.h
+++ b/sockpp/include/sockpp/unix_address.h
@@ -125,7 +125,7 @@ public:
* Gets the path to which this address refers.
* @return The path to which this address refers.
*/
- std::string path() const { return std::string(addr_.sun_path); }
+ std::string path() const { return std::string(addr_.sun_path, strnlen(addr_.sun_path, MAX_PATH_NAME)); }
/**
* Gets the size of the address structure.
* Note: In this implementation, this should return sizeof(this) but
@@ -170,7 +170,7 @@ public:
* "unix:<path>"
*/
std::string to_string() const {
- return std::string("unix:") + std::string(addr_.sun_path);
+ return std::string("unix:") + path();
}
};
--- a/sockpp/tests/unit/test_unix_address.cpp
+++ b/sockpp/tests/unit/test_unix_address.cpp
@@ -65,8 +65,8 @@ TEST_CASE("unix_address path constructor", "[address]") {
// Check the low-level struct
REQUIRE(AF_UNIX == addr.sockaddr_un_ptr()->sun_family);
- REQUIRE(0 == strcmp(PATH.c_str(),
- (const char*) &addr.sockaddr_un_ptr()->sun_path));
+ REQUIRE(0 == strncmp(PATH.c_str(),
+ (const char*) &addr.sockaddr_un_ptr()->sun_path, MAX_PATH_NAME));
SECTION("copy constructor") {
unix_address addr2(addr);
@@ -77,8 +77,8 @@ TEST_CASE("unix_address path constructor", "[address]") {
// Check the low-level struct
REQUIRE(AF_UNIX == addr2.sockaddr_un_ptr()->sun_family);
- REQUIRE(0 == strcmp(PATH.c_str(),
- (const char*) &addr2.sockaddr_un_ptr()->sun_path));
+ REQUIRE(0 == strncmp(PATH.c_str(),
+ (const char*) &addr2.sockaddr_un_ptr()->sun_path, MAX_PATH_NAME));
}
SECTION("sockaddr conversions") {
@@ -91,15 +91,15 @@ TEST_CASE("unix_address path constructor", "[address]") {
// Check the low-level struct
REQUIRE(AF_UNIX == addr2.sockaddr_un_ptr()->sun_family);
- REQUIRE(0 == strcmp(PATH.c_str(),
- (const char*) &(addr2.sockaddr_un_ptr()->sun_path)));
+ REQUIRE(0 == strncmp(PATH.c_str(),
+ (const char*) &(addr2.sockaddr_un_ptr()->sun_path, MAX_PATH_NAME)));
}
}
TEST_CASE("unix_address sockaddr_un constructor", "[address]") {
sockaddr_un unaddr;
unaddr.sun_family = AF_UNIX;
- strcpy(unaddr.sun_path, PATH.c_str());
+ strncpy(unaddr.sun_path, PATH.c_str(), MAX_PATH_NAME);
unix_address addr(unaddr);
@@ -109,8 +109,8 @@ TEST_CASE("unix_address sockaddr_un constructor", "[address]") {
// Check the low-level struct
REQUIRE(AF_UNIX == addr.sockaddr_un_ptr()->sun_family);
- REQUIRE(0 == strcmp(PATH.c_str(),
- (const char*) &addr.sockaddr_un_ptr()->sun_path));
+ REQUIRE(0 == strncmp(PATH.c_str(),
+ (const char*) &addr.sockaddr_un_ptr()->sun_path, MAX_PATH_NAME));
// TODO: Restore this when all address checks in place
/*
These warnings are generated on the Windows build...
inet_address.cpp(72): warning C4996: 'gethostbyname': Use getaddrinfo() or GetAddrInfoW() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings
inet_address.cpp(101): warning C4996: 'inet_ntoa': Use inet_ntop() or InetNtop() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings
inet_address.h(224): warning C4996: 'inet_ntoa': Use inet_ntop() or InetNtop() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings
exception.cpp(53): warning C4996: 'strerror': This function or variable may be unsafe. Consider using strerror_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
socket.cpp(114): warning C4996: 'WSADuplicateSocketA': Use WSADuplicateSocketW() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings
socket.cpp(115): warning C4996: 'WSASocketA': Use WSASocketW() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings
datagram_socket.obj : warning LNK4221: This object file does not define any previously undefined public symbols, so it will not be used by any link operation that consumes this library
The implementation of the socket
class's last_error
property is not thread-safe. The error code is copied from errno
into a member variable after a system call. However, the error really needs to be tracked per thread, as errno
itself is.
This is significant because it's not uncommon to have one thread writing to a socket and another thread reading from it โ this is a typical way to implement WebSockets, for example. What can happen in this case is:
write
.send
system call fails, and the error is copied from errno
into the socket's lastErr_
.read
.recv
system call succeeds, so lastErr_
is set to 0.write
call returned -1, and calls get_last_error
.get_last_error
returns 0, not the actual error from the write.In inet_address.cpp:
if (::getaddrinfo(saddr.c_str(), NULL, &hints, &res) != 0)
throw sys_error();
getaddrinfo
doesn't set errno
; it returns an error code instead. So this results in throwing a sys_err
with a code of zero, which isn't useful.
Worse, these error codes aren't errno
values, they're a different numbering system declared in netdb.h, like EAI_NONAME
(8), so putting the error code in the sys_error
would be a mistake.
Best solution is probably to create a getaddrinfo_error
exception class and throw that...
Hello.
I ran into a couple of issues trying to build examples with MSVS2015 update3 on Windows:
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\random(2387): error C2338: invalid template argument for uniform_int_distribution
F:\dump\sockpp\examples\tcp\tcpechotest.cpp(92): note: see reference to class template instantiation 'std::uniform_int_distribution<char>' being compiled
This is because the template parameter of std::uniform_int_distribution must be either: int
, short
, long
, long long
or their unsigned counterpart. Please see Template parameters
section here: std::uniform_int_distribution
F:\dump\sockpp\examples\udp\udpechosvr.cpp(75): error C2666: 'sockpp::datagram_socket_tmpl<sockpp::inet_address>::send_to': 2 overloads have similar conversions
F:\dump\sockpp\include\sockpp/datagram_socket.h(355): note: could be 'ssize_t sockpp::datagram_socket_tmpl<sockpp::inet_address>::send_to(const void *,std::size_t,const ADDR &)'
<...>
F:\dump\sockpp\include\sockpp/datagram_socket.h(345): note: or 'ssize_t sockpp::datagram_socket_tmpl<sockpp::inet_address>::send_to(const std::string &,int,const ADDR &)'
You can see the full error text for the 2nd issue here: https://gist.github.com/tsilia/6c9959ad0393a211970160c598a7cd41
I recently stumbled on a Microsoft blog claiming that some version of Windows 10 now supports Unix-domain sockets:
https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/
I have no experience with it, nor do I have access to a PC with a recent version of Windows 10. But if anyone has tried this and/or sees a desire for it, I don't think it would be too difficult to implement. Maybe we could create a CMake option for SOCKPP_BUILD_AF_UNIX, or something like that, and have it default true on Linux and false on Windows.
When building for Android targets, I've encountered the following error:
/workspace/myproject/third-party/sockpp/src/exception.cpp:70:15: error: no matching conversion for functional-style cast from 'int' to 'std::string' (aka 'basic_string<char, char_traits<char>, allocator<char> >')
return s ? std::string(s) : std::string();
I'll look into an actual resolution and submit a PR if the fix isn't immediately obvious, but was able to get around it by commenting it out, and the rest of the library built fine.
sockpp has its own declaration of ssize_t
in platform.h, but on non-Windows systems it defines it as int
. This is wrong on 64-bit OSs that use 32-bit ints, which includes all Apple platforms. (Dunno about Linux or BSD.) This leads to compile errors if a source file ends up including both platform.h and the OS's declaration. That aside, there are potentially actual integer overflow bugs if dealing with sizes > 4GB.
sockpp/include/sockpp/platform.h
Lines 78 to 86 in 180f18d
You shouldn't need to declare this at all. Instead:
#include <sys/types.h>
.#include <BaseTsd.h>
and then using ssize_t = SSIZE_T;
.(Also, it's kind of icky that the types declared in platform.h
are all in the global namespace. Could they be put in the sockpp
namespace like the rest of the API?)
It would be great if this library could be used without exceptions. There are many environments where exceptions are not allowed.
Hi, I'm just wondering but is there any mechanism in this repository that can simply be able to receive data from another endpoint without knowing the length of it and be able to receive it all properly? For example, if I send an image on the server side to the client, is there any way I can receive the full image which one simple line to store it all in an array without sending the length of the data first then the actual data?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.