Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
spdlog
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
spdlog
Commits
3b55709e
Commit
3b55709e
authored
Mar 13, 2020
by
Gabi Melman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
tcp_sink windows impl
parent
b4a1b4b5
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
192 additions
and
4 deletions
+192
-4
include/spdlog/details/tcp_client-windows.h
include/spdlog/details/tcp_client-windows.h
+179
-0
include/spdlog/sinks/tcp_sink.h
include/spdlog/sinks/tcp_sink.h
+13
-4
No files found.
include/spdlog/details/tcp_client-windows.h
0 → 100644
View file @
3b55709e
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#define WIN32_LEAN_AND_MEAN
// tcp client helper
#include <spdlog/common.h>
#include <spdlog/details/os.h>
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib
#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "Mswsock.lib")
#pragma comment(lib, "AdvApi32.lib")
namespace
spdlog
{
namespace
details
{
class
tcp_client
{
SOCKET
socket_
=
INVALID_SOCKET
;
static
bool
winsock_initialized_
()
{
SOCKET
s
=
socket
(
AF_INET
,
SOCK_STREAM
,
IPPROTO_TCP
);
if
(
s
==
INVALID_SOCKET
)
{
return
false
;
}
else
{
closesocket
(
s
);
return
true
;
}
}
static
void
init_winsock_
()
{
WSADATA
wsaData
;
auto
rv
=
WSAStartup
(
MAKEWORD
(
2
,
2
),
&
wsaData
);
if
(
rv
!=
0
)
{
throw_winsock_error_
(
"WSAStartup failed"
,
::
WSAGetLastError
());
}
}
static
void
throw_winsock_error_
(
const
std
::
string
&
msg
,
int
last_error
)
{
char
buf
[
512
];
::
FormatMessage
(
FORMAT_MESSAGE_FROM_SYSTEM
|
FORMAT_MESSAGE_IGNORE_INSERTS
,
NULL
,
last_error
,
MAKELANGID
(
LANG_NEUTRAL
,
SUBLANG_DEFAULT
),
buf
,
(
sizeof
(
buf
)
/
sizeof
(
char
)),
NULL
);
SPDLOG_THROW
(
spdlog_ex
(
fmt
::
format
(
"tcp_sink - {}: {}"
,
msg
,
buf
)));
}
public:
bool
is_connected
()
const
{
return
socket_
!=
INVALID_SOCKET
;
}
void
close
()
{
::
closesocket
(
socket_
);
socket_
=
INVALID_SOCKET
;
WSACleanup
();
}
SOCKET
fd
()
const
{
return
socket_
;
}
~
tcp_client
()
{
close
();
}
// try to connect or throw on failure
void
connect
(
const
std
::
string
&
host
,
int
port
)
{
// initialize winsock if needed
if
(
!
winsock_initialized_
())
{
init_winsock_
();
}
if
(
is_connected
())
{
close
();
}
struct
addrinfo
hints
{};
ZeroMemory
(
&
hints
,
sizeof
(
hints
));
hints
.
ai_family
=
AF_INET
;
// IPv4
hints
.
ai_socktype
=
SOCK_STREAM
;
// TCP
hints
.
ai_flags
=
AI_NUMERICSERV
;
// port passed as as numeric value
hints
.
ai_protocol
=
0
;
auto
port_str
=
std
::
to_string
(
port
);
struct
addrinfo
*
addrinfo_result
;
auto
rv
=
::
getaddrinfo
(
host
.
c_str
(),
port_str
.
c_str
(),
&
hints
,
&
addrinfo_result
);
int
last_error
=
0
;
if
(
rv
!=
0
)
{
last_error
=
::
WSAGetLastError
();
WSACleanup
();
throw_winsock_error_
(
"getaddrinfo failed"
,
last_error
);
}
// Try each address until we successfully connect(2).
for
(
auto
*
rp
=
addrinfo_result
;
rp
!=
nullptr
;
rp
=
rp
->
ai_next
)
{
socket_
=
socket
(
rp
->
ai_family
,
rp
->
ai_socktype
,
rp
->
ai_protocol
);
if
(
socket_
==
INVALID_SOCKET
)
{
last_error
=
::
WSAGetLastError
();
WSACleanup
();
continue
;
}
if
(
::
connect
(
socket_
,
rp
->
ai_addr
,
(
int
)
rp
->
ai_addrlen
)
==
0
)
{
break
;
}
else
{
last_error
=
::
WSAGetLastError
();
close
();
}
}
::
freeaddrinfo
(
addrinfo_result
);
if
(
socket_
==
INVALID_SOCKET
)
{
WSACleanup
();
throw_winsock_error_
(
"connect failed"
,
last_error
);
}
// set TCP_NODELAY
int
enable_flag
=
1
;
::
setsockopt
(
socket_
,
IPPROTO_TCP
,
TCP_NODELAY
,
(
char
*
)
&
enable_flag
,
sizeof
(
enable_flag
));
}
// Send exactly n_bytes of the given data.
// On error close the connection and throw.
void
send
(
const
char
*
data
,
size_t
n_bytes
)
{
size_t
bytes_sent
=
0
;
while
(
bytes_sent
<
n_bytes
)
{
const
int
send_flags
=
0
;
auto
write_result
=
::
send
(
socket_
,
data
+
bytes_sent
,
(
int
)(
n_bytes
-
bytes_sent
),
send_flags
);
if
(
write_result
==
SOCKET_ERROR
)
{
int
last_error
=
::
WSAGetLastError
();
close
();
throw_winsock_error_
(
"send failed"
,
last_error
);
}
if
(
write_result
==
0
)
// (probably should not happen but in any case..)
{
break
;
}
bytes_sent
+=
static_cast
<
size_t
>
(
write_result
);
}
}
};
}
// namespace details
}
// namespace spdlog
\ No newline at end of file
include/spdlog/sinks/tcp_sink.h
View file @
3b55709e
...
@@ -6,7 +6,12 @@
...
@@ -6,7 +6,12 @@
#include <spdlog/common.h>
#include <spdlog/common.h>
#include <spdlog/sinks/base_sink.h>
#include <spdlog/sinks/base_sink.h>
#include <spdlog/details/null_mutex.h>
#include <spdlog/details/null_mutex.h>
#ifdef _WIN32
#include <spdlog/details/tcp_client-windows.h>
#else
#include <spdlog/details/tcp_client.h>
#include <spdlog/details/tcp_client.h>
#endif
#include <mutex>
#include <mutex>
#include <string>
#include <string>
#include <chrono>
#include <chrono>
...
@@ -26,11 +31,12 @@ struct tcp_sink_config
...
@@ -26,11 +31,12 @@ struct tcp_sink_config
{
{
std
::
string
server_host
;
std
::
string
server_host
;
int
server_port
;
int
server_port
;
bool
lazy_connect
=
false
;
// connect on first log call instead of in construction
bool
lazy_connect
;
// connect on first log call instead of in construction
tcp_sink_config
(
std
::
string
host
,
int
port
)
tcp_sink_config
(
std
::
string
host
,
int
port
,
bool
lazy_connect
)
:
server_host
{
std
::
move
(
host
)}
:
server_host
{
std
::
move
(
host
)}
,
server_port
{
port
}
,
server_port
{
port
}
,
lazy_connect
{
lazy_connect
}
{}
{}
};
};
...
@@ -40,8 +46,9 @@ class tcp_sink : public spdlog::sinks::base_sink<Mutex>
...
@@ -40,8 +46,9 @@ class tcp_sink : public spdlog::sinks::base_sink<Mutex>
public:
public:
// connect to tcp host/port or throw if failed
// connect to tcp host/port or throw if failed
// host can be hostname or ip address
// host can be hostname or ip address
explicit
tcp_sink
(
tcp_sink_config
sink_config
)
:
config_
{
std
::
move
(
sink_config
)}
explicit
tcp_sink
(
tcp_sink_config
sink_config
)
:
config_
{
std
::
move
(
sink_config
)}
{
{
if
(
!
config_
.
lazy_connect
)
if
(
!
config_
.
lazy_connect
)
{
{
...
@@ -49,6 +56,8 @@ public:
...
@@ -49,6 +56,8 @@ public:
}
}
}
}
~
tcp_sink
()
override
=
default
;
~
tcp_sink
()
override
=
default
;
protected:
protected:
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment