Skip to content

Commit

Permalink
Merge pull request #9 from smlng/pr_fix_sigpipe
Browse files Browse the repository at this point in the history
handle sigpipe error
  • Loading branch information
waehlisch committed Jun 22, 2016
2 parents 99ec8fb + 01f4d11 commit 7f93ab0
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 99 deletions.
130 changes: 74 additions & 56 deletions bird-rtrlib-cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
* Website: https://github.com/rtrlib/bird-rtrlib-cli
*/

#include <errno.h>
#include <signal.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
Expand All @@ -30,44 +32,54 @@
#include "cli.h"
#include "config.h"
#include "rtr.h"
#include <rtrlib/rtrlib.h>

#define CMD_EXIT "exit"

#define BIRD_RSP_SIZE (200)
// Socket to BIRD.
static int bird_socket = -1;

// Buffer for BIRD commands.
static char *bird_command = 0;

// Length of buffer for BIRD commands.
static size_t bird_command_length = -1;

// "add roa" BIRD command "table" part. Defaults to an empty string and becomes
// "table " + config->bird_roa_table if provided.
static char *bird_add_roa_table_arg = "";
// Main configuration.
static struct config config;

/**
* Handle SIGPIPE on bird_socket, write error log entry
*/
void sigpipe_handler(int signum)
{
syslog(LOG_ERR, "Caught SIGPIPE %d.", signum);
}

