Skip to content

Commit 7f93ab0

Browse files
authored
Merge pull request #9 from smlng/pr_fix_sigpipe
handle sigpipe error
2 parents 99ec8fb + 01f4d11 commit 7f93ab0

File tree

6 files changed

+98
-99
lines changed

6 files changed

+98
-99
lines changed

bird-rtrlib-cli.c

+74-56
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
* Website: https://github.com/rtrlib/bird-rtrlib-cli
2020
*/
2121

22+
#include <errno.h>
23+
#include <signal.h>
2224
#include <stddef.h>
2325
#include <stdio.h>
2426
#include <stdlib.h>
@@ -30,44 +32,54 @@
3032
#include "cli.h"
3133
#include "config.h"
3234
#include "rtr.h"
35+
#include <rtrlib/rtrlib.h>
3336

3437
#define CMD_EXIT "exit"
35-
38+
#define BIRD_RSP_SIZE (200)
3639
// Socket to BIRD.
3740
static int bird_socket = -1;
38-
3941
// Buffer for BIRD commands.
4042
static char *bird_command = 0;
41-
4243
// Length of buffer for BIRD commands.
4344
static size_t bird_command_length = -1;
44-
4545
// "add roa" BIRD command "table" part. Defaults to an empty string and becomes
4646
// "table " + config->bird_roa_table if provided.
4747
static char *bird_add_roa_table_arg = "";
48+
// Main configuration.
49+
static struct config config;
50+
51+
/**
52+
* Handle SIGPIPE on bird_socket, write error log entry
53+
*/
54+
void sigpipe_handler(int signum)
55+
{
56+
syslog(LOG_ERR, "Caught SIGPIPE %d.", signum);
57+
}
4858

