Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
biboumi
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
88
Issues
88
List
Boards
Labels
Service Desk
Milestones
Merge Requests
7
Merge Requests
7
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Packages & Registries
Packages & Registries
Container Registry
Analytics
Analytics
CI / CD
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
louiz’
biboumi
Commits
3afb63a6
Commit
3afb63a6
authored
Dec 21, 2013
by
louiz’
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Shutdown cleanly on SIGINT
parent
df59a091
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
152 additions
and
29 deletions
+152
-29
src/bridge/bridge.cpp
src/bridge/bridge.cpp
+8
-0
src/bridge/bridge.hpp
src/bridge/bridge.hpp
+4
-0
src/irc/irc_client.cpp
src/irc/irc_client.cpp
+20
-0
src/irc/irc_client.hpp
src/irc/irc_client.hpp
+6
-0
src/main.cpp
src/main.cpp
+50
-3
src/network/poller.cpp
src/network/poller.cpp
+24
-21
src/network/poller.hpp
src/network/poller.hpp
+11
-3
src/xmpp/xmpp_component.cpp
src/xmpp/xmpp_component.cpp
+17
-1
src/xmpp/xmpp_component.hpp
src/xmpp/xmpp_component.hpp
+12
-1
No files found.
src/bridge/bridge.cpp
View file @
3afb63a6
...
...
@@ -21,6 +21,14 @@ Bridge::~Bridge()
{
}
void
Bridge
::
shutdown
()
{
for
(
auto
it
=
this
->
irc_clients
.
begin
();
it
!=
this
->
irc_clients
.
end
();
++
it
)
{
it
->
second
->
send_quit_command
();
}
}
Xmpp
::
body
Bridge
::
make_xmpp_body
(
const
std
::
string
&
str
)
{
std
::
string
res
;
...
...
src/bridge/bridge.hpp
View file @
3afb63a6
...
...
@@ -24,6 +24,10 @@ class Bridge
public:
explicit
Bridge
(
const
std
::
string
&
user_jid
,
XmppComponent
*
xmpp
,
Poller
*
poller
);
~
Bridge
();
/**
* QUIT all connected IRC servers.
*/
void
shutdown
();
static
Xmpp
::
body
make_xmpp_body
(
const
std
::
string
&
str
);
/***
...
...
src/irc/irc_client.cpp
View file @
3afb63a6
...
...
@@ -118,6 +118,11 @@ void IrcClient::send_kick_command(const std::string& chan_name, const std::strin
this
->
send_message
(
IrcMessage
(
"KICK"
,
{
chan_name
,
target
,
reason
}));
}
void
IrcClient
::
send_quit_command
()
{
this
->
send_message
(
IrcMessage
(
"QUIT"
,
{
"gateway shutdown"
}));
}
void
IrcClient
::
send_join_command
(
const
std
::
string
&
chan_name
)
{
if
(
this
->
welcomed
==
false
)
...
...
@@ -310,6 +315,21 @@ void IrcClient::on_part(const IrcMessage& message)
}
}
void
IrcClient
::
on_error
(
const
IrcMessage
&
message
)
{
const
std
::
string
leave_message
=
message
.
arguments
[
0
];
// The user is out of all the channels
for
(
auto
it
=
this
->
channels
.
begin
();
it
!=
this
->
channels
.
end
();
++
it
)
{
Iid
iid
;
iid
.
chan
=
it
->
first
;
iid
.
server
=
this
->
hostname
;
IrcChannel
*
channel
=
it
->
second
.
get
();
std
::
string
own_nick
=
channel
->
get_self
()
->
nick
;
this
->
bridge
->
send_muc_leave
(
std
::
move
(
iid
),
std
::
move
(
own_nick
),
leave_message
,
true
);
}
}
void
IrcClient
::
on_quit
(
const
IrcMessage
&
message
)
{
std
::
string
txt
;
...
...
src/irc/irc_client.hpp
View file @
3afb63a6
...
...
@@ -95,6 +95,10 @@ public:
* Send the KICK irc command
*/
void
send_kick_command
(
const
std
::
string
&
chan_name
,
const
std
::
string
&
target
,
const
std
::
string
&
reason
);
/**
* Send the QUIT irc command
*/
void
send_quit_command
();
/**
* Forward the server message received from IRC to the XMPP component
*/
...
...
@@ -139,6 +143,7 @@ public:
*/
void
on_welcome_message
(
const
IrcMessage
&
message
);
void
on_part
(
const
IrcMessage
&
message
);
void
on_error
(
const
IrcMessage
&
message
);
void
on_nick
(
const
IrcMessage
&
message
);
void
on_kick
(
const
IrcMessage
&
message
);
void
on_mode
(
const
IrcMessage
&
message
);
...
...
@@ -216,6 +221,7 @@ static const std::unordered_map<std::string, irc_callback_t> irc_callbacks = {
{
"366"
,
&
IrcClient
::
on_channel_completely_joined
},
{
"001"
,
&
IrcClient
::
on_welcome_message
},
{
"PART"
,
&
IrcClient
::
on_part
},
{
"ERROR"
,
&
IrcClient
::
on_error
},
{
"QUIT"
,
&
IrcClient
::
on_quit
},
{
"NICK"
,
&
IrcClient
::
on_nick
},
{
"MODE"
,
&
IrcClient
::
on_mode
},
...
...
src/main.cpp
View file @
3afb63a6
#include <xmpp/xmpp_component.hpp>
#include <network/poller.hpp>
#include <config/config.hpp>
#include <logger/logger.hpp>
#include <iostream>
#include <memory>
#include <atomic>
#include <signal.h>
// A flag set by the SIGINT signal handler.
volatile
std
::
atomic
<
bool
>
stop
(
false
);
// A flag indicating that we are wanting to exit the process. i.e: if this
// flag is set and all connections are closed, we can exit properly.
static
bool
exiting
=
false
;
/**
* Provide an helpful message to help the user write a minimal working
...
...
@@ -20,6 +30,11 @@ int config_help(const std::string& missing_option)
return
1
;
}
static
void
sigint_handler
(
int
,
siginfo_t
*
,
void
*
)
{
stop
=
true
;
}
int
main
(
int
ac
,
char
**
av
)
{
if
(
ac
>
1
)
...
...
@@ -44,8 +59,40 @@ int main(int ac, char** av)
Poller
p
;
p
.
add_socket_handler
(
xmpp_component
);
xmpp_component
->
start
();
while
(
p
.
poll
())
;
if
(
!
xmpp_component
->
start
())
{
log_info
(
"Exiting"
);
return
-
1
;
}
// Install the signals used to exit the process cleanly, or reload the
// config
sigset_t
mask
;
sigemptyset
(
&
mask
);
struct
sigaction
on_sig
;
on_sig
.
sa_sigaction
=
&
sigint_handler
;
on_sig
.
sa_mask
=
mask
;
// we want to catch that signal only once.
// Sending SIGINT again will "force" an exit
on_sig
.
sa_flags
=
SA_RESETHAND
;
sigaction
(
SIGINT
,
&
on_sig
,
nullptr
);
sigaction
(
SIGTERM
,
&
on_sig
,
nullptr
);
const
std
::
chrono
::
milliseconds
timeout
(
-
1
);
while
(
p
.
poll
(
timeout
)
!=
-
1
||
!
exiting
)
{
if
(
stop
)
{
log_info
(
"Signal received, exiting..."
);
exiting
=
true
;
stop
=
false
;
xmpp_component
->
shutdown
();
}
// If the only existing connection is the one to the XMPP component:
// close the XMPP stream.
if
(
exiting
&&
p
.
size
()
==
1
&&
xmpp_component
->
is_document_open
())
xmpp_component
->
close_document
();
}
log_info
(
"All connection cleanely closed, have a nice day."
);
return
0
;
}
src/network/poller.cpp
View file @
3afb63a6
...
...
@@ -9,7 +9,6 @@
Poller
::
Poller
()
{
#if POLLER == POLL
memset
(
this
->
fds
,
0
,
sizeof
(
this
->
fds
));
this
->
nfds
=
0
;
#elif POLLER == EPOLL
this
->
epfd
=
::
epoll_create1
(
0
);
...
...
@@ -42,9 +41,7 @@ void Poller::add_socket_handler(std::shared_ptr<SocketHandler> socket_handler)
this
->
nfds
++
;
#endif
#if POLLER == EPOLL
struct
epoll_event
event
;
event
.
data
.
ptr
=
socket_handler
.
get
();
event
.
events
=
EPOLLIN
;
struct
epoll_event
event
=
{
EPOLLIN
,
{
socket_handler
.
get
()}};
const
int
res
=
::
epoll_ctl
(
this
->
epfd
,
EPOLL_CTL_ADD
,
socket_handler
->
get_socket
(),
&
event
);
if
(
res
==
-
1
)
{
...
...
@@ -99,9 +96,7 @@ void Poller::watch_send_events(SocketHandler* socket_handler)
}
throw
std
::
runtime_error
(
"Cannot watch a non-registered socket for send events"
);
#elif POLLER == EPOLL
struct
epoll_event
event
;
event
.
data
.
ptr
=
socket_handler
;
event
.
events
=
EPOLLIN
|
EPOLLOUT
;
struct
epoll_event
event
=
{
EPOLLIN
|
EPOLLOUT
,
{
socket_handler
}};
const
int
res
=
::
epoll_ctl
(
this
->
epfd
,
EPOLL_CTL_MOD
,
socket_handler
->
get_socket
(),
&
event
);
if
(
res
==
-
1
)
{
...
...
@@ -124,9 +119,7 @@ void Poller::stop_watching_send_events(SocketHandler* socket_handler)
}
throw
std
::
runtime_error
(
"Cannot watch a non-registered socket for send events"
);
#elif POLLER == EPOLL
struct
epoll_event
event
;
event
.
data
.
ptr
=
socket_handler
;
event
.
events
=
EPOLLIN
;
struct
epoll_event
event
=
{
EPOLLIN
,
{
socket_handler
}};
const
int
res
=
::
epoll_ctl
(
this
->
epfd
,
EPOLL_CTL_MOD
,
socket_handler
->
get_socket
(),
&
event
);
if
(
res
==
-
1
)
{
...
...
@@ -136,21 +129,23 @@ void Poller::stop_watching_send_events(SocketHandler* socket_handler)
#endif
}
bool
Poller
::
poll
(
)
int
Poller
::
poll
(
const
std
::
chrono
::
milliseconds
&
timeout
)
{
if
(
this
->
socket_handlers
.
size
()
==
0
)
return
-
1
;
#if POLLER == POLL
if
(
this
->
nfds
==
0
)
return
false
;
int
res
=
::
poll
(
this
->
fds
,
this
->
nfds
,
-
1
);
if
(
res
<
0
)
int
nb_events
=
::
poll
(
this
->
fds
,
this
->
nfds
,
timeout
.
count
());
if
(
nb_events
<
0
)
{
if
(
errno
==
EINTR
)
return
true
;
perror
(
"poll"
);
throw
std
::
runtime_error
(
"Poll failed"
);
}
// We cannot possibly have more ready events than the number of fds we are
// watching
assert
(
static_cast
<
unsigned
int
>
(
re
s
)
<=
this
->
nfds
);
for
(
size_t
i
=
0
;
i
<=
this
->
nfds
&&
re
s
!=
0
;
++
i
)
assert
(
static_cast
<
unsigned
int
>
(
nb_event
s
)
<=
this
->
nfds
);
for
(
size_t
i
=
0
;
i
<=
this
->
nfds
&&
nb_event
s
!=
0
;
++
i
)
{
if
(
this
->
fds
[
i
].
revents
==
0
)
continue
;
...
...
@@ -158,21 +153,24 @@ bool Poller::poll()
{
auto
socket_handler
=
this
->
socket_handlers
.
at
(
this
->
fds
[
i
].
fd
);
socket_handler
->
on_recv
();
re
s
--
;
nb_event
s
--
;
}
else
if
(
this
->
fds
[
i
].
revents
&
POLLOUT
)
{
auto
socket_handler
=
this
->
socket_handlers
.
at
(
this
->
fds
[
i
].
fd
);
socket_handler
->
on_send
();
re
s
--
;
nb_event
s
--
;
}
}
return
1
;
#elif POLLER == EPOLL
static
const
size_t
max_events
=
12
;
struct
epoll_event
revents
[
max_events
];
const
int
nb_events
=
epoll_wait
(
this
->
epfd
,
revents
,
max_events
,
-
1
);
const
int
nb_events
=
::
epoll_wait
(
this
->
epfd
,
revents
,
max_events
,
timeout
.
count
()
);
if
(
nb_events
==
-
1
)
{
if
(
errno
==
EINTR
)
return
0
;
perror
(
"epoll_wait"
);
throw
std
::
runtime_error
(
"Epoll_wait failed"
);
}
...
...
@@ -184,6 +182,11 @@ bool Poller::poll()
if
(
revents
[
i
].
events
&
EPOLLOUT
)
socket_handler
->
on_send
();
}
return
nb_events
;
#endif
return
true
;
}
size_t
Poller
::
size
()
const
{
return
this
->
socket_handlers
.
size
();
}
src/network/poller.hpp
View file @
3afb63a6
...
...
@@ -5,6 +5,7 @@
#include <unordered_map>
#include <memory>
#include <chrono>
#define POLL 1
#define EPOLL 2
...
...
@@ -58,10 +59,17 @@ public:
void
stop_watching_send_events
(
SocketHandler
*
socket_handler
);
/**
* Wait for all watched events, and call the SocketHandlers' callbacks
* when one is ready.
* Returns false if there are 0 SocketHandler in the list.
* when one is ready. Returns if nothing happened before the provided
* timeout. If the timeout is 0, it waits forever. If there is no
* watched event, returns -1 immediately, ignoring the timeout value.
* Otherwise, returns the number of event handled. If 0 is returned this
* means that we were interrupted by a signal, or the timeout occured.
*/
bool
poll
();
int
poll
(
const
std
::
chrono
::
milliseconds
&
timeout
);
/**
* Returns the number of SocketHandlers managed by the poller.
*/
size_t
size
()
const
;
private:
/**
...
...
src/xmpp/xmpp_component.cpp
View file @
3afb63a6
...
...
@@ -24,7 +24,8 @@
XmppComponent
::
XmppComponent
(
const
std
::
string
&
hostname
,
const
std
::
string
&
secret
)
:
served_hostname
(
hostname
),
secret
(
secret
),
authenticated
(
false
)
authenticated
(
false
),
doc_open
(
false
)
{
this
->
parser
.
add_stream_open_callback
(
std
::
bind
(
&
XmppComponent
::
on_remote_stream_open
,
this
,
std
::
placeholders
::
_1
));
...
...
@@ -51,6 +52,11 @@ bool XmppComponent::start()
return
this
->
connect
(
"127.0.0.1"
,
"5347"
);
}
bool
XmppComponent
::
is_document_open
()
const
{
return
this
->
doc_open
;
}
void
XmppComponent
::
send_stanza
(
const
Stanza
&
stanza
)
{
std
::
string
str
=
stanza
.
to_string
();
...
...
@@ -66,6 +72,7 @@ void XmppComponent::on_connected()
node
[
"xmlns:stream"
]
=
STREAM_NS
;
node
[
"to"
]
=
this
->
served_hostname
;
this
->
send_stanza
(
node
);
this
->
doc_open
=
true
;
}
void
XmppComponent
::
on_connection_close
()
...
...
@@ -79,6 +86,14 @@ void XmppComponent::parse_in_buffer()
this
->
in_buf
.
clear
();
}
void
XmppComponent
::
shutdown
()
{
for
(
auto
it
=
this
->
bridges
.
begin
();
it
!=
this
->
bridges
.
end
();
++
it
)
{
it
->
second
->
shutdown
();
}
}
void
XmppComponent
::
on_remote_stream_open
(
const
XmlNode
&
node
)
{
log_debug
(
"XMPP DOCUMENT OPEN: "
<<
node
.
to_string
());
...
...
@@ -145,6 +160,7 @@ void XmppComponent::close_document()
{
log_debug
(
"XMPP SENDING: </stream:stream>"
);
this
->
send_data
(
"</stream:stream>"
);
this
->
doc_open
=
false
;
}
void
XmppComponent
::
handle_handshake
(
const
Stanza
&
stanza
)
...
...
src/xmpp/xmpp_component.hpp
View file @
3afb63a6
...
...
@@ -23,7 +23,14 @@ public:
void
on_connected
()
override
final
;
void
on_connection_close
()
override
final
;
void
parse_in_buffer
()
override
final
;
/**
* Send a "close" message to all our connected peers. That message
* depends on the protocol used (this may be a QUIT irc message, or a
* <stream/>, etc). We may also directly close the connection, or we may
* wait for the remote peer to acknowledge it before closing.
*/
void
shutdown
();
bool
is_document_open
()
const
;
/**
* Connect to the XMPP server.
* Returns false if we failed to connect
...
...
@@ -115,6 +122,10 @@ private:
std
::
string
served_hostname
;
std
::
string
secret
;
bool
authenticated
;
/**
* Whether or not OUR XMPP document is open
*/
bool
doc_open
;
std
::
unordered_map
<
std
::
string
,
std
::
function
<
void
(
const
Stanza
&
)
>>
stanza_handlers
;
...
...
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