This repository has been archived on 2020-04-11. You can view files and clone it, but cannot push or open issues or pull requests.
eilduscd/src/ildus-manager.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);
}