/**
* Performs cleanup on resources allocated by `init()`.
*/
void cleanup(void) {
void cleanup(void)
{
closelog();
}

/**
* Frees memory allocated with the " table <bird_roa_table>" clause for the
* "add roa" BIRD command.
*/
void cleanup_bird_add_roa_table_arg(void) {
// If the buffer is "", it has never been changed, thus there is no malloc'd
// buffer.
void cleanup_bird_add_roa_table_arg(void)
{
// free buffer only, if not empty - i.e., mem was malloc'd
if (strcmp(bird_add_roa_table_arg, "") != 0)
free(bird_add_roa_table_arg);
}

/**
* Frees memory allocated with the BIRD command buffer.
*/
void cleanup_bird_command(void) {
void cleanup_bird_command(void)
{
if (bird_command) {
free(bird_command);
bird_command = 0;
Expand All @@ -78,29 +90,30 @@ void cleanup_bird_command(void) {
/**
* Initializes the application prerequisites.
*/
void init(void) {
void init(void)
{
openlog(NULL, LOG_PERROR | LOG_CONS | LOG_PID, LOG_DAEMON);
}

/**
* Creates and populates the "add roa" command's "table" argument buffer.
* @param bird_roa_table
*/
void init_bird_add_roa_table_arg(char *bird_roa_table) {
void init_bird_add_roa_table_arg(char *bird_roa_table)
{
// Size of the buffer (" table " + <roa_table> + \0).
const size_t length = (8 + strlen(bird_roa_table)) * sizeof (char);

// Allocate buffer.
bird_add_roa_table_arg = malloc(length);

// Populate buffer.
snprintf(bird_add_roa_table_arg, length, " table %s", bird_roa_table);
}

/**
* Creates the buffer for the "add roa" command.
*/
void init_bird_command(void) {
void init_bird_command(void)
{
// Size of the buffer ("add roa " + <addr> + "/" + <minlen> + " max " +
// <maxlen> + " as " + <asnum> + <bird_add_roa_table_cmd> + \0)
bird_command_length = (
Expand All @@ -115,7 +128,6 @@ void init_bird_command(void) {
strlen(bird_add_roa_table_arg) + // length of fixed " table " + <table>
1 // \0
) * sizeof (char);

// Allocate buffer.
bird_command = malloc(bird_command_length);
}
Expand All @@ -134,13 +146,10 @@ static void pfx_update_callback(struct pfx_table *table,
{
// IP address buffer.
static char ip_addr_str[INET6_ADDRSTRLEN];

// Buffer for BIRD response.
static char bird_response[200];

static char bird_response[BIRD_RSP_SIZE];
// Fetch IP address as string.
lrtr_ip_addr_to_str(&(record.prefix), ip_addr_str, sizeof(ip_addr_str));

// Write BIRD command to buffer.
if (
snprintf(
Expand All @@ -159,14 +168,28 @@ static void pfx_update_callback(struct pfx_table *table,
syslog(LOG_ERR, "BIRD command too long.");
return;
}

// Log the BIRD command and send it to the BIRD server.
syslog(LOG_INFO, "To BIRD: %s", bird_command);
write(bird_socket, bird_command, strlen(bird_command));

// Fetch the answer and log.
bird_response[read(bird_socket, bird_response, sizeof(bird_response)-1)] = 0;
syslog(LOG_INFO, "From BIRD: %s", bird_response);
// reconnect bird_socket on SIGPIPE error, and resend BIRD command
while ((write(bird_socket, bird_command, strlen(bird_command)) < 0) &&
(errno == EPIPE)) {
syslog(LOG_ERR, "BIRD socket send failed, try reconnect!");
close(bird_socket);
bird_socket = bird_connect(config.bird_socket_path);
}
// Fetch BIRD answer, reconnect bird_socket on SIGPIPE while receive
int size = -1;
while (((size = read(bird_socket, bird_response, BIRD_RSP_SIZE-1)) <0) &&
(errno == EPIPE)){
syslog(LOG_ERR, "BIRD socket recv failed, try reconnect!");
close(bird_socket);
bird_socket = bird_connect(config.bird_socket_path);
}
// log answer, if any valid response
if (size > 0) {
bird_response[size] = 0;
syslog(LOG_INFO, "From BIRD: %s", bird_response);
}
}

/**
Expand All @@ -175,53 +198,45 @@ static void pfx_update_callback(struct pfx_table *table,
* @param argv
* @return
*/
int main(int argc, char *argv[]) {
// Main configuration.
struct config config;

int main(int argc, char *argv[])
{
// Buffer for commands and its length.
char *command = 0;
size_t command_len = 0;

// Initialize variables.
config_init(&config);

// Initialize framework.
init();

// Parse CLI arguments into config and bail out on error.
if (!parse_cli(argc, argv, &config)) {
cleanup();
fprintf(stderr, "Invalid command line parameter!\n");
return EXIT_FAILURE;
}

// Check config.
if (!config_check(&config)) {
if (config_check(&config)) {
cleanup();
fprintf(stderr, "Invalid configuration parameters!\n");
return EXIT_FAILURE;
}

// Setup BIRD ROA table command argument.
if (config.bird_roa_table) {
init_bird_add_roa_table_arg(config.bird_roa_table);
}

// Setup BIRD command buffer.
init_bird_command();

// Try to connect to BIRD and bail out on failure.
bird_socket = bird_connect(config.bird_socket_path);
if (bird_socket == -1) {
cleanup();
fprintf(stderr, "Failed to connect to BIRD socket!\n");
return EXIT_FAILURE;
}

struct tr_socket tr_sock;
struct tr_tcp_config *tcp_config;
struct tr_ssh_config *ssh_config;

// Try to connect to the RTR server depending on the requested connection
// type.
// Try to connect to the RTR server depending on requested connection type.
switch (config.rtr_connection_type) {
case tcp:
tcp_config = rtr_create_tcp_config(
Expand All @@ -237,53 +252,56 @@ int main(int argc, char *argv[]) {
break;
default:
cleanup();
fprintf(stderr, "Invalid connection type, use tcp or ssh!\n");
return EXIT_FAILURE;
}

struct rtr_socket rtr;
struct rtr_mgr_config *conf;
struct rtr_mgr_group groups[1];

// init rtr_socket and groups
rtr.tr_socket = &tr_sock;
groups[0].sockets_len = 1;
groups[0].sockets = malloc(1 * sizeof(rtr));
groups[0].sockets[0] = &rtr;
groups[0].preference = 1;

// init rtr_mgr
int ret = rtr_mgr_init(&conf, groups, 1, 30, 600, 600,
pfx_update_callback, NULL, NULL, NULL);

if (ret == RTR_ERROR)
printf("Error in rtr_mgr_init!\n");
else if (ret == RTR_INVALID_PARAM)
printf("Invalid params passed to rtr_mgr_init\n");

if (!conf)
// check for init errors
if (ret == RTR_ERROR) {
fprintf(stderr, "Error in rtr_mgr_init!\n");
return EXIT_FAILURE;

}
else if (ret == RTR_INVALID_PARAM) {
fprintf(stderr, "Invalid params passed to rtr_mgr_init\n");
return EXIT_FAILURE;
}
// check if rtr_mgr config valid
if (!conf) {
fprintf(stderr, "No config for rtr manager!\n");
return EXIT_FAILURE;
}
// set handler for SIGPIPE
signal(SIGPIPE, sigpipe_handler);
// start rtr_mgr
rtr_mgr_start(conf);

// Server loop. Read commands from stdin.
while (getline(&command, &command_len, stdin) != -1) {
if (strncmp(command, CMD_EXIT, strlen(CMD_EXIT)) == 0)
break;
}

// Clean up RTRLIB memory.
rtr_mgr_stop(conf);
rtr_mgr_free(conf);
free(groups[0].sockets);

// Close BIRD socket.
close(bird_socket);

// Cleanup memory.
cleanup_bird_command();
cleanup_bird_add_roa_table_arg();

// Cleanup framework.
cleanup();

// Exit with success.
return EXIT_SUCCESS;
}
9 changes: 2 additions & 7 deletions bird.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,38 +27,33 @@

#include "bird.h"

int bird_connect(const char *socket_path) {
int bird_connect(const char *socket_path)
{
// Result value containing the socket to the BIRD.
int bird_socket = -1;

// Socket address to the BIRD.
struct sockaddr_un addr;

// Check socket path length.
if (strlen(socket_path) >= sizeof addr.sun_path) {
syslog(LOG_EMERG, "Socket path too long");
return -1;
}

// Create socket and bail out on error.
bird_socket = socket(AF_UNIX, SOCK_STREAM, 0);
if (bird_socket < 0) {
syslog(LOG_EMERG, "Socket creation error: %m");
return -1;
}

// Create socket address.
memset(&addr, 0, sizeof addr);
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, socket_path);

// Try to connect to BIRD.
if (connect(bird_socket, (struct sockaddr *) &addr, sizeof addr) == -1) {
syslog(LOG_EMERG, "BIRD connection to %s failed: %m", socket_path);
close(bird_socket);
return -1;
}

// Return socket.
return bird_socket;
}
11 changes: 4 additions & 7 deletions cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@
#define ARGKEY_RTRSSH_USERNAME 0x103

// Parser function for argp_parse().
static error_t argp_parser(int key, char *arg, struct argp_state *state) {
static error_t argp_parser(int key, char *arg, struct argp_state *state)
{
// Shortcut to config object passed to argp_parse().
struct config *config = state->input;

// Process command line argument.
switch (key) {
case ARGKEY_BIRD_ROA_TABLE:
Expand Down Expand Up @@ -71,13 +71,13 @@ static error_t argp_parser(int key, char *arg, struct argp_state *state) {
// Process unknown argument.
return ARGP_ERR_UNKNOWN;
}

// Return success.
return 0;
}

// Parses the specified command line arguments into the program config.
int parse_cli(int argc, char **argv, struct config *config) {
int parse_cli(int argc, char **argv, struct config *config)
{
// Command line options definition.
const struct argp_option argp_options[] = {
{
Expand Down Expand Up @@ -150,7 +150,6 @@ int parse_cli(int argc, char **argv, struct config *config) {
},
{0}
};

// argp structure to be passed to argp_parse().
const struct argp argp = {
argp_options,
Expand All @@ -161,10 +160,8 @@ int parse_cli(int argc, char **argv, struct config *config) {
NULL,
NULL
};

// Parse command line. Exits on errors.
argp_parse(&argp, argc, argv, 0, NULL, config);

// Return success.
return 1;
}
Loading

0 comments on commit 7f93ab0

Please sign in to comment.