189 lines
5.1 KiB
C
189 lines
5.1 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
|
|
#include <common.h>
|
|
#include "ildus-connection.h"
|
|
#include "ildus-manager.h"
|
|
|
|
#define ILDUS_OKAY 200
|
|
#define ILDUS_WELCOME 220
|
|
#define ILDUS_GOODBYE 221
|
|
#define ILDUS_AUTHENTICATED 230
|
|
#define ILDUS_UPATE_OK 240
|
|
#define ILDUS_USER_OKAY 331
|
|
|
|
typedef struct {
|
|
char *server;
|
|
int port;
|
|
char *hostname;
|
|
char *username;
|
|
char *password;
|
|
} ildus_manager_t;
|
|
|
|
ildus_manager_t *manager;
|
|
|
|
static void
|
|
_ildus_print_message(ildus_message_t *m) {
|
|
if (m->long_msg) {
|
|
int i;
|
|
printf("<+%s\n", m->head_msg);
|
|
for (i = 0; m->data[i] != NULL; i++) {
|
|
printf("{+%s\n", m->data[i]);
|
|
}
|
|
}
|
|
printf("<<%s\n", m->msg);
|
|
}
|
|
|
|
static int
|
|
_ildus_send_message(ildus_connection_t *c, char *format, ...) {
|
|
#define BUFSIZE 1024
|
|
char buffer[BUFSIZE];
|
|
va_list ap;
|
|
int n;
|
|
va_start(ap , format);
|
|
n = vsnprintf(buffer, BUFSIZE - 1, format, ap);
|
|
va_end(ap);
|
|
if (n < 0 || n > BUFSIZE - 1) {
|
|
return -1;
|
|
}
|
|
printf(">>%s", buffer);
|
|
return ildus_connection_send(c, buffer);
|
|
}
|
|
|
|
static int
|
|
_ildus_get_message(ildus_connection_t *con, int replycode,
|
|
ildus_connection_error_t *error) {
|
|
ildus_message_t *msg = NULL;
|
|
int ret = TRUE;
|
|
|
|
msg = ildus_connection_get_message(con, error);
|
|
if (msg == NULL) {
|
|
printf("Failed to get message\n");
|
|
return FALSE;
|
|
}
|
|
_ildus_print_message(msg);
|
|
if (msg->code != replycode) {
|
|
fprintf(stderr,
|
|
"Unexpected reply from ildus server received (%d != %d)\n",
|
|
msg->code, replycode);
|
|
ret = FALSE;
|
|
}
|
|
del_ildus_message(msg);
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
ildus_manager_do_update(address_t *v4, address_t *v6) {
|
|
#define GET_MESSAGE(replycode) \
|
|
do { if (!_ildus_get_message(con, replycode, &error)) \
|
|
goto error; \
|
|
} while(0)
|
|
#define SEND_MESSAGE(...) \
|
|
do { \
|
|
if (!_ildus_send_message(con, __VA_ARGS__)) { \
|
|
fprintf(stderr, "Failed to send data to ildus server\n"); \
|
|
goto error; \
|
|
} \
|
|
} while(0)
|
|
|
|
ildus_connection_t *con = NULL;
|
|
ildus_connection_error_t error = ILDUS_CONNECTION_CONNECTION_NO_ERROR;
|
|
int ret = TRUE;
|
|
if (v4 && v4->current) {
|
|
v4 = NULL;
|
|
}
|
|
if (v6 && v6->current) {
|
|
v6 = NULL;
|
|
}
|
|
if (v4 == NULL && v6 == NULL) {
|
|
/* Nothing to do */
|
|
return TRUE;
|
|
}
|
|
/* We need to update at least one address */
|
|
con = new_ildus_connection("ildus.luon.net", 9000, &error);
|
|
if (con == NULL) {
|
|
goto error;
|
|
}
|
|
/* First we receive the welcome */
|
|
GET_MESSAGE(ILDUS_WELCOME);
|
|
/* Send username */
|
|
SEND_MESSAGE("USER %s\r\n", manager->username);
|
|
GET_MESSAGE(ILDUS_USER_OKAY);
|
|
/* Password */
|
|
SEND_MESSAGE("PASS %s\r\n", manager->password);
|
|
GET_MESSAGE(ILDUS_AUTHENTICATED);
|
|
/* Update when needed */
|
|
if (v4) {
|
|
char buffer[INET6_ADDRSTRLEN];
|
|
inet_ntop(v4->family, &(v4->a.v4), buffer, INET6_ADDRSTRLEN);
|
|
SEND_MESSAGE("UPDT %s %s\r\n", manager->hostname, buffer);
|
|
if (_ildus_get_message(con, ILDUS_UPATE_OK, &error)) {
|
|
address_toggle_current(v4);
|
|
} else if (error == ILDUS_CONNECTION_CONNECTION_NO_ERROR) {
|
|
/* We didn't get the ILDUS_UPATE_OK reply */
|
|
fprintf(stderr, "Failed to update IPv4 address\n");
|
|
ret = FALSE;
|
|
} else {
|
|
goto error;
|
|
}
|
|
}
|
|
if (v6) {
|
|
char buffer[INET6_ADDRSTRLEN];
|
|
inet_ntop(v6->family, &(v6->a.v6), buffer, INET6_ADDRSTRLEN);
|
|
SEND_MESSAGE("UPDT %s %s\r\n", manager->hostname, buffer);
|
|
if (_ildus_get_message(con, ILDUS_UPATE_OK, &error)) {
|
|
address_toggle_current(v6);
|
|
} else if (error == ILDUS_CONNECTION_CONNECTION_NO_ERROR) {
|
|
/* We didn't get the ILDUS_UPATE_OK reply */
|
|
fprintf(stderr, "Failed to update IPv6 address\n");
|
|
ret = FALSE;
|
|
} else {
|
|
goto error;
|
|
}
|
|
}
|
|
/* and quit */
|
|
SEND_MESSAGE("QUIT\r\n");
|
|
GET_MESSAGE(ILDUS_GOODBYE);
|
|
del_ildus_connection(con);
|
|
return ret;
|
|
|
|
error:
|
|
switch (error) {
|
|
case ILDUS_CONNECTION_CONNECTION_NO_ERROR:
|
|
/* No need to print, something else caused it (wrong replycode ?) */
|
|
break;
|
|
case ILDUS_CONNECTION_CONNECTION_READ_ERROR:
|
|
fprintf(stderr, "Connection to ildus server closed unexpectedly\n");
|
|
break;
|
|
case ILDUS_CONNECTION_CONNECTION_BUFFER_OVERFLOW:
|
|
fprintf(stderr, "Received line from ildus server too long\n");
|
|
break;
|
|
case ILDUS_CONNECTION_UNRESOLVED_HOST_ERROR:
|
|
fprintf(stderr, "Couldn't resolve: %s\n", manager->server);
|
|
break;
|
|
case ILDUS_CONNECTION_FAILED:
|
|
fprintf(stderr, "Failed to connect to ildus server: [%s]:%d\n",
|
|
manager->server, manager->port);
|
|
break;
|
|
case ILDUS_CONNECTION_MALFORMED_REPLY:
|
|
fprintf(stderr, "Got malformed reply from ildus server\n");
|
|
break;
|
|
fprintf(stderr,"Unknown error %d\n", error);
|
|
}
|
|
del_ildus_connection(con);
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
ildus_manager_init(char *server, int port,
|
|
char *username, char *password, char *hostname) {
|
|
manager = malloc(sizeof(ildus_manager_t));
|
|
manager->server = strdup(server);
|
|
manager->port = port;
|
|
manager->username = strdup(username);
|
|
manager->password = strdup(password);
|
|
manager->hostname = strdup(hostname);
|
|
}
|