#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <stdlib.h>
#include <regex.h>
#include <sys/time.h> /* needed for Linux */
#include <irrd_ops.h>
#include <hdr_comm.h>
#include <pgp.h>
static char *start_irrd_session (trace_t *tr, int sockfd);
static int read_socket_obj (trace_t *tr, int sockfd, FILE *fobj, int obj_size,
int len, int max_line_size);
/* JP moved to irrd_ops.h */
/*static char *send_socket_cmd (trace_t *tr, int fd, char *cmd);*/
/*static char *read_socket_cmd (trace_t *tr, int fd, char *response);*/
static char *send_transaction (trace_t *tr, char *warn_tag, int fd, char *op,
char *source, FILE *fin);
static char *send_object (trace_t *, FILE *, int, char *);
/* open connection */
int open_connection (trace_t *tr, char *IRRd_HOST, int IRRd_PORT) {
int sockfd;
struct sockaddr_in servaddr;
struct hostent *hoste;
unsigned long addr;
trace (TR_TRACE, tr, "open_connection %s:%d\n", IRRd_HOST, IRRd_PORT);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family= AF_INET;
servaddr.sin_port = htons(IRRd_PORT);
/* don't you love how gethostbyname is too stupid to accept numeric
addresses? grrrr. */
addr = inet_addr(IRRd_HOST);
if ((signed long) addr == -1) {
if ((hoste = gethostbyname(IRRd_HOST)) == NULL) {
trace (NORM, tr,
"open_connection () ERROR resolving %s: (%s)\n",
IRRd_HOST, strerror (errno));
return -1;
}
memcpy(&addr, hoste->h_addr_list[0], sizeof(struct in_addr));
}
servaddr.sin_addr.s_addr = addr;
if (-1 == connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr))) {
trace (NORM, tr, "ERROR opening IRRd TCP connection \n");
return -1;
}
return sockfd;
}
/* close connection */
int close_connection (int fd) {
close (fd);
return 1;
}
char *send_socket_cmd (trace_t *tr, int fd, char *cmd) {
fd_set write_fds;
struct timeval tv;
if (fd < 0)
return "\"System error: send_socket_cmd () broken IRRd pipe.\"\n";
/* fprintf (stderr, "send_socket_cmd () cmd len (%d)\n", strlen(cmd)); */
FD_ZERO(&write_fds);
FD_SET(fd, &write_fds);
tv.tv_sec = 3;
tv.tv_usec = 0;
if (select (fd + 1, 0, &write_fds, 0, &tv) < 1) {
trace (ERROR, tr, "send_socket_cmd () write time out!\n");
return "\"System error: IRRd write timeout. IRRd down or connectivity problems.\"\n";
}
if (write (fd, cmd, strlen (cmd)) < 0) {
trace (ERROR, tr, "send_socket_cmd () write error (%s)\n", strerror(errno));
return "\"System error: IRRd socket write error.\"\n";
}
return NULL;
}
/*
* Read something back from IRRd. If you don't care
* about the return code from IRRd set response = NULL.
* Otherwise, set *response to what you are expecting
* from IRRd (eg, "C\n"). If the response does not match,
* the function will return the entire IRRd response line.
*
* Return codes:
* NULL means *response matched IRRd's response
* otherwise return IRRd response.
*/
char *read_socket_cmd (trace_t *tr, int fd, char *response) {
char buf[MAXLINE];
int n;
fd_set read_fds;
struct timeval tv;
if (fd < 0)
return "\"System error: read_socket_cmd () broken IRRd pipe.\"\n";
FD_ZERO (&read_fds);
FD_SET (fd, &read_fds);
tv.tv_sec = 1;
tv.tv_usec = 0;
if (select (fd + 1, 0, &read_fds, 0, &tv) < 1) {
trace (ERROR, tr, "read_socket_cmd () read time out!\n");
return "Read timeout. Remote host is down or connectivity problems.";
}
n = read (fd, buf, MAXLINE - 1);
if (response == NULL)
return NULL;
if (n <= 0) {
trace (ERROR, tr, "read_socket_cmd () read error (%s)!\n", strerror (errno));
return "\"System error: Read IRRd socket error.\"\n";
}
buf[n] = '\0';
if (strncmp (buf, response, strlen (response)))
return strdup (buf);
return NULL;
}
/*
* Read a single line terminated by a '\n'. 'bufsize' should be >= 2
* or else function will return an error. The function pads the line
* with a '\0' null byte string terminator.
*
* Return:
* number of characters read.
*/
int read_socket_line (trace_t *tr, int sockfd, char buf[], int bufsize) {
int n = 0, x = 0, i;
fd_set read_fds;
struct timeval tv;
if (sockfd < 0) {
trace (ERROR, tr, "System error: read_socket_line () broken IRRd pipe.\n");
return -1;
}
FD_ZERO(&read_fds);
FD_SET(sockfd, &read_fds);
tv.tv_sec = 1;
tv.tv_usec = 0;
for (i = bufsize - 1; i > 0; i--) {
if (select (sockfd + 1, 0, &read_fds, 0, &tv) < 1) {
trace (ERROR, tr, "read_socket_line () read time out!\n");
return -1;
}
if ((x = read (sockfd, &buf[n], 1)) <= 0 ||
buf[n++] == '\n')
break;
}
buf[n] = '\0';
if (x <= 0) {
trace (ERROR, tr,
"read_socket_line () read (%d) bytes and did not get a '\\n', buffer size (%d)\n", n, bufsize);
return -1;
}
/*
fprintf (dfile, "read_socket_line () irrd:(%s)\n", buf);
*/
return n;
}
/* JW: need to check this routine for bug: if an object submission
* exceeds the 'max_line_size' then SNIP_MSG could be inserted into
* the object and written to the DB. Not sure if this is can happen or not.
*/
/* Read a DB object into file 'fobj'. We have already read the 'A...'
* answer length specifier, 'len', and are now reading the object data.
* 'obj_size' can be either 'FULL_OBJECT' or 'SHORT_OBJECT'. 'SHORT_OBJECT'
* will retrieve select fields only to minimize the amount of processing
* and disk space needed. For example, irr_auth only needs the maintainer
* references, auth fields, etc... Some aut-num objects can be as large
* as 25Mb so a definite savings is possible.
*
* Return:
* -1 means the 'A...'/'len' specifier did not match or a socket
* error occured.
* 1 object was successfully read and saved to file.
*/
int read_socket_obj (trace_t *tr, int sockfd, FILE *fobj, int obj_size,
int len, int max_line_size) {
char buf[MAXLINE];
int n, print_snip = 1;
int dump_line = 0, line_cont = 0, line_begin;
while (len > 0) {
if ((n = read_socket_line (tr, sockfd, buf, MAXLINE)) <= 0)
return -1;
len -= n;
if ((line_begin = !line_cont))
dump_line = 0;
line_cont = (buf[n - 1] != '\n');
if (dump_line ||
(line_begin && ((--max_line_size < 0 || obj_size == SHORT_OBJECT) &&
!(is_upd_to (buf) ||
is_mnt_nfy (buf) ||
is_notify (buf) ||
is_auth (buf) ||
is_mnt_by (buf) ||
is_changed (buf) ||
is_source (buf))))) {
if (print_snip && max_line_size < 0) {
fwrite (SNIP_MSG, 1, strlen (SNIP_MSG), fobj);
print_snip = 0;
}
dump_line = 1;
continue;
}
if (fwrite (buf, 1, n, fobj) < n) {
trace (ERROR, tr, "read_socket_obj () write file error: (%s)\n", strerror (errno));
return -1;
}
}
/* read the IRRd 'C\n' return code */
read_socket_line (tr, sockfd, buf, MAXLINE);
return 1;
}
/* send '!!' */
char *start_irrd_session (trace_t *tr, int sockfd) {
return send_socket_cmd (tr, sockfd, "!!\n");
}
/* send '!q' */
char *end_irrd_session (trace_t *tr, int sockfd) {
return send_socket_cmd (tr, sockfd, "!q\n");
}
/* Send a
* !us<DB>
* <OPERATION>
*
*...<object>...
*
* !ue
*
* Return:
* Char return line from IRRd.
* Char error line from this routine if
* a system or network error occurs.
* NULL if routine encounters something
* other than ADD or DEL (NOOP?). NULL
* means nothing was sent.
*/
char *send_transaction (trace_t *tr, char *warn_tag, int fd, char *op,
char *source, FILE *fin) {
char buf[MAXLINE], *ret_code;
int line_cont, line_begin, n;
sprintf (buf, "!us%s\n", source);
if (!strcmp (op, ADD_OP) || !strcmp (op, REPLACE_OP)) {
/*fprintf (tr, "!us%s\n", source );*/
if ((ret_code = send_socket_cmd (tr, fd, buf)) != NULL)
return ret_code;
if ((ret_code = read_socket_cmd (tr, fd, "C\n")) != NULL)
return ret_code;
if ((ret_code = send_socket_cmd (tr, fd, "ADD\n")) != NULL ||
(ret_code = send_socket_cmd (tr, fd, "\n")) != NULL)
return ret_code;
}
else if (!strcmp (op, DEL_OP)) {
/*fprintf (dfile, "!us%s\nDEL\n\n", source);*/
if ((ret_code = send_socket_cmd (tr, fd, buf)) != NULL)
return ret_code;
if ((ret_code = read_socket_cmd (tr, fd, "C\n")) != NULL)
return ret_code;
if ((ret_code = send_socket_cmd (tr, fd, "DEL\n")) != NULL ||
(ret_code = send_socket_cmd (tr, fd, "\n")) != NULL)
return ret_code;
}
else /* Must be a NOOP, don't do anything.
* We should never get here, calling routine
* should recognize NOOP's and skip.
*/
return NULL;
line_cont = 0; /* line cont in the fgets () sense, not in the rpsl sense
* ie, the current input line was larger than our memory
* buffer
*/
while (fgets (buf, MAXLINE - 1, fin) != NULL) {
n = strlen (buf);
line_begin = !line_cont;
line_cont = (buf[n - 1] != '\n');
if (line_begin && !strncmp (buf, warn_tag, strlen (warn_tag)))
continue;
if ((ret_code = send_socket_cmd (tr, fd, buf)) != NULL)
return ret_code;
if (line_begin && buf[0] == '\n') /* looking for a blank line */
break;
}
/*fprintf (dfile, "!ue\n");
printf ("send !ue...\n");
*/
if ((ret_code = send_socket_cmd (tr, fd, "!ue\n")) != NULL)
return ret_code;
if ((ret_code = read_socket_cmd (tr, fd, "C\n")) != NULL) {
/*
printf ("send_trans (): exit bad return code (%s)", ret_code);
*/
return ret_code;
}
/*
printf ("send_trans: exit good return code (%s)", "C\n");
*/
return "C\n";
}
/* Send an IRRd transaction (ie, !us...!ue).
* Function expects file position pointer to
* be at the start of the object.
*
* Return:
*
* Char *response/return code from IRRd
* Char *line from this routine if the IRRd
* socket could not be opened succesfully.
*/
char *irrd_transaction (trace_t *tr, char *warn_tag, int *socketfd, FILE *fin,
char *op, char *source, int num_trans, int *open_conn,
char *IRRd_HOST, int IRRd_PORT) {
char *ret_code;
if (num_trans == 1) {
/* Open connection */
if ((*socketfd = open_connection (tr, IRRd_HOST, IRRd_PORT)) < 0)
return "\"System error: Open socket () error!\"\n";
*open_conn = 1;
if ((ret_code = start_irrd_session (tr, *socketfd)) != NULL)
return ret_code;
}
return send_transaction (tr, warn_tag, *socketfd, op, source, fin);
}
/* Send a single object from the irr_submit pipeline file to IRRd.
* Object is canonicalized and ready for DB inclusion.
*
* Need to add comments.
*/
char *send_object (trace_t *tr, FILE *fin, int fd, char *warn_tag) {
char buf[MAXLINE], *ret_code;
int line_cont, line_begin, n;
line_cont = 0; /* line cont in the fgets () sense, not in the rpsl sense
* ie, the current input line was larger than our memory
* buffer
*/
while (fgets (buf, MAXLINE - 1, fin) != NULL) {
n = strlen (buf);
line_begin = !line_cont;
line_cont = (buf[n - 1] != '\n');
if (line_begin && !strncmp (buf, warn_tag, strlen (warn_tag)))
continue;
if ((ret_code = send_socket_cmd (tr, fd, buf)) != NULL)
return ret_code;
if (line_begin && buf[0] == '\n') /* looking for a blank line */
break;
}
return NULL;
}
/* Send RPS-DIST a transaction. The format of the message sent
* to RPS-DIST is as follows:
*
* !us<db source>
* <!us...!ue file name for IRRd>
* <pgp updates file name of "NULL">
* <journal entry file name>
* !ue
*
* RPS-DIST will responsd with current serial value of the current
* transaction. The "cs" value can be used to query IRRd should
* we timeout/RPS-DIST become unreachable.
*
* This routine expects one more message from RPS-DIST which is
* the return code from IRRd, ie, a "C" to signify the transaction
* was committed or a 'F...' which means the transaction was not
* committed and a text message is given.
*
* Input:
* -the IRRd !us...!ue transaction file name (irrdfn)
* -the pgp updates file name (pgpfn)
* -the journal entry file name (jentryfn)
* -the RPS-DIST host and port (RPSDIST_HOST,RPSDIST_PORT)
*
* Return:
* -"C\n" which means the transaction was committed without error
* -"current serial" which means we lost contact or timed out with
* RPS-DIST and irr_submit can use this value to contact IRRd to find
* out the transaction outcome
* -otherwise a text message is returned that explains an error
* note that a text message does not indicate the transaction
* aborted. For example we could timeout yet the transaction
* could end up committing.
*/
char *rpsdist_transaction (trace_t *tr, char *irrdfn, char *pgpfn,
char *jentryfn, char *source, char *RPSDIST_HOST,
int RPSDIST_PORT) {
int fd;
char buf[MAXLINE], cs[25], *ret_code = NULL;
/* Open an IRRd connection */
if ((fd = open_connection (tr, RPSDIST_HOST, RPSDIST_PORT)) < 0)
return "\"System error: RPSDIST open socket () error!\"\n";
/* Send the !us<db> */
sprintf (buf, "!us%s\n", source);
if ((ret_code = send_socket_cmd (tr, fd, buf)) != NULL)
goto CLOSE_CONN;
/* Send the irrd !us...!ue file name */
strcpy (buf, irrdfn);
strcat (buf, "\n");
if ((ret_code = send_socket_cmd (tr, fd, buf)) != NULL)
goto CLOSE_CONN;
/* Send the pgp update file name */
strcpy (buf, pgpfn);
strcat (buf, "\n");
if ((ret_code = send_socket_cmd (tr, fd, buf)) != NULL)
goto CLOSE_CONN;
/* Send the journal entry file name */
strcpy (buf, jentryfn);
strcat (buf, "\n");
if ((ret_code = send_socket_cmd (tr, fd, buf)) != NULL)
goto CLOSE_CONN;
/* Send the !ue to terminate the transaction */
if ((ret_code = send_socket_cmd (tr, fd, "!ue\n")) != NULL)
goto CLOSE_CONN;
/* Expecting the current serial of the transaction from RPS-DIST */
ret_code = read_socket_cmd (tr, fd, "^|@");
/* Sanity check */
if (ret_code == NULL) {
trace (ERROR, tr, "rpsdist_trans () NULL response from RPSDIST. Expecting 'cs' or error message. Abort transaction!");
ret_code = strdup ("NULL response from RPSDIST, transaction outcome not known.");
goto CLOSE_CONN;
}
if (*ret_code < '0' || *ret_code >'9') {
trace (ERROR, tr, "rpsdist_trans () Error message from RPS-DIST. Expected current serial. Aborting transaction! (%s)", ret_code);
goto CLOSE_CONN;
}
else
trace (NORM, tr, "rpsdist_trans () current serial (%s)", ret_code);
/* save the current serial */
strcpy (cs, ret_code);
/* Expecting a "C\n" return code to signify IRRd committed the trans */
if ((ret_code = read_socket_cmd (tr, fd, "C\n")) != NULL) {
trace (ERROR, tr, "rpsdist_trans () Error message from RPS-DIST. Expected 'C'. (%s)", ret_code);
/* Something went wrong, irr_submit should contact IRRd to find out the
* transaction outcome. irr_submit will use the current serial
* to query IRRd */
ret_code = strdup (cs);
}
else
ret_code = "C\n";
CLOSE_CONN:
close_connection (fd);
trace (NORM, tr, "exit rps_dist_trans ()\n");
return ret_code;
}
char *irrd_transaction_new (trace_t *tr, char *warn_tag, FILE *fin,
ret_info_t *start, char *IRRd_HOST, int IRRd_PORT) {
int fd;
irrd_result_t *p;
char buf[MAXLINE], *ret_code = NULL;
/* Open an IRRd connection */
if ((fd = open_connection (tr, IRRd_HOST, IRRd_PORT)) < 0)
return "\"System error: Open socket () error!\"\n";
/* Stay open mode !! */
if ((ret_code = send_socket_cmd (tr, fd, "!!\n")) != NULL)
goto CLOSE_CONN;
trace (NORM, tr, "send !us\n");
/* Send the !us<db> */
sprintf (buf, "!us%s\n", start->first->source);
if ((ret_code = send_socket_cmd (tr, fd, buf)) != NULL ||
(ret_code = read_socket_cmd (tr, fd, "C\n")) != NULL)
goto CLOSE_CONN;
trace (NORM, tr, "send first object\n");
/* Send the objects */
for (p = start->first; p != NULL; p = p->next) {
trace (NORM, tr, "top of loop\n");
/* Skip if we have a NOOP object */
if (p->svr_res & NOOP_RESULT) {
trace (NORM, tr, "NOOP submission. Object not added to IRRd.\n");
continue;
}
/* seek to the beginning of object */
fseek (fin, p->offset, SEEK_SET);
trace (NORM, tr, "send operator\n");
/* Send the operator */
if (!strcmp (p->op, DEL_OP)) {
if ((ret_code = send_socket_cmd (tr, fd, "DEL\n\n")) != NULL)
goto CLOSE_CONN;
}
else if ((ret_code = send_socket_cmd (tr, fd, "ADD\n\n")) != NULL)
goto CLOSE_CONN;
trace (NORM, tr, "send object\n");
/* Send the object */
send_object (tr, fin, fd, warn_tag);
trace (NORM, tr, "end object\n");
}
trace (NORM, tr, "send !ue\n");
/* Send the !ue to terminate the transaction */
if ((ret_code = send_socket_cmd (tr, fd, "!ue\n")) != NULL ||
(ret_code = read_socket_cmd (tr, fd, "C\n")) != NULL)
goto CLOSE_CONN;
trace (NORM, tr, "send !q\n");
/* send '!q' */
send_socket_cmd (tr, fd, "!q\n");
CLOSE_CONN:
fflush (fin); /* JW only needed when irrd commands are sent to terminal */
close_connection (fd);
trace (NORM, tr, "exit irrd_send_trans ()\n");
return ret_code;
}
/* Fetch a DB object from IRRd and put it into file '*fname'. 'obj_size'
* can be either 'SHORT_OBJECT' in which case only notify, mnt_nfy, upd_to,
* and auth fields are fetched, or 'FULL_OBJECT'.
*
* Return:
* Stream file pointer to the object if it was received successfully from IRRd
* and the name of the file in 'fname'.
* NULL otherwise.
*/
FILE *IRRd_fetch_obj (trace_t *tr, char *fname, int *conn_open, int *sockfd,
int obj_size, char *obj_type, char *obj_key, char *source,
int max_obj_line_size, char *IRRd_HOST, int IRRd_PORT) {
char buf[MAXLINE];
FILE *fobj;
int fd;
/* open the output file */
fd = mkstemp (fname);
if ((fobj = fdopen (fd, "w+")) == NULL) {
trace (ERROR, tr, "IRRd_fetch_obj() can't open \"%s\": (%s)\n",
fname, strerror (errno));
return NULL;
}
/* Open an IRRd connection */
if (++*conn_open == 1) {
if ((*sockfd = open_connection (tr, IRRd_HOST, IRRd_PORT)) < 0) {
fclose (fobj);
remove (fname);
*conn_open = 0;
return NULL;
}
/* Send a '!!' */
if (start_irrd_session (tr, *sockfd) != NULL) {
trace (ERROR, tr, "IRRd_fetch_obj() '!!' failed\n");
goto fetch_fail;
}
/* make sure we can get withdrawn routes too */
sprintf (buf, "!uwd=1\n");
if (send_socket_cmd (tr, *sockfd, buf) != NULL ||
read_socket_cmd (tr, *sockfd, "C\n") != NULL) {
trace (ERROR, tr, "IRRd_fetch_obj() '!uwd=1' failed\n");
goto fetch_fail;
}
}
/* send the IRRd commands to retrieve the object */
sprintf (buf, "!s%s\n", source);
if (send_socket_cmd (tr, *sockfd, buf) != NULL ||
read_socket_cmd (tr, *sockfd, "C\n") != NULL) {
trace (ERROR, tr, "IRRd_fetch_obj() '!s' failed\n");
goto fetch_fail;
}
sprintf (buf, "!m%s,%s\n", obj_type, obj_key);
if (send_socket_cmd (tr, *sockfd, buf) != NULL ||
read_socket_line (tr, *sockfd, buf, MAXLINE) < 0) {
trace (ERROR, tr, "IRRd_fetch_obj() '!m' failed\n");
goto fetch_fail;
}
/* An 'A' return code means we have the object, otherwise
* the object was not found.
*/
/*fprintf (dfile, "IRRd_fetch_object () irrd ret_code (%s)\n", buf);*/
if (buf[0] != 'A') {
fclose (fobj);
remove (fname);
return NULL;
}
/* put the object into file */
newline_remove (buf);
if (read_socket_obj (tr, *sockfd, fobj, obj_size, atoi (&buf[1]), max_obj_line_size) < 0) {
trace (ERROR, tr, "IRRd_fetch_obj() read_socket_obj failed\n");
fetch_fail:
fclose (fobj);
remove (fname);
close(*sockfd);
*sockfd = -1;
*conn_open = 0;
return NULL;
}
/* Simplify NOOP checking, put a blank line after the object */
if (EOF == fputs ("\n", fobj))
trace (ERROR, tr, "IRRd_fetch_obj () can't write \\n at object end: (%s)\n", strerror (errno));
return fobj;
}
/* Take a !us...!ue file from irr_submit and send it to IRRd.
*
* Input:
* an input !us...!ue file (fin)
* Note: file should not have leading or trailing blank lines
* the irrd host (IRRd_HOST)
* the irrd port (IRRd_PORT)
*
* Return:
* -"C\n" if the file was committed by irrd
* -a text file error message otherwise. This would
* mean irrd did not commit the transation.
*/
char *send_rpsdist_trans (trace_t *tr, FILE *fin, char *IRRd_HOST,
int IRRd_PORT) {
int fd;
char buf[MAXLINE], *ret_code = NULL;
/* make sure were at the beginning of file */
fseek (fin, 0L, SEEK_SET);
/* Open an IRRd connection */
if ((fd = open_connection (tr, IRRd_HOST, IRRd_PORT)) < 0) {
trace (ERROR, tr, "send_rpsdist_trans () Could not open connection to IRRd (%s, %d)\n", IRRd_HOST, IRRd_PORT);
return "send_rpsdist_trans () IRRd unreachable or down. Tranaction aborted!\n";
}
/* Stay open mode !! */
if ((ret_code = send_socket_cmd (tr, fd, "!!\n")) != NULL)
goto CLOSE_CONN;
/* JW:!!!: needs to be fixed to handle lines longer than MAXLINE */
/* loop through the !us...!ue irrd update file */
while (fgets (buf, MAXLINE - 1, fin) != NULL) {
if ((ret_code = send_socket_cmd (tr, fd, buf)) != NULL)
goto CLOSE_CONN;
/* for !us or !ue expect a "C\n" return code from irrd */
if ((!strncmp (buf, "!us", 3) ||
!strncmp (buf, "!ms", 3) ||
!strcmp (buf, "!ue\n")) &&
(ret_code = read_socket_cmd (tr, fd, "C\n")) != NULL)
goto CLOSE_CONN;
}
/* send '!q' */
send_socket_cmd (tr, fd, "!q\n");
CLOSE_CONN:
close_connection (fd);
return ret_code;
}
/* Perform the PGP operations from irr_submit on the local rings.
*
* Input:
* -pointer to the file of PGP operations to be performed (fin)
* -fully qualified dir path to the location of the production rings (pgpdir)
*
* Return:
* -NULL if there were no errors and the operations were carried
* out successfully
* -a character text message of an error condition, ie, the PGP
* operations were not carried to completion
*/
char *rpsdist_update_pgp_ring (trace_t *tr, FILE *fin, char *pgpdir) {
char curline[MAXLINE], *ret_code = NULL;
regex_t blanklinere;
char *blankline = "^[ \t]*\n$";
char *newline;
int add;
/* compile the regex */
regcomp (&blanklinere, blankline, REG_EXTENDED|REG_NOSUB);
/* rewind */
fseek (fin, 0L, SEEK_SET);
/* loop through the pgp update file and perform the updates */
while (fgets (curline, MAXLINE - 1, fin) != NULL) {
/* skip blank lines */
if (regexec (&blanklinere, curline, 0, 0, 0) == 0)
continue;
/* read the op */
add = !strncmp(curline, ADD_OP, 3);
/* read the operation data item */
if (fgets (curline, MAXLINE - 1, fin) == NULL) {
trace (ERROR, tr, "rpsdist_update_pgp_ring () PGP disk read error.\n");
ret_code = "SERVER ERROR: PGP disk read error. Transaction aborted.";
break; /* we're hosed, break out of the loop */
}
/* change the '\n' to EOS */
if ((newline = strchr (curline, '\n')))
*newline = '\0';
/* (ret_code) not NULL means we are aborting the transaction */
if (ret_code == NULL) {
if (add) {
/* perform the add operation */
if (!pgp_add (tr, pgpdir, curline, NULL)) {
trace (ERROR, tr, "rpsdist_update_pgp_ring () pgp add error.\n");
ret_code = "SERVER ERROR: pgp add read error. Transaction aborted.";
}
}
/* perform the delete operation */
else if (!pgp_del (tr, pgpdir, curline)) {
trace (ERROR, tr, "rpsdist_update_pgp_ring () PGP delete error.\n");
ret_code = "SERVER ERROR: PGP delete error. Transaction aborted.";
}
}
/* clean up the temp files */
if (add)
remove (curline);
}
/* make purify happy */
regfree (&blanklinere);
return NULL;
}
char *irrd_curr_serial (trace_t *tr, char *source, char *host, int port) {
int fd;
char buf[MAXLINE], cs[MAXLINE];
/* Open an IRRd connection */
if ((fd = open_connection (tr, host, port)) < 0) {
trace (ERROR, tr, "irrd_curr_serial () Could not open connection to IRRd (%s, %d)\n", host, port);
return NULL;
}
/* Stay open mode !! */
sprintf (buf, "!j%s\n", source);
if (send_socket_cmd (tr, fd, buf) != NULL ||
read_socket_line (tr, fd, buf, MAXLINE) < 0) {
trace (ERROR, tr, "irrd_curr_serial () 1. failed !j command\n");
goto CLOSE_CONN;
}
/* Grab the 'A' return code */
if (buf[0] != 'A') {
trace (ERROR, tr, "irrd_curr_serial () 2. failed !j command\n");
goto CLOSE_CONN;
}
/* read the data line and the 'C' */
if (read_socket_line (tr, fd, cs, MAXLINE) < 0 ||
read_socket_line (tr, fd, buf, MAXLINE) < 0) {
trace (ERROR, tr, "irrd_curr_serial () 3. failed !j command\n");
goto CLOSE_CONN;
}
close_connection (fd);
return strdup (cs);
CLOSE_CONN:
close_connection (fd);
return NULL;
}
syntax highlighted by Code2HTML, v. 0.9.1