4959
/**
5060
* Performs cleanup on resources allocated by `init()`.
5161
*/
52-
void cleanup(void) {
62+
void cleanup(void)
63+
{
5364
closelog();
5465
}
5566

5667
/**
5768
* Frees memory allocated with the " table <bird_roa_table>" clause for the
5869
* "add roa" BIRD command.
5970
*/
60-
void cleanup_bird_add_roa_table_arg(void) {
61-
// If the buffer is "", it has never been changed, thus there is no malloc'd
62-
// buffer.
71+
void cleanup_bird_add_roa_table_arg(void)
72+
{
73+
// free buffer only, if not empty - i.e., mem was malloc'd
6374
if (strcmp(bird_add_roa_table_arg, "") != 0)
6475
free(bird_add_roa_table_arg);
6576
}
6677

6778
/**
6879
* Frees memory allocated with the BIRD command buffer.
6980
*/
70-
void cleanup_bird_command(void) {
81+
void cleanup_bird_command(void)
82+
{
7183
if (bird_command) {
7284
free(bird_command);
7385
bird_command = 0;
@@ -78,29 +90,30 @@ void cleanup_bird_command(void) {
7890
/**
7991
* Initializes the application prerequisites.
8092
*/
81-
void init(void) {
93+
void init(void)
94+
{
8295
openlog(NULL, LOG_PERROR | LOG_CONS | LOG_PID, LOG_DAEMON);
8396
}
8497

8598
/**
8699
* Creates and populates the "add roa" command's "table" argument buffer.
87100
* @param bird_roa_table
88101
*/
89-
void init_bird_add_roa_table_arg(char *bird_roa_table) {
102+
void init_bird_add_roa_table_arg(char *bird_roa_table)
103+
{
90104
// Size of the buffer (" table " + <roa_table> + \0).
91105
const size_t length = (8 + strlen(bird_roa_table)) * sizeof (char);
92-
93106
// Allocate buffer.
94107
bird_add_roa_table_arg = malloc(length);
95-
96108
// Populate buffer.
97109
snprintf(bird_add_roa_table_arg, length, " table %s", bird_roa_table);
98110
}
99111

100112
/**
101113
* Creates the buffer for the "add roa" command.
102114
*/
103-
void init_bird_command(void) {
115+
void init_bird_command(void)
116+
{
104117
// Size of the buffer ("add roa " + <addr> + "/" + <minlen> + " max " +
105118
// <maxlen> + " as " + <asnum> + <bird_add_roa_table_cmd> + \0)
106119
bird_command_length = (
@@ -115,7 +128,6 @@ void init_bird_command(void) {
115128
strlen(bird_add_roa_table_arg) + // length of fixed " table " + <table>
116129
1 // \0
117130
) * sizeof (char);
118-
119131
// Allocate buffer.
120132
bird_command = malloc(bird_command_length);
121133
}
@@ -134,13 +146,10 @@ static void pfx_update_callback(struct pfx_table *table,
134146
{
135147
// IP address buffer.
136148
static char ip_addr_str[INET6_ADDRSTRLEN];
137-
138149
// Buffer for BIRD response.
139-
static char bird_response[200];
140-
150+
static char bird_response[BIRD_RSP_SIZE];
141151
// Fetch IP address as string.
142152
lrtr_ip_addr_to_str(&(record.prefix), ip_addr_str, sizeof(ip_addr_str));
143-
144153
// Write BIRD command to buffer.
145154
if (
146155
snprintf(
@@ -159,14 +168,28 @@ static void pfx_update_callback(struct pfx_table *table,
159168
syslog(LOG_ERR, "BIRD command too long.");
160169
return;
161170
}
162-
163171
// Log the BIRD command and send it to the BIRD server.
164172
syslog(LOG_INFO, "To BIRD: %s", bird_command);
165-
write(bird_socket, bird_command, strlen(bird_command));
166-
167-
// Fetch the answer and log.
168-
bird_response[read(bird_socket, bird_response, sizeof(bird_response)-1)] = 0;
169-
syslog(LOG_INFO, "From BIRD: %s", bird_response);
173+
// reconnect bird_socket on SIGPIPE error, and resend BIRD command
174+
while ((write(bird_socket, bird_command, strlen(bird_command)) < 0) &&
175+
(errno == EPIPE)) {
176+
syslog(LOG_ERR, "BIRD socket send failed, try reconnect!");
177+
close(bird_socket);
178+
bird_socket = bird_connect(config.bird_socket_path);
179+
}
180+
// Fetch BIRD answer, reconnect bird_socket on SIGPIPE while receive
181+
int size = -1;
182+
while (((size = read(bird_socket, bird_response, BIRD_RSP_SIZE-1)) <0) &&
183+
(errno == EPIPE)){
184+
syslog(LOG_ERR, "BIRD socket recv failed, try reconnect!");
185+
close(bird_socket);
186+
bird_socket = bird_connect(config.bird_socket_path);
187+
}
188+
// log answer, if any valid response
189+
if (size > 0) {
190+
bird_response[size] = 0;
191+
syslog(LOG_INFO, "From BIRD: %s", bird_response);
192+
}
170193
}
171194

172195
/**
@@ -175,53 +198,45 @@ static void pfx_update_callback(struct pfx_table *table,
175198
* @param argv
176199
* @return
177200
*/
178-
int main(int argc, char *argv[]) {
179-
// Main configuration.
180-
struct config config;
181-
201+
int main(int argc, char *argv[])
202+
{
182203
// Buffer for commands and its length.
183204
char *command = 0;
184205
size_t command_len = 0;
185-
186206
// Initialize variables.
187207
config_init(&config);
188-
189208
// Initialize framework.
190209
init();
191-
192210
// Parse CLI arguments into config and bail out on error.
193211
if (!parse_cli(argc, argv, &config)) {
194212
cleanup();
213+
fprintf(stderr, "Invalid command line parameter!\n");
195214
return EXIT_FAILURE;
196215
}
197-
198216
// Check config.
199-
if (!config_check(&config)) {
217+
if (config_check(&config)) {
200218
cleanup();
219+
fprintf(stderr, "Invalid configuration parameters!\n");
201220
return EXIT_FAILURE;
202221
}
203-
204222
// Setup BIRD ROA table command argument.
205223
if (config.bird_roa_table) {
206224
init_bird_add_roa_table_arg(config.bird_roa_table);
207225
}
208-
209226
// Setup BIRD command buffer.
210227
init_bird_command();
211-
212228
// Try to connect to BIRD and bail out on failure.
213229
bird_socket = bird_connect(config.bird_socket_path);
214230
if (bird_socket == -1) {
215231
cleanup();
232+
fprintf(stderr, "Failed to connect to BIRD socket!\n");
216233
return EXIT_FAILURE;
217234
}
218235

219236
struct tr_socket tr_sock;
220237
struct tr_tcp_config *tcp_config;
221238
struct tr_ssh_config *ssh_config;
222-
223-
// Try to connect to the RTR server depending on the requested connection
224-
// type.
239+
// Try to connect to the RTR server depending on requested connection type.
225240
switch (config.rtr_connection_type) {
226241
case tcp:
227242
tcp_config = rtr_create_tcp_config(
@@ -237,53 +252,56 @@ int main(int argc, char *argv[]) {
237252
break;
238253
default:
239254
cleanup();
255+
fprintf(stderr, "Invalid connection type, use tcp or ssh!\n");
240256
return EXIT_FAILURE;
241257
}
242258

243259
struct rtr_socket rtr;
244260
struct rtr_mgr_config *conf;
245261
struct rtr_mgr_group groups[1];
246-
262+
// init rtr_socket and groups
247263
rtr.tr_socket = &tr_sock;
248264
groups[0].sockets_len = 1;
249265
groups[0].sockets = malloc(1 * sizeof(rtr));
250266
groups[0].sockets[0] = &rtr;
251267
groups[0].preference = 1;
252-
268+
// init rtr_mgr
253269
int ret = rtr_mgr_init(&conf, groups, 1, 30, 600, 600,
254270
pfx_update_callback, NULL, NULL, NULL);
255-
256-
if (ret == RTR_ERROR)
257-
printf("Error in rtr_mgr_init!\n");
258-
else if (ret == RTR_INVALID_PARAM)
259-
printf("Invalid params passed to rtr_mgr_init\n");
260-
261-
if (!conf)
271+
// check for init errors
272+
if (ret == RTR_ERROR) {
273+
fprintf(stderr, "Error in rtr_mgr_init!\n");
262274
return EXIT_FAILURE;
263-
275+
}
276+
else if (ret == RTR_INVALID_PARAM) {
277+
fprintf(stderr, "Invalid params passed to rtr_mgr_init\n");
278+
return EXIT_FAILURE;
279+
}
280+
// check if rtr_mgr config valid
281+
if (!conf) {
282+
fprintf(stderr, "No config for rtr manager!\n");
283+
return EXIT_FAILURE;
284+
}
285+
// set handler for SIGPIPE
286+
signal(SIGPIPE, sigpipe_handler);
287+
// start rtr_mgr
264288
rtr_mgr_start(conf);
265-
266289
// Server loop. Read commands from stdin.
267290
while (getline(&command, &command_len, stdin) != -1) {
268291
if (strncmp(command, CMD_EXIT, strlen(CMD_EXIT)) == 0)
269292
break;
270293
}
271-
272294
// Clean up RTRLIB memory.
273295
rtr_mgr_stop(conf);
274296
rtr_mgr_free(conf);
275297
free(groups[0].sockets);
276-
277298
// Close BIRD socket.
278299
close(bird_socket);
279-
280300
// Cleanup memory.
281301
cleanup_bird_command();
282302
cleanup_bird_add_roa_table_arg();
283-
284303
// Cleanup framework.
285304
cleanup();
286-
287305
// Exit with success.
288306
return EXIT_SUCCESS;
289307
}

bird.c

+2-7
Original file line numberDiff line numberDiff line change
@@ -27,38 +27,33 @@
2727

2828
#include "bird.h"
2929

30-
int bird_connect(const char *socket_path) {
30+
int bird_connect(const char *socket_path)
31+
{
3132
// Result value containing the socket to the BIRD.
3233
int bird_socket = -1;
33-
3434
// Socket address to the BIRD.
3535
struct sockaddr_un addr;
36-
3736
// Check socket path length.
3837
if (strlen(socket_path) >= sizeof addr.sun_path) {
3938
syslog(LOG_EMERG, "Socket path too long");
4039
return -1;
4140
}
42-
4341
// Create socket and bail out on error.
4442
bird_socket = socket(AF_UNIX, SOCK_STREAM, 0);
4543
if (bird_socket < 0) {
4644
syslog(LOG_EMERG, "Socket creation error: %m");
4745
return -1;
4846
}
49-
5047
// Create socket address.
5148
memset(&addr, 0, sizeof addr);
5249
addr.sun_family = AF_UNIX;
5350
strcpy(addr.sun_path, socket_path);
54-
5551
// Try to connect to BIRD.
5652
if (connect(bird_socket, (struct sockaddr *) &addr, sizeof addr) == -1) {
5753
syslog(LOG_EMERG, "BIRD connection to %s failed: %m", socket_path);
5854
close(bird_socket);
5955
return -1;
6056
}
61-
6257
// Return socket.
6358
return bird_socket;
6459
}

cli.c

+4-7
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@
3535
#define ARGKEY_RTRSSH_USERNAME 0x103
3636

3737
// Parser function for argp_parse().
38-
static error_t argp_parser(int key, char *arg, struct argp_state *state) {
38+
static error_t argp_parser(int key, char *arg, struct argp_state *state)
39+
{
3940
// Shortcut to config object passed to argp_parse().
4041
struct config *config = state->input;
41-
4242
// Process command line argument.
4343
switch (key) {
4444
case ARGKEY_BIRD_ROA_TABLE:
@@ -71,13 +71,13 @@ static error_t argp_parser(int key, char *arg, struct argp_state *state) {
7171
// Process unknown argument.
7272
return ARGP_ERR_UNKNOWN;
7373
}
74-
7574
// Return success.
7675
return 0;
7776
}
7877

7978
// Parses the specified command line arguments into the program config.
80-
int parse_cli(int argc, char **argv, struct config *config) {
79+
int parse_cli(int argc, char **argv, struct config *config)
80+
{
8181
// Command line options definition.
8282
const struct argp_option argp_options[] = {
8383
{
@@ -150,7 +150,6 @@ int parse_cli(int argc, char **argv, struct config *config) {
150150
},
151151
{0}
152152
};
153-
154153
// argp structure to be passed to argp_parse().
155154
const struct argp argp = {
156155
argp_options,
@@ -161,10 +160,8 @@ int parse_cli(int argc, char **argv, struct config *config) {
161160
NULL,
162161
NULL
163162
};
164-
165163
// Parse command line. Exits on errors.
166164
argp_parse(&argp, argc, argv, 0, NULL, config);
167-
168165
// Return success.
169166
return 1;
170167
}

0 commit comments

Comments
 (0)