ogserver/sources/ogAdmServer.c

6650 lines
190 KiB
C

// *******************************************************************************************************
// Servicio: ogAdmServer
// Autor: José Manuel Alonso (E.T.S.I.I.) Universidad de Sevilla
// Fecha Creación: Marzo-2010
// Fecha Última modificación: Marzo-2010
// Nombre del fichero: ogAdmServer.cpp
// Descripción :Este fichero implementa el servicio de administración general del sistema
// *******************************************************************************************************
#include "ogAdmServer.h"
#include "ogAdmLib.c"
#include "dbi.h"
#include "list.h"
#include "schedule.h"
#include <ev.h>
#include <syslog.h>
#include <sys/ioctl.h>
#include <ifaddrs.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <jansson.h>
#include <time.h>
static char usuario[LONPRM]; // Usuario de acceso a la base de datos
static char pasguor[LONPRM]; // Password del usuario
static char datasource[LONPRM]; // Dirección IP del gestor de base de datos
static char catalog[LONPRM]; // Nombre de la base de datos
static char interface[LONPRM]; // Interface name
static char auth_token[LONPRM]; // API token
static struct og_dbi_config dbi_config = {
.user = usuario,
.passwd = pasguor,
.host = datasource,
.database = catalog,
};
//________________________________________________________________________________________________________
// Función: tomaConfiguracion
//
// Descripción:
// Lee el fichero de configuración del servicio
// Parámetros:
// filecfg : Ruta completa al fichero de configuración
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
//________________________________________________________________________________________________________
static bool tomaConfiguracion(const char *filecfg)
{
char buf[1024], *line;
char *key, *value;
FILE *fcfg;
if (filecfg == NULL || strlen(filecfg) == 0) {
syslog(LOG_ERR, "No configuration file has been specified\n");
return false;
}
fcfg = fopen(filecfg, "rt");
if (fcfg == NULL) {
syslog(LOG_ERR, "Cannot open configuration file `%s'\n",
filecfg);
return false;
}
servidoradm[0] = '\0'; //inicializar variables globales
line = fgets(buf, sizeof(buf), fcfg);
while (line != NULL) {
const char *delim = "=";
line[strlen(line) - 1] = '\0';
key = strtok(line, delim);
value = strtok(NULL, delim);
if (!strcmp(StrToUpper(key), "SERVIDORADM"))
snprintf(servidoradm, sizeof(servidoradm), "%s", value);
else if (!strcmp(StrToUpper(key), "PUERTO"))
snprintf(puerto, sizeof(puerto), "%s", value);
else if (!strcmp(StrToUpper(key), "USUARIO"))
snprintf(usuario, sizeof(usuario), "%s", value);
else if (!strcmp(StrToUpper(key), "PASSWORD"))
snprintf(pasguor, sizeof(pasguor), "%s", value);
else if (!strcmp(StrToUpper(key), "DATASOURCE"))
snprintf(datasource, sizeof(datasource), "%s", value);
else if (!strcmp(StrToUpper(key), "CATALOG"))
snprintf(catalog, sizeof(catalog), "%s", value);
else if (!strcmp(StrToUpper(key), "INTERFACE"))
snprintf(interface, sizeof(interface), "%s", value);
else if (!strcmp(StrToUpper(key), "APITOKEN"))
snprintf(auth_token, sizeof(auth_token), "%s", value);
line = fgets(buf, sizeof(buf), fcfg);
}
fclose(fcfg);
if (!servidoradm[0]) {
syslog(LOG_ERR, "Missing SERVIDORADM in configuration file\n");
return false;
}
if (!puerto[0]) {
syslog(LOG_ERR, "Missing PUERTO in configuration file\n");
return false;
}
if (!usuario[0]) {
syslog(LOG_ERR, "Missing USUARIO in configuration file\n");
return false;
}
if (!pasguor[0]) {
syslog(LOG_ERR, "Missing PASSWORD in configuration file\n");
return false;
}
if (!datasource[0]) {
syslog(LOG_ERR, "Missing DATASOURCE in configuration file\n");
return false;
}
if (!catalog[0]) {
syslog(LOG_ERR, "Missing CATALOG in configuration file\n");
return false;
}
if (!interface[0])
syslog(LOG_ERR, "Missing INTERFACE in configuration file\n");
return true;
}
enum og_client_state {
OG_CLIENT_RECEIVING_HEADER = 0,
OG_CLIENT_RECEIVING_PAYLOAD,
OG_CLIENT_PROCESSING_REQUEST,
};
#define OG_MSG_REQUEST_MAXLEN 65536
#define OG_CMD_MAXLEN 64
/* Shut down connection if there is no complete message after 10 seconds. */
#define OG_CLIENT_TIMEOUT 10
/* Agent client operation might take longer, shut down after 30 seconds. */
#define OG_AGENT_CLIENT_TIMEOUT 30
static LIST_HEAD(client_list);
struct og_client {
struct list_head list;
struct ev_io io;
struct ev_timer timer;
struct sockaddr_in addr;
enum og_client_state state;
char buf[OG_MSG_REQUEST_MAXLEN];
unsigned int buf_len;
unsigned int msg_len;
int keepalive_idx;
bool rest;
bool agent;
int content_length;
char auth_token[64];
const char *status;
char last_cmd[OG_CMD_MAXLEN];
};
static inline int og_client_socket(const struct og_client *cli)
{
return cli->io.fd;
}
// ________________________________________________________________________________________________________
// Función: clienteDisponible
//
// Descripción:
// Comprueba la disponibilidad del cliente para recibir comandos interactivos
// Parametros:
// - ip : La ip del cliente a buscar
// - idx: (Salida) Indice que ocupa el cliente, de estar ya registrado
// Devuelve:
// true: Si el cliente está disponible
// false: En caso contrario
// ________________________________________________________________________________________________________
bool clienteDisponible(char *ip, int* idx)
{
int estado;
if (clienteExistente(ip, idx)) {
estado = strcmp(tbsockets[*idx].estado, CLIENTE_OCUPADO); // Cliente ocupado
if (estado == 0)
return false;
estado = strcmp(tbsockets[*idx].estado, CLIENTE_APAGADO); // Cliente apagado
if (estado == 0)
return false;
estado = strcmp(tbsockets[*idx].estado, CLIENTE_INICIANDO); // Cliente en proceso de inclusión
if (estado == 0)
return false;
return true; // En caso contrario el cliente está disponible
}
return false; // Cliente no está registrado en el sistema
}
// ________________________________________________________________________________________________________
// Función: clienteExistente
//
// Descripción:
// Comprueba si el cliente está registrado en la tabla de socket del sistema
// Parametros:
// - ip : La ip del cliente a buscar
// - idx:(Salida) Indice que ocupa el cliente, de estar ya registrado
// Devuelve:
// true: Si el cliente está registrado
// false: En caso contrario
// ________________________________________________________________________________________________________
bool clienteExistente(char *ip, int* idx)
{
int i;
for (i = 0; i < MAXIMOS_CLIENTES; i++) {
if (contieneIP(ip, tbsockets[i].ip)) { // Si existe la IP en la cadena
*idx = i;
return true;
}
}
return false;
}
// ________________________________________________________________________________________________________
// Función: hayHueco
//
// Descripción:
// Esta función devuelve true o false dependiendo de que haya hueco en la tabla de sockets para un nuevo cliente.
// Parametros:
// - idx: Primer indice libre que se podrn utilizar
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// ________________________________________________________________________________________________________
static bool hayHueco(int *idx)
{
int i;
for (i = 0; i < MAXIMOS_CLIENTES; i++) {
if (strncmp(tbsockets[i].ip, "\0", 1) == 0) { // Hay un hueco
*idx = i;
return true;
}
}
return false;
}
// ________________________________________________________________________________________________________
// Función: InclusionClienteWin
//
// Descripción:
// Esta función incorpora el socket de un nuevo cliente Windows o Linux a la tabla de clientes
// Parámetros:
// - socket_c: Socket del cliente que envió el mensaje
// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// ________________________________________________________________________________________________________
static bool InclusionClienteWinLnx(TRAMA *ptrTrama, struct og_client *cli)
{
int socket_c = og_client_socket(cli);
int res,idordenador,lon;
char nombreordenador[LONFIL];
res = procesoInclusionClienteWinLnx(socket_c, ptrTrama, &idordenador,
nombreordenador);
// Prepara la trama de respuesta
initParametros(ptrTrama,0);
ptrTrama->tipo=MSG_RESPUESTA;
lon = sprintf(ptrTrama->parametros, "nfn=RESPUESTA_InclusionClienteWinLnx\r");
lon += sprintf(ptrTrama->parametros + lon, "ido=%d\r", idordenador);
lon += sprintf(ptrTrama->parametros + lon, "npc=%s\r", nombreordenador);
lon += sprintf(ptrTrama->parametros + lon, "res=%d\r", res);
if (!mandaTrama(&socket_c, ptrTrama)) {
syslog(LOG_ERR, "failed to send response to %s:%hu reason=%s\n",
inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port),
strerror(errno));
return false;
}
return true;
}
// ________________________________________________________________________________________________________
// Función: procesoInclusionClienteWinLnx
//
// Descripción:
// Implementa el proceso de inclusión en el sistema del Cliente Windows o Linux
// Parámetros de entrada:
// - socket_c: Socket del cliente que envió el mensaje
// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
// Parámetros de salida:
// - ido: Identificador del ordenador
// - nombreordenador: Nombre del ordenador
// Devuelve:
// Código del error producido en caso de ocurrir algún error, 0 si el proceso es correcto
// ________________________________________________________________________________________________________
bool procesoInclusionClienteWinLnx(int socket_c, TRAMA *ptrTrama, int *idordenador, char *nombreordenador)
{
struct og_dbi *dbi;
const char *msglog;
dbi_result result;
char *iph;
// Toma parámetros
iph = copiaParametro("iph",ptrTrama); // Toma ip
dbi = og_dbi_open(&dbi_config);
if (!dbi) {
syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
__func__, __LINE__);
goto err_dbi_open;
}
result = dbi_conn_queryf(dbi->conn,
"SELECT idordenador,nombreordenador FROM ordenadores "
" WHERE ordenadores.ip = '%s'", iph);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
goto err_query_fail;
}
if (!dbi_result_next_row(result)) {
syslog(LOG_ERR, "client does not exist in database (%s:%d)\n",
__func__, __LINE__);
dbi_result_free(result);
goto err_query_fail;
}
syslog(LOG_DEBUG, "Client %s requesting inclusion\n", iph);
*idordenador = dbi_result_get_uint(result, "idordenador");
nombreordenador = (char *)dbi_result_get_string(result, "nombreordenador");
dbi_result_free(result);
og_dbi_close(dbi);
if (!registraCliente(iph)) { // Incluyendo al cliente en la tabla de sokets
liberaMemoria(iph);
syslog(LOG_ERR, "client table is full\n");
return false;
}
liberaMemoria(iph);
return true;
err_query_fail:
og_dbi_close(dbi);
err_dbi_open:
liberaMemoria(iph);
return false;
}
// ________________________________________________________________________________________________________
// Función: InclusionCliente
//
// Descripción:
// Esta función incorpora el socket de un nuevo cliente a la tabla de clientes y le devuelve alguna de sus propiedades:
// nombre, identificador, tamaño de la caché , etc ...
// Parámetros:
// - socket_c: Socket del cliente que envió el mensaje
// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// ________________________________________________________________________________________________________
static bool InclusionCliente(TRAMA *ptrTrama, struct og_client *cli)
{
int socket_c = og_client_socket(cli);
if (!procesoInclusionCliente(cli, ptrTrama)) {
initParametros(ptrTrama,0);
strcpy(ptrTrama->parametros, "nfn=RESPUESTA_InclusionCliente\rres=0\r");
if (!mandaTrama(&socket_c, ptrTrama)) {
syslog(LOG_ERR, "failed to send response to %s:%hu reason=%s\n",
inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port),
strerror(errno));
return false;
}
}
return true;
}
// ________________________________________________________________________________________________________
// Función: procesoInclusionCliente
//
// Descripción:
// Implementa el proceso de inclusión en el sistema del Cliente
// Parámetros:
// - socket_c: Socket del cliente que envió el mensaje
// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// ________________________________________________________________________________________________________
bool procesoInclusionCliente(struct og_client *cli, TRAMA *ptrTrama)
{
int socket_c = og_client_socket(cli);
const char *msglog, *str;
struct og_dbi *dbi;
dbi_result result;
char *iph, *cfg;
char nombreordenador[LONFIL];
int lon, resul, idordenador, cache, idproautoexec, idaula, idcentro;
// Toma parámetros
iph = copiaParametro("iph",ptrTrama); // Toma ip
cfg = copiaParametro("cfg",ptrTrama); // Toma configuracion
dbi = og_dbi_open(&dbi_config);
if (!dbi) {
syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
__func__, __LINE__);
goto err_dbi_open;
}
// Recupera los datos del cliente
result = dbi_conn_queryf(dbi->conn,
"SELECT ordenadores.*,aulas.idaula,centros.idcentro FROM ordenadores "
" INNER JOIN aulas ON aulas.idaula=ordenadores.idaula"
" INNER JOIN centros ON centros.idcentro=aulas.idcentro"
" WHERE ordenadores.ip = '%s'", iph);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
goto err_query_fail;
}
if (!dbi_result_next_row(result)) {
syslog(LOG_ERR, "client does not exist in database (%s:%d)\n",
__func__, __LINE__);
dbi_result_free(result);
goto err_query_fail;
}
syslog(LOG_DEBUG, "Client %s requesting inclusion\n", iph);
idordenador = dbi_result_get_uint(result, "idordenador");
str = (char *)dbi_result_get_string(result, "nombreordenador");
sprintf(nombreordenador, "%s", str);
cache = dbi_result_get_uint(result, "cache");
idproautoexec = dbi_result_get_uint(result, "idproautoexec");
idaula = dbi_result_get_uint(result, "idaula");
idcentro = dbi_result_get_uint(result, "idcentro");
dbi_result_free(result);
resul = actualizaConfiguracion(dbi, cfg, idordenador); // Actualiza la configuración del ordenador
liberaMemoria(cfg);
og_dbi_close(dbi);
if (!resul) {
liberaMemoria(iph);
syslog(LOG_ERR, "Cannot add client to database\n");
return false;
}
if (!registraCliente(iph)) { // Incluyendo al cliente en la tabla de sokets
liberaMemoria(iph);
syslog(LOG_ERR, "client table is full\n");
return false;
}
/*------------------------------------------------------------------------------------------------------------------------------
Prepara la trama de respuesta
-------------------------------------------------------------------------------------------------------------------------------*/
initParametros(ptrTrama,0);
ptrTrama->tipo=MSG_RESPUESTA;
lon = sprintf(ptrTrama->parametros, "nfn=RESPUESTA_InclusionCliente\r");
lon += sprintf(ptrTrama->parametros + lon, "ido=%d\r", idordenador);
lon += sprintf(ptrTrama->parametros + lon, "npc=%s\r", nombreordenador);
lon += sprintf(ptrTrama->parametros + lon, "che=%d\r", cache);
lon += sprintf(ptrTrama->parametros + lon, "exe=%d\r", idproautoexec);
lon += sprintf(ptrTrama->parametros + lon, "ida=%d\r", idaula);
lon += sprintf(ptrTrama->parametros + lon, "idc=%d\r", idcentro);
lon += sprintf(ptrTrama->parametros + lon, "res=%d\r", 1); // Confirmación proceso correcto
if (!mandaTrama(&socket_c, ptrTrama)) {
syslog(LOG_ERR, "failed to send response to %s:%hu reason=%s\n",
inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port),
strerror(errno));
return false;
}
liberaMemoria(iph);
return true;
err_query_fail:
og_dbi_close(dbi);
err_dbi_open:
liberaMemoria(iph);
liberaMemoria(cfg);
return false;
}
// ________________________________________________________________________________________________________
// Función: actualizaConfiguracion
//
// Descripción:
// Esta función actualiza la base de datos con la configuracion de particiones de un cliente
// Parámetros:
// - db: Objeto base de datos (ya operativo)
// - tbl: Objeto tabla
// - cfg: cadena con una Configuración
// - ido: Identificador del ordenador cliente
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// Especificaciones:
// Los parametros de la configuración son:
// par= Número de partición
// cpt= Codigo o tipo de partición
// sfi= Sistema de ficheros que está implementado en la partición
// soi= Nombre del sistema de ficheros instalado en la partición
// tam= Tamaño de la partición
// ________________________________________________________________________________________________________
bool actualizaConfiguracion(struct og_dbi *dbi, char *cfg, int ido)
{
int lon, p, c,i, dato, swu, idsoi, idsfi,k;
char *ptrPar[MAXPAR], *ptrCfg[7], *ptrDual[2], tbPar[LONSTD];
char *ser, *disk, *par, *cpt, *sfi, *soi, *tam, *uso; // Parametros de configuración.
dbi_result result, result_update;
const char *msglog;
lon = 0;
p = splitCadena(ptrPar, cfg, '\n');
for (i = 0; i < p; i++) {
c = splitCadena(ptrCfg, ptrPar[i], '\t');
// Si la 1ª línea solo incluye el número de serie del equipo; actualizar BD.
if (i == 0 && c == 1) {
splitCadena(ptrDual, ptrCfg[0], '=');
ser = ptrDual[1];
if (strlen(ser) > 0) {
// Solo actualizar si número de serie no existía.
result = dbi_conn_queryf(dbi->conn,
"UPDATE ordenadores SET numserie='%s'"
" WHERE idordenador=%d AND numserie IS NULL",
ser, ido);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return false;
}
dbi_result_free(result);
}
continue;
}
// Distribución de particionado.
disk = par = cpt = sfi = soi = tam = uso = NULL;
splitCadena(ptrDual, ptrCfg[0], '=');
disk = ptrDual[1]; // Número de disco
splitCadena(ptrDual, ptrCfg[1], '=');
par = ptrDual[1]; // Número de partición
k=splitCadena(ptrDual, ptrCfg[2], '=');
if(k==2){
cpt = ptrDual[1]; // Código de partición
}else{
cpt = (char*)"0";
}
k=splitCadena(ptrDual, ptrCfg[3], '=');
if(k==2){
sfi = ptrDual[1]; // Sistema de ficheros
/* Comprueba existencia del s0xistema de ficheros instalado */
idsfi = checkDato(dbi, sfi, "sistemasficheros", "descripcion","idsistemafichero");
}
else
idsfi=0;
k=splitCadena(ptrDual, ptrCfg[4], '=');
if(k==2){ // Sistema operativo detecdtado
soi = ptrDual[1]; // Nombre del S.O. instalado
/* Comprueba existencia del sistema operativo instalado */
idsoi = checkDato(dbi, soi, "nombresos", "nombreso", "idnombreso");
}
else
idsoi=0;
splitCadena(ptrDual, ptrCfg[5], '=');
tam = ptrDual[1]; // Tamaño de la partición
splitCadena(ptrDual, ptrCfg[6], '=');
uso = ptrDual[1]; // Porcentaje de uso del S.F.
lon += sprintf(tbPar + lon, "(%s, %s),", disk, par);
result = dbi_conn_queryf(dbi->conn,
"SELECT numdisk, numpar, tamano, uso, idsistemafichero, idnombreso"
" FROM ordenadores_particiones"
" WHERE idordenador=%d AND numdisk=%s AND numpar=%s",
ido, disk, par);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return false;
}
if (!dbi_result_next_row(result)) {
result_update = dbi_conn_queryf(dbi->conn,
"INSERT INTO ordenadores_particiones(idordenador,numdisk,numpar,codpar,tamano,uso,idsistemafichero,idnombreso,idimagen)"
" VALUES(%d,%s,%s,0x%s,%s,%s,%d,%d,0)",
ido, disk, par, cpt, tam, uso, idsfi, idsoi);
if (!result_update) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return false;
}
dbi_result_free(result_update);
} else { // Existe el registro
swu = true; // Se supone que algún dato ha cambiado
dato = dbi_result_get_uint(result, "tamano");
if (atoi(tam) == dato) {// Parámetro tamaño igual al almacenado
dato = dbi_result_get_uint(result, "idsistemafichero");
if (idsfi == dato) {// Parámetro sistema de fichero igual al almacenado
dato = dbi_result_get_uint(result, "idnombreso");
if (idsoi == dato) {// Parámetro sistema de fichero distinto al almacenado
swu = false; // Todos los parámetros de la partición son iguales, no se actualiza
}
}
}
if (swu) { // Hay que actualizar los parámetros de la partición
result_update = dbi_conn_queryf(dbi->conn,
"UPDATE ordenadores_particiones SET "
" codpar=0x%s,"
" tamano=%s,"
" uso=%s,"
" idsistemafichero=%d,"
" idnombreso=%d,"
" idimagen=0,"
" idperfilsoft=0,"
" fechadespliegue=NULL"
" WHERE idordenador=%d AND numdisk=%s AND numpar=%s",
cpt, tam, uso, idsfi, idsoi, ido, disk, par);
} else { // Actualizar porcentaje de uso.
result_update = dbi_conn_queryf(dbi->conn,
"UPDATE ordenadores_particiones SET "
" codpar=0x%s,"
" uso=%s"
" WHERE idordenador=%d AND numdisk=%s AND numpar=%s",
cpt, uso, ido, disk, par);
}
if (!result_update) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return false;
}
dbi_result_free(result_update);
}
dbi_result_free(result);
}
lon += sprintf(tbPar + lon, "(0,0)");
// Eliminar particiones almacenadas que ya no existen
result_update = dbi_conn_queryf(dbi->conn,
"DELETE FROM ordenadores_particiones WHERE idordenador=%d AND (numdisk, numpar) NOT IN (%s)",
ido, tbPar);
if (!result_update) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return false;
}
dbi_result_free(result_update);
return true;
}
// ________________________________________________________________________________________________________
// Función: checkDato
//
// Descripción:
// Esta función comprueba si existe un dato en una tabla y si no es así lo incluye. devuelve en
// cualquier caso el identificador del registro existenet o del insertado
// Parámetros:
// - db: Objeto base de datos (ya operativo)
// - tbl: Objeto tabla
// - dato: Dato
// - tabla: Nombre de la tabla
// - nomdato: Nombre del dato en la tabla
// - nomidentificador: Nombre del identificador en la tabla
// Devuelve:
// El identificador del registro existente o el del insertado
//
// Especificaciones:
// En caso de producirse algún error se devuelve el valor 0
// ________________________________________________________________________________________________________
int checkDato(struct og_dbi *dbi, char *dato, const char *tabla,
const char *nomdato, const char *nomidentificador)
{
const char *msglog;
int identificador;
dbi_result result;
if (strlen(dato) == 0)
return (0); // EL dato no tiene valor
result = dbi_conn_queryf(dbi->conn,
"SELECT %s FROM %s WHERE %s ='%s'", nomidentificador,
tabla, nomdato, dato);
// Ejecuta consulta
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return (0);
}
if (!dbi_result_next_row(result)) { // Software NO existente
dbi_result_free(result);
result = dbi_conn_queryf(dbi->conn,
"INSERT INTO %s (%s) VALUES('%s')", tabla, nomdato, dato);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
og_info((char *)msglog);
return (0);
}
// Recupera el identificador del software
identificador = dbi_conn_sequence_last(dbi->conn, NULL);
} else {
identificador = dbi_result_get_uint(result, nomidentificador);
}
dbi_result_free(result);
return (identificador);
}
// ________________________________________________________________________________________________________
// Función: registraCliente
//
// Descripción:
// Incluye al cliente en la tabla de sokets
// Parámetros:
// - iph: Dirección ip del cliente
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// ________________________________________________________________________________________________________
bool registraCliente(char *iph)
{
int idx;
if (!clienteExistente(iph, &idx)) { // Si no existe la IP ...
if (!hayHueco(&idx)) { // Busca hueco para el nuevo cliente
return false; // No hay huecos
}
}
strcpy(tbsockets[idx].ip, iph); // Copia IP
strcpy(tbsockets[idx].estado, CLIENTE_INICIANDO); // Actualiza el estado del cliente
return true;
}
// ________________________________________________________________________________________________________
// Función: AutoexecCliente
//
// Descripción:
// Envía archivo de autoexec al cliente
// Parámetros:
// - socket_c: Socket del cliente que envió el mensaje
// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// ________________________________________________________________________________________________________
static bool AutoexecCliente(TRAMA *ptrTrama, struct og_client *cli)
{
int socket_c = og_client_socket(cli);
int lon;
char *iph, *exe;
FILE *fileexe;
char fileautoexec[LONPRM];
char parametros[LONGITUD_PARAMETROS];
struct og_dbi *dbi;
iph = copiaParametro("iph",ptrTrama); // Toma dirección IP del cliente
exe = copiaParametro("exe",ptrTrama); // Toma identificador del procedimiento inicial
sprintf(fileautoexec, "/tmp/Sautoexec-%s", iph);
liberaMemoria(iph);
fileexe = fopen(fileautoexec, "wb"); // Abre fichero de script
if (fileexe == NULL) {
syslog(LOG_ERR, "cannot create temporary file\n");
return false;
}
dbi = og_dbi_open(&dbi_config);
if (!dbi) {
syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
__func__, __LINE__);
return false;
}
initParametros(ptrTrama,0);
if (recorreProcedimientos(dbi, parametros, fileexe, exe)) {
lon = sprintf(ptrTrama->parametros, "nfn=RESPUESTA_AutoexecCliente\r");
lon += sprintf(ptrTrama->parametros + lon, "nfl=%s\r", fileautoexec);
lon += sprintf(ptrTrama->parametros + lon, "res=1\r");
} else {
lon = sprintf(ptrTrama->parametros, "nfn=RESPUESTA_AutoexecCliente\r");
lon += sprintf(ptrTrama->parametros + lon, "res=0\r");
}
og_dbi_close(dbi);
fclose(fileexe);
if (!mandaTrama(&socket_c, ptrTrama)) {
liberaMemoria(exe);
syslog(LOG_ERR, "failed to send response to %s:%hu reason=%s\n",
inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port),
strerror(errno));
return false;
}
liberaMemoria(exe);
return true;
}
// ________________________________________________________________________________________________________
// Función: recorreProcedimientos
//
// Descripción:
// Crea un archivo con el código de un procedimiento separando cada comando por un salto de linea
// Parámetros:
// Database db,char* parametros,FILE* fileexe,char* idp
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// ________________________________________________________________________________________________________
bool recorreProcedimientos(struct og_dbi *dbi, char *parametros, FILE *fileexe, char *idp)
{
char idprocedimiento[LONPRM];
int procedimientoid, lsize;
const char *msglog, *param;
dbi_result result;
result = dbi_conn_queryf(dbi->conn,
"SELECT procedimientoid,parametros FROM procedimientos_acciones"
" WHERE idprocedimiento=%s ORDER BY orden", idp);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return false;
}
while (dbi_result_next_row(result)) {
procedimientoid = dbi_result_get_uint(result, "procedimientoid");
if (procedimientoid > 0) { // Procedimiento recursivo
sprintf(idprocedimiento, "%d", procedimientoid);
if (!recorreProcedimientos(dbi, parametros, fileexe, idprocedimiento)) {
return false;
}
} else {
param = dbi_result_get_string(result, "parametros");
sprintf(parametros, "%s@", param);
lsize = strlen(parametros);
fwrite(parametros, 1, lsize, fileexe); // Escribe el código a ejecutar
}
}
dbi_result_free(result);
return true;
}
struct og_task {
uint32_t procedure_id;
uint32_t type_scope;
uint32_t scope;
const char *filtered_scope;
const char *params;
};
struct og_cmd {
struct list_head list;
uint32_t client_id;
const char *params;
const char *ip;
const char *mac;
};
static LIST_HEAD(cmd_list);
static const struct og_cmd *og_cmd_find(char *client_ip)
{
struct og_cmd *cmd, *next;
list_for_each_entry_safe(cmd, next, &cmd_list, list) {
if (strcmp(cmd->ip, client_ip))
continue;
list_del(&cmd->list);
return cmd;
}
return NULL;
}
static void og_cmd_free(const struct og_cmd *cmd)
{
free((void *)cmd->params);
free((void *)cmd->ip);
free((void *)cmd->mac);
free((void *)cmd);
}
static TRAMA *og_msg_alloc(char *data, unsigned int len);
static void og_msg_free(TRAMA *ptrTrama);
static int og_deliver_pending_command(const struct og_cmd *cmd, int *socket,
int idx)
{
char buf[4096];
TRAMA *msg;
int len;
len = snprintf(buf, sizeof(buf), "%s\r", cmd->params);
msg = og_msg_alloc(buf, len);
if (!msg)
return false;
strcpy(tbsockets[idx].estado, CLIENTE_OCUPADO);
if (!mandaTrama(socket, msg)) {
syslog(LOG_ERR, "failed to send response to %s reason=%s\n",
cmd->ip, strerror(errno));
return false;
}
og_msg_free(msg);
og_cmd_free(cmd);
return true;
}
// ________________________________________________________________________________________________________
// Función: ComandosPendientes
//
// Descripción:
// Esta función busca en la base de datos,comandos pendientes de ejecutar por un ordenador concreto
// Parámetros:
// - socket_c: Socket del cliente que envió el mensaje
// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// ________________________________________________________________________________________________________
static bool ComandosPendientes(TRAMA *ptrTrama, struct og_client *cli)
{
int socket_c = og_client_socket(cli);
char *ido,*iph,pids[LONPRM];
const struct og_cmd *cmd;
int ids, idx;
iph = copiaParametro("iph",ptrTrama); // Toma dirección IP
ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
if (!clienteExistente(iph, &idx)) { // Busca índice del cliente
liberaMemoria(iph);
liberaMemoria(ido);
syslog(LOG_ERR, "client does not exist\n");
return false;
}
cmd = og_cmd_find(iph);
if (cmd) {
liberaMemoria(iph);
liberaMemoria(ido);
return og_deliver_pending_command(cmd, &socket_c, idx);
} else if (buscaComandos(ido, ptrTrama, &ids)) { // Existen comandos pendientes
ptrTrama->tipo = MSG_COMANDO;
sprintf(pids, "\rids=%d\r", ids);
strcat(ptrTrama->parametros, pids);
strcpy(tbsockets[idx].estado, CLIENTE_OCUPADO);
} else {
initParametros(ptrTrama,0);
strcpy(ptrTrama->parametros, "nfn=NoComandosPtes\r");
}
if (!mandaTrama(&socket_c, ptrTrama)) {
liberaMemoria(iph);
liberaMemoria(ido);
syslog(LOG_ERR, "failed to send response to %s:%hu reason=%s\n",
inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port),
strerror(errno));
return false;
}
liberaMemoria(iph);
liberaMemoria(ido);
return true;
}
// ________________________________________________________________________________________________________
// Función: buscaComandos
//
// Descripción:
// Busca en la base de datos,comandos pendientes de ejecutar por el cliente
// Parámetros:
// - ido: Identificador del ordenador
// - cmd: Parámetros del comando (Salida)
// - ids: Identificador de la sesion(Salida)
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// ________________________________________________________________________________________________________
bool buscaComandos(char *ido, TRAMA *ptrTrama, int *ids)
{
const char *param, *msglog;
struct og_dbi *dbi;
dbi_result result;
unsigned int lonprm;
dbi = og_dbi_open(&dbi_config);
if (!dbi) {
syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
__func__, __LINE__);
goto err_dbi_open;
}
result = dbi_conn_queryf(dbi->conn,
"SELECT sesion, parametros"\
" FROM acciones WHERE idordenador=%s AND estado='%d'"\
" ORDER BY idaccion", ido, ACCION_INICIADA);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
goto err_query_fail;
}
if (!dbi_result_next_row(result)) {
dbi_result_free(result);
og_dbi_close(dbi);
return false; // No hay comandos pendientes
}
*ids = dbi_result_get_uint(result, "sesion");
param = dbi_result_get_string(result, "parametros");
lonprm = strlen(param);
if(!initParametros(ptrTrama,lonprm + LONGITUD_PARAMETROS)){
syslog(LOG_ERR, "%s:%d OOM\n", __FILE__, __LINE__);
goto err_init_params;
}
sprintf(ptrTrama->parametros, "%s", param);
dbi_result_free(result);
og_dbi_close(dbi);
return true; // Hay comandos pendientes, se toma el primero de la cola
err_init_params:
dbi_result_free(result);
err_query_fail:
og_dbi_close(dbi);
err_dbi_open:
return false;
}
// ________________________________________________________________________________________________________
// Función: DisponibilidadComandos
//
// Descripción:
// Esta función habilita a un cliente para recibir comandos desde la consola
// Parámetros:
// - socket_c: Socket del cliente que envió el mensaje
// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// ________________________________________________________________________________________________________
//
static bool DisponibilidadComandos(TRAMA *ptrTrama, struct og_client *cli)
{
char *iph, *tpc;
int idx;
iph = copiaParametro("iph",ptrTrama); // Toma ip
if (!clienteExistente(iph, &idx)) { // Busca índice del cliente
liberaMemoria(iph);
syslog(LOG_ERR, "client does not exist\n");
return false;
}
tpc = copiaParametro("tpc",ptrTrama); // Tipo de cliente (Plataforma y S.O.)
strcpy(tbsockets[idx].estado, tpc);
cli->keepalive_idx = idx;
liberaMemoria(iph);
liberaMemoria(tpc);
return true;
}
// ________________________________________________________________________________________________________
// Función: respuestaEstandar
//
// Descripción:
// Esta función actualiza la base de datos con el resultado de la ejecución de un comando con seguimiento
// Parámetros:
// - res: resultado de la ejecución del comando
// - der: Descripción del error si hubiese habido
// - iph: Dirección IP
// - ids: identificador de la sesión
// - ido: Identificador del ordenador que notifica
// - db: Objeto base de datos (operativo)
// - tbl: Objeto tabla
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// ________________________________________________________________________________________________________
static bool respuestaEstandar(TRAMA *ptrTrama, char *iph, char *ido,
struct og_dbi *dbi)
{
char *res, *ids, *der;
char fechafin[LONPRM];
const char *msglog;
dbi_result result;
struct tm* st;
int idaccion;
ids = copiaParametro("ids",ptrTrama);
res = copiaParametro("res",ptrTrama);
if (ids == NULL) {
if (atoi(res) == ACCION_FALLIDA) {
liberaMemoria(res);
return false;
}
liberaMemoria(res);
return true;
}
if (atoi(ids) == 0) {
liberaMemoria(ids);
if (atoi(res) == ACCION_FALLIDA) {
liberaMemoria(res);
return false;
}
liberaMemoria(res);
return true;
}
result = dbi_conn_queryf(dbi->conn,
"SELECT * FROM acciones WHERE idordenador=%s"
" AND sesion=%s ORDER BY idaccion", ido,ids);
liberaMemoria(ids);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return false;
}
if (!dbi_result_next_row(result)) {
syslog(LOG_ERR, "no actions available\n");
dbi_result_free(result);
return true;
}
idaccion = dbi_result_get_uint(result, "idaccion");
dbi_result_free(result);
st = tomaHora();
sprintf(fechafin, "%d/%d/%d %d:%d:%d", st->tm_year + 1900, st->tm_mon + 1,
st->tm_mday, st->tm_hour, st->tm_min, st->tm_sec);
der = copiaParametro("der",ptrTrama); // Toma descripción del error (si hubiera habido)
result = dbi_conn_queryf(dbi->conn,
"UPDATE acciones"\
" SET resultado='%s',estado='%d',fechahorafin='%s',descrinotificacion='%s'"\
" WHERE idordenador=%s AND idaccion=%d",
res, ACCION_FINALIZADA, fechafin, der, ido, idaccion);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
liberaMemoria(res);
liberaMemoria(der);
og_info((char *)msglog);
return false;
}
dbi_result_free(result);
liberaMemoria(der);
if (atoi(res) == ACCION_FALLIDA) {
liberaMemoria(res);
return false;
}
liberaMemoria(res);
return true;
}
static bool og_send_cmd(char *ips_array[], int ips_array_len,
const char *state, TRAMA *ptrTrama)
{
int i, idx;
for (i = 0; i < ips_array_len; i++) {
if (clienteDisponible(ips_array[i], &idx)) { // Si el cliente puede recibir comandos
int sock = tbsockets[idx].cli ? tbsockets[idx].cli->io.fd : -1;
strcpy(tbsockets[idx].estado, state); // Actualiza el estado del cliente
if (sock >= 0 && !mandaTrama(&sock, ptrTrama)) {
syslog(LOG_ERR, "failed to send response to %s:%s\n",
ips_array[i], strerror(errno));
}
}
}
return true;
}
// ________________________________________________________________________________________________________
// Función: enviaComando
//
// Descripción:
// Envía un comando a los clientes
// Parámetros:
// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
// - estado: Estado en el se deja al cliente mientras se ejecuta el comando
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// ________________________________________________________________________________________________________
bool enviaComando(TRAMA* ptrTrama, const char *estado)
{
char *iph, *Ipes, *ptrIpes[MAXIMOS_CLIENTES];
int lon;
iph = copiaParametro("iph",ptrTrama); // Toma dirección/es IP
lon = strlen(iph); // Calcula longitud de la cadena de direccion/es IPE/S
Ipes = (char*) reservaMemoria(lon + 1);
if (Ipes == NULL) {
syslog(LOG_ERR, "%s:%d OOM\n", __FILE__, __LINE__);
return false;
}
strcpy(Ipes, iph); // Copia cadena de IPES
liberaMemoria(iph);
lon = splitCadena(ptrIpes, Ipes, ';');
FINCADaINTRO(ptrTrama);
if (!og_send_cmd(ptrIpes, lon, estado, ptrTrama))
return false;
liberaMemoria(Ipes);
return true;
}
//______________________________________________________________________________________________________
// Función: respuestaConsola
//
// Descripción:
// Envia una respuesta a la consola sobre el resultado de la ejecución de un comando
// Parámetros:
// - socket_c: (Salida) Socket utilizado para el envío
// - res: Resultado del envío del comando
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// ________________________________________________________________________________________________________
bool respuestaConsola(int socket_c, TRAMA *ptrTrama, int res)
{
initParametros(ptrTrama,0);
sprintf(ptrTrama->parametros, "res=%d\r", res);
if (!mandaTrama(&socket_c, ptrTrama)) {
syslog(LOG_ERR, "%s:%d failed to send response: %s\n",
__func__, __LINE__, strerror(errno));
return false;
}
return true;
}
// ________________________________________________________________________________________________________
// Función: Levanta
//
// Descripción:
// Enciende ordenadores a través de la red cuyas macs se pasan como parámetro
// Parámetros:
// - iph: Cadena de direcciones ip separadas por ";"
// - mac: Cadena de direcciones mac separadas por ";"
// - mar: Método de arranque (1=Broadcast, 2=Unicast)
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// ________________________________________________________________________________________________________
bool Levanta(char *ptrIP[], char *ptrMacs[], int lon, char *mar)
{
unsigned int on = 1;
struct sockaddr_in local;
int i, res;
int s;
/* Creación de socket para envío de magig packet */
s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s < 0) {
syslog(LOG_ERR, "cannot create socket for magic packet\n");
return false;
}
res = setsockopt(s, SOL_SOCKET, SO_BROADCAST, (unsigned int *) &on,
sizeof(on));
if (res < 0) {
syslog(LOG_ERR, "cannot set broadcast socket\n");
return false;
}
memset(&local, 0, sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(PUERTO_WAKEUP);
local.sin_addr.s_addr = htonl(INADDR_ANY);
for (i = 0; i < lon; i++) {
if (!WakeUp(s, ptrIP[i], ptrMacs[i], mar)) {
syslog(LOG_ERR, "problem sending magic packet\n");
close(s);
return false;
}
}
close(s);
return true;
}
#define OG_WOL_SEQUENCE 6
#define OG_WOL_MACADDR_LEN 6
#define OG_WOL_REPEAT 16
struct wol_msg {
char secuencia_FF[OG_WOL_SEQUENCE];
char macbin[OG_WOL_REPEAT][OG_WOL_MACADDR_LEN];
};
static bool wake_up_broadcast(int sd, struct sockaddr_in *client,
const struct wol_msg *msg)
{
struct sockaddr_in *broadcast_addr;
struct ifaddrs *ifaddr, *ifa;
int ret;
if (getifaddrs(&ifaddr) < 0) {
syslog(LOG_ERR, "cannot get list of addresses\n");
return false;
}
client->sin_addr.s_addr = htonl(INADDR_BROADCAST);
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL ||
ifa->ifa_addr->sa_family != AF_INET ||
strcmp(ifa->ifa_name, interface) != 0)
continue;
broadcast_addr =
(struct sockaddr_in *)ifa->ifa_ifu.ifu_broadaddr;
client->sin_addr.s_addr = broadcast_addr->sin_addr.s_addr;
break;
}
freeifaddrs(ifaddr);
ret = sendto(sd, msg, sizeof(*msg), 0,
(struct sockaddr *)client, sizeof(*client));
if (ret < 0) {
syslog(LOG_ERR, "failed to send broadcast wol\n");
return false;
}
return true;
}
static bool wake_up_unicast(int sd, struct sockaddr_in *client,
const struct wol_msg *msg,
const struct in_addr *addr)
{
int ret;
client->sin_addr.s_addr = addr->s_addr;
ret = sendto(sd, msg, sizeof(*msg), 0,
(struct sockaddr *)client, sizeof(*client));
if (ret < 0) {
syslog(LOG_ERR, "failed to send unicast wol\n");
return false;
}
return true;
}
enum wol_delivery_type {
OG_WOL_BROADCAST = 1,
OG_WOL_UNICAST = 2
};
//_____________________________________________________________________________________________________________
// Función: WakeUp
//
// Descripción:
// Enciende el ordenador cuya MAC se pasa como parámetro
// Parámetros:
// - s : Socket para enviar trama magic packet
// - iph : Cadena con la dirección ip
// - mac : Cadena con la dirección mac en formato XXXXXXXXXXXX
// - mar: Método de arranque (1=Broadcast, 2=Unicast)
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
//_____________________________________________________________________________________________________________
//
bool WakeUp(int s, char* iph, char *mac, char *mar)
{
unsigned int macaddr[OG_WOL_MACADDR_LEN];
char HDaddress_bin[OG_WOL_MACADDR_LEN];
struct sockaddr_in WakeUpCliente;
struct wol_msg Trama_WakeUp;
struct in_addr addr;
bool ret;
int i;
for (i = 0; i < 6; i++) // Primera secuencia de la trama Wake Up (0xFFFFFFFFFFFF)
Trama_WakeUp.secuencia_FF[i] = 0xFF;
sscanf(mac, "%02x%02x%02x%02x%02x%02x",
&macaddr[0], &macaddr[1], &macaddr[2],
&macaddr[3], &macaddr[4], &macaddr[5]);
for (i = 0; i < 6; i++)
HDaddress_bin[i] = (uint8_t)macaddr[i];
for (i = 0; i < 16; i++) // Segunda secuencia de la trama Wake Up , repetir 16 veces su la MAC
memcpy(&Trama_WakeUp.macbin[i][0], &HDaddress_bin, 6);
/* Creación de socket del cliente que recibe la trama magic packet */
WakeUpCliente.sin_family = AF_INET;
WakeUpCliente.sin_port = htons((short) PUERTO_WAKEUP);
switch (atoi(mar)) {
case OG_WOL_BROADCAST:
ret = wake_up_broadcast(s, &WakeUpCliente, &Trama_WakeUp);
break;
case OG_WOL_UNICAST:
if (inet_aton(iph, &addr) < 0) {
syslog(LOG_ERR, "bad IP address for unicast wol\n");
ret = false;
break;
}
ret = wake_up_unicast(s, &WakeUpCliente, &Trama_WakeUp, &addr);
break;
default:
syslog(LOG_ERR, "unknown wol type\n");
ret = false;
break;
}
return ret;
}
// ________________________________________________________________________________________________________
// Función: RESPUESTA_Arrancar
//
// Descripción:
// Respuesta del cliente al comando Arrancar
// Parámetros:
// - socket_c: Socket del cliente que envió el mensaje
// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// ________________________________________________________________________________________________________
static bool RESPUESTA_Arrancar(TRAMA* ptrTrama, struct og_client *cli)
{
struct og_dbi *dbi;
char *iph, *ido;
char *tpc;
int i;
dbi = og_dbi_open(&dbi_config);
if (!dbi) {
syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
__func__, __LINE__);
return false;
}
iph = copiaParametro("iph",ptrTrama); // Toma dirección ip
ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) {
liberaMemoria(iph);
liberaMemoria(ido);
syslog(LOG_ERR, "failed to register notification\n");
og_dbi_close(dbi);
return false;
}
tpc = copiaParametro("tpc",ptrTrama); // Tipo de cliente (Plataforma y S.O.)
if (clienteExistente(iph, &i)) // Actualiza estado
strcpy(tbsockets[i].estado, tpc);
liberaMemoria(iph);
liberaMemoria(ido);
liberaMemoria(tpc);
og_dbi_close(dbi);
return true;
}
// ________________________________________________________________________________________________________
// Función: RESPUESTA_Apagar
//
// Descripción:
// Respuesta del cliente al comando Apagar
// Parámetros:
// - socket_c: Socket del cliente que envió el mensaje
// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// ________________________________________________________________________________________________________
static bool RESPUESTA_Apagar(TRAMA* ptrTrama, struct og_client *cli)
{
struct og_dbi *dbi;
char *iph, *ido;
int i;
dbi = og_dbi_open(&dbi_config);
if (!dbi) {
syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
__func__, __LINE__);
return false;
}
iph = copiaParametro("iph",ptrTrama); // Toma dirección ip
ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) {
liberaMemoria(iph);
liberaMemoria(ido);
syslog(LOG_ERR, "failed to register notification\n");
og_dbi_close(dbi);
return false; // Error al registrar notificacion
}
if (clienteExistente(iph, &i)) // Actualiza estado
strcpy(tbsockets[i].estado, CLIENTE_APAGADO);
liberaMemoria(iph);
liberaMemoria(ido);
og_dbi_close(dbi);
return true;
}
// ________________________________________________________________________________________________________
// Función: RESPUESTA_CrearImagen
//
// Descripción:
// Respuesta del cliente al comando CrearImagen
// Parámetros:
// - socket_c: Socket del cliente que envió el mensaje
// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// ________________________________________________________________________________________________________
static bool RESPUESTA_CrearImagen(TRAMA* ptrTrama, struct og_client *cli)
{
char *iph, *dsk, *par, *cpt, *ipr, *ido;
struct og_dbi *dbi;
char *idi;
bool res;
dbi = og_dbi_open(&dbi_config);
if (!dbi) {
syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
__func__, __LINE__);
return false;
}
iph = copiaParametro("iph",ptrTrama); // Toma dirección ip
ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) {
liberaMemoria(iph);
liberaMemoria(ido);
syslog(LOG_ERR, "failed to register notification\n");
og_dbi_close(dbi);
return false; // Error al registrar notificacion
}
// Acciones posteriores
idi = copiaParametro("idi",ptrTrama);
dsk = copiaParametro("dsk",ptrTrama);
par = copiaParametro("par",ptrTrama);
cpt = copiaParametro("cpt",ptrTrama);
ipr = copiaParametro("ipr",ptrTrama);
res=actualizaCreacionImagen(dbi, idi, dsk, par, cpt, ipr, ido);
liberaMemoria(idi);
liberaMemoria(par);
liberaMemoria(cpt);
liberaMemoria(ipr);
og_dbi_close(dbi);
if (!res)
syslog(LOG_ERR, "Problem processing update\n");
return res;
}
// ________________________________________________________________________________________________________
// Función: actualizaCreacionImagen
//
// Descripción:
// Esta función actualiza la base de datos con el resultado de la creación de una imagen
// Parámetros:
// - db: Objeto base de datos (ya operativo)
// - tbl: Objeto tabla
// - idi: Identificador de la imagen
// - dsk: Disco de donde se creó
// - par: Partición de donde se creó
// - cpt: Código de partición
// - ipr: Ip del repositorio
// - ido: Identificador del ordenador modelo
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// ________________________________________________________________________________________________________
bool actualizaCreacionImagen(struct og_dbi *dbi, char *idi, char *dsk,
char *par, char *cpt, char *ipr, char *ido)
{
const char *msglog;
dbi_result result;
int idr,ifs;
/* Toma identificador del repositorio correspondiente al ordenador modelo */
result = dbi_conn_queryf(dbi->conn,
"SELECT repositorios.idrepositorio"
" FROM repositorios"
" LEFT JOIN ordenadores USING (idrepositorio)"
" WHERE repositorios.ip='%s' AND ordenadores.idordenador=%s", ipr, ido);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return false;
}
if (!dbi_result_next_row(result)) {
syslog(LOG_ERR,
"repository does not exist in database (%s:%d)\n",
__func__, __LINE__);
dbi_result_free(result);
return false;
}
idr = dbi_result_get_uint(result, "idrepositorio");
dbi_result_free(result);
/* Toma identificador del perfilsoftware */
result = dbi_conn_queryf(dbi->conn,
"SELECT idperfilsoft"
" FROM ordenadores_particiones"
" WHERE idordenador=%s AND numdisk=%s AND numpar=%s", ido, dsk, par);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return false;
}
if (!dbi_result_next_row(result)) {
syslog(LOG_ERR,
"software profile does not exist in database (%s:%d)\n",
__func__, __LINE__);
dbi_result_free(result);
return false;
}
ifs = dbi_result_get_uint(result, "idperfilsoft");
dbi_result_free(result);
/* Actualizar los datos de la imagen */
result = dbi_conn_queryf(dbi->conn,
"UPDATE imagenes"
" SET idordenador=%s, numdisk=%s, numpar=%s, codpar=%s,"
" idperfilsoft=%d, idrepositorio=%d,"
" fechacreacion=NOW(), revision=revision+1"
" WHERE idimagen=%s", ido, dsk, par, cpt, ifs, idr, idi);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return false;
}
dbi_result_free(result);
/* Actualizar los datos en el cliente */
result = dbi_conn_queryf(dbi->conn,
"UPDATE ordenadores_particiones"
" SET idimagen=%s, revision=(SELECT revision FROM imagenes WHERE idimagen=%s),"
" fechadespliegue=NOW()"
" WHERE idordenador=%s AND numdisk=%s AND numpar=%s",
idi, idi, ido, dsk, par);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return false;
}
dbi_result_free(result);
return true;
}
// ________________________________________________________________________________________________________
// Función: RESPUESTA_CrearImagenBasica
//
// Descripción:
// Respuesta del cliente al comando CrearImagenBasica
// Parámetros:
// - socket_c: Socket del cliente que envió el mensaje
// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// ________________________________________________________________________________________________________
static bool RESPUESTA_CrearImagenBasica(TRAMA* ptrTrama, struct og_client *cli)
{
// La misma respuesta que la creación de imagen monolítica
return RESPUESTA_CrearImagen(ptrTrama, cli);
}
// ________________________________________________________________________________________________________
// Función: RESPUESTA_CrearSoftIncremental
//
// Descripción:
// Respuesta del cliente al comando crearImagenDiferencial
// Parámetros:
// - socket_c: Socket del cliente que envió el mensaje
// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// ________________________________________________________________________________________________________
static bool RESPUESTA_CrearSoftIncremental(TRAMA* ptrTrama, struct og_client *cli)
{
char *iph,*par,*ido,*idf;
int ifs;
const char *msglog;
struct og_dbi *dbi;
dbi_result result;
dbi = og_dbi_open(&dbi_config);
if (!dbi) {
syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
__func__, __LINE__);
return false;
}
iph = copiaParametro("iph",ptrTrama); // Toma dirección ip
ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) {
og_dbi_close(dbi);
liberaMemoria(iph);
liberaMemoria(ido);
syslog(LOG_ERR, "failed to register notification\n");
return false;
}
par = copiaParametro("par",ptrTrama);
/* Toma identificador del perfilsoftware creado por el inventario de software */
result = dbi_conn_queryf(dbi->conn,
"SELECT idperfilsoft FROM ordenadores_particiones WHERE idordenador=%s AND numpar=%s",
ido, par);
liberaMemoria(iph);
liberaMemoria(ido);
liberaMemoria(par);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
og_dbi_close(dbi);
return false;
}
if (!dbi_result_next_row(result)) {
syslog(LOG_ERR,
"software profile does not exist in database (%s:%d)\n",
__func__, __LINE__);
dbi_result_free(result);
og_dbi_close(dbi);
return false;
}
ifs = dbi_result_get_uint(result, "idperfilsoft");
dbi_result_free(result);
/* Actualizar los datos de la imagen */
idf = copiaParametro("idf", ptrTrama);
result = dbi_conn_queryf(dbi->conn,
"UPDATE imagenes SET idperfilsoft=%d WHERE idimagen=%s",
ifs, idf);
liberaMemoria(idf);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
og_dbi_close(dbi);
return false;
}
dbi_result_free(result);
og_dbi_close(dbi);
return true;
}
// ________________________________________________________________________________________________________
// Función: RESPUESTA_RestaurarImagen
//
// Descripción:
// Respuesta del cliente al comando RestaurarImagen
// Parámetros:
// - socket_c: Socket del cliente que envió el mensaje
// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// ________________________________________________________________________________________________________
//
static bool RESPUESTA_RestaurarImagen(TRAMA* ptrTrama, struct og_client *cli)
{
bool res;
char *iph, *ido, *idi, *dsk, *par, *ifs, *cfg;
struct og_dbi *dbi;
dbi = og_dbi_open(&dbi_config);
if (!dbi) {
syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
__func__, __LINE__);
return false;
}
iph = copiaParametro("iph",ptrTrama); // Toma dirección ip
ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) {
og_dbi_close(dbi);
liberaMemoria(iph);
liberaMemoria(ido);
syslog(LOG_ERR, "failed to register notification\n");
return false;
}
// Acciones posteriores
idi = copiaParametro("idi",ptrTrama); // Toma identificador de la imagen
dsk = copiaParametro("dsk",ptrTrama); // Número de disco
par = copiaParametro("par",ptrTrama); // Número de partición
ifs = copiaParametro("ifs",ptrTrama); // Identificador del perfil software contenido
cfg = copiaParametro("cfg",ptrTrama); // Configuración de discos
if(cfg){
actualizaConfiguracion(dbi, cfg, atoi(ido)); // Actualiza la configuración del ordenador
liberaMemoria(cfg);
}
res=actualizaRestauracionImagen(dbi, idi, dsk, par, ido, ifs);
liberaMemoria(iph);
liberaMemoria(ido);
liberaMemoria(idi);
liberaMemoria(par);
liberaMemoria(ifs);
og_dbi_close(dbi);
if(!res)
syslog(LOG_ERR, "Problem after restoring image\n");
return res;
}
// ________________________________________________________________________________________________________
//
// Función: RESPUESTA_RestaurarImagenBasica
//
// Descripción:
// Respuesta del cliente al comando RestaurarImagen
// Parámetros:
// - socket_c: Socket del cliente que envió el mensaje
// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// ________________________________________________________________________________________________________
//
static bool RESPUESTA_RestaurarImagenBasica(TRAMA* ptrTrama, struct og_client *cli)
{
return RESPUESTA_RestaurarImagen(ptrTrama, cli);
}
// ________________________________________________________________________________________________________
// Función: RESPUESTA_RestaurarSoftIncremental
//
// Descripción:
// Respuesta del cliente al comando RestaurarSoftIncremental
// Parámetros:
// - socket_c: Socket del cliente que envió el mensaje
// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// ________________________________________________________________________________________________________
static bool RESPUESTA_RestaurarSoftIncremental(TRAMA* ptrTrama, struct og_client *cli)
{
return RESPUESTA_RestaurarImagen(ptrTrama, cli);
}
// ________________________________________________________________________________________________________
// Función: actualizaRestauracionImagen
//
// Descripción:
// Esta función actualiza la base de datos con el resultado de la restauración de una imagen
// Parámetros:
// - db: Objeto base de datos (ya operativo)
// - tbl: Objeto tabla
// - idi: Identificador de la imagen
// - dsk: Disco de donde se restauró
// - par: Partición de donde se restauró
// - ido: Identificador del cliente donde se restauró
// - ifs: Identificador del perfil software contenido en la imagen
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// ________________________________________________________________________________________________________
bool actualizaRestauracionImagen(struct og_dbi *dbi, char *idi,
char *dsk, char *par, char *ido, char *ifs)
{
const char *msglog;
dbi_result result;
/* Actualizar los datos de la imagen */
result = dbi_conn_queryf(dbi->conn,
"UPDATE ordenadores_particiones"
" SET idimagen=%s, idperfilsoft=%s, fechadespliegue=NOW(),"
" revision=(SELECT revision FROM imagenes WHERE idimagen=%s),"
" idnombreso=IFNULL((SELECT idnombreso FROM perfilessoft WHERE idperfilsoft=%s),0)"
" WHERE idordenador=%s AND numdisk=%s AND numpar=%s", idi, ifs, idi, ifs, ido, dsk, par);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return false;
}
dbi_result_free(result);
return true;
}
// ________________________________________________________________________________________________________
// Función: RESPUESTA_EjecutarScript
//
// Descripción:
// Respuesta del cliente al comando EjecutarScript
// Parámetros:
// - socket_c: Socket del cliente que envió el mensaje
// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// ________________________________________________________________________________________________________
static bool RESPUESTA_EjecutarScript(TRAMA* ptrTrama, struct og_client *cli)
{
char *iph, *ido,*cfg;
struct og_dbi *dbi;
bool res = true;
dbi = og_dbi_open(&dbi_config);
if (!dbi) {
syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
__func__, __LINE__);
return false;
}
iph = copiaParametro("iph",ptrTrama); // Toma dirección ip
ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) {
og_dbi_close(dbi);
liberaMemoria(iph);
liberaMemoria(ido);
syslog(LOG_ERR, "failed to register notification\n");
return false;
}
cfg = copiaParametro("cfg",ptrTrama); // Toma configuración de particiones
if(cfg){
res = actualizaConfiguracion(dbi, cfg, atoi(ido)); // Actualiza la configuración del ordenador
liberaMemoria(cfg);
}
liberaMemoria(iph);
liberaMemoria(ido);
og_dbi_close(dbi);
if (!res)
syslog(LOG_ERR, "Problem updating client configuration\n");
return res;
}
// ________________________________________________________________________________________________________
// Función: RESPUESTA_InventarioHardware
//
// Descripción:
// Respuesta del cliente al comando InventarioHardware
// Parámetros:
// - socket_c: Socket del cliente que envió el mensaje
// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// ________________________________________________________________________________________________________
static bool RESPUESTA_InventarioHardware(TRAMA* ptrTrama, struct og_client *cli)
{
bool res;
char *iph, *ido, *idc, *npc, *hrd, *buffer;
struct og_dbi *dbi;
dbi = og_dbi_open(&dbi_config);
if (!dbi) {
syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
__func__, __LINE__);
return false;
}
iph = copiaParametro("iph",ptrTrama); // Toma dirección ip del cliente
ido = copiaParametro("ido",ptrTrama); // Toma identificador del cliente
if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) {
og_dbi_close(dbi);
liberaMemoria(iph);
liberaMemoria(ido);
syslog(LOG_ERR, "failed to register notification\n");
return false;
}
// Lee archivo de inventario enviado anteriormente
hrd = copiaParametro("hrd",ptrTrama);
buffer = rTrim(leeArchivo(hrd));
npc = copiaParametro("npc",ptrTrama);
idc = copiaParametro("idc",ptrTrama); // Toma identificador del Centro
if (buffer)
res=actualizaHardware(dbi, buffer, ido, npc, idc);
else
res = false;
liberaMemoria(iph);
liberaMemoria(ido);
liberaMemoria(npc);
liberaMemoria(idc);
liberaMemoria(buffer);
og_dbi_close(dbi);
if (!res)
syslog(LOG_ERR, "Problem updating client configuration\n");
return res;
}
// ________________________________________________________________________________________________________
// Función: actualizaHardware
//
// Descripción:
// Actualiza la base de datos con la configuracion hardware del cliente
// Parámetros:
// - db: Objeto base de datos (ya operativo)
// - tbl: Objeto tabla
// - hrd: cadena con el inventario hardware
// - ido: Identificador del ordenador
// - npc: Nombre del ordenador
// - idc: Identificador del centro o Unidad organizativa
// ________________________________________________________________________________________________________
//
bool actualizaHardware(struct og_dbi *dbi, char *hrd, char *ido, char *npc,
char *idc)
{
const char *msglog;
int idtipohardware, idperfilhard;
int lon, i, j, aux;
bool retval;
char *whard;
int tbidhardware[MAXHARDWARE];
char *tbHardware[MAXHARDWARE],*dualHardware[2], strInt[LONINT], *idhardwares;
dbi_result result;
/* Toma Centro (Unidad Organizativa) */
result = dbi_conn_queryf(dbi->conn,
"SELECT idperfilhard FROM ordenadores WHERE idordenador=%s",
ido);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return false;
}
if (!dbi_result_next_row(result)) {
syslog(LOG_ERR, "client does not exist in database (%s:%d)\n",
__func__, __LINE__);
dbi_result_free(result);
return false;
}
idperfilhard = dbi_result_get_uint(result, "idperfilhard");
dbi_result_free(result);
whard=escaparCadena(hrd); // Codificar comillas simples
if(!whard)
return false;
/* Recorre componentes hardware*/
lon = splitCadena(tbHardware, whard, '\n');
if (lon > MAXHARDWARE)
lon = MAXHARDWARE; // Limita el número de componentes hardware
/*
for (i=0;i<lon;i++){
sprintf(msglog,"Linea de inventario: %s",tbHardware[i]);
RegistraLog(msglog,false);
}
*/
for (i = 0; i < lon; i++) {
splitCadena(dualHardware, rTrim(tbHardware[i]), '=');
//sprintf(msglog,"nemonico: %s",dualHardware[0]);
//RegistraLog(msglog,false);
//sprintf(msglog,"valor: %s",dualHardware[1]);
//RegistraLog(msglog,false);
result = dbi_conn_queryf(dbi->conn,
"SELECT idtipohardware,descripcion FROM tipohardwares WHERE nemonico='%s'",
dualHardware[0]);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return false;
}
if (!dbi_result_next_row(result)) { // Tipo de Hardware NO existente
dbi_result_free(result);
return false;
} else { // Tipo de Hardware Existe
idtipohardware = dbi_result_get_uint(result, "idtipohardware");
dbi_result_free(result);
result = dbi_conn_queryf(dbi->conn,
"SELECT idhardware FROM hardwares WHERE idtipohardware=%d AND descripcion='%s'",
idtipohardware, dualHardware[1]);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return false;
}
if (!dbi_result_next_row(result)) { // Hardware NO existente
dbi_result_free(result);
result = dbi_conn_queryf(dbi->conn,
"INSERT hardwares (idtipohardware,descripcion,idcentro,grupoid) "
" VALUES(%d,'%s',%s,0)", idtipohardware,
dualHardware[1], idc);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return false;
}
// Recupera el identificador del hardware
tbidhardware[i] = dbi_conn_sequence_last(dbi->conn, NULL);
} else {
tbidhardware[i] = dbi_result_get_uint(result, "idhardware");
}
dbi_result_free(result);
}
}
// Ordena tabla de identificadores para cosultar si existe un pefil con esas especificaciones
for (i = 0; i < lon - 1; i++) {
for (j = i + 1; j < lon; j++) {
if (tbidhardware[i] > tbidhardware[j]) {
aux = tbidhardware[i];
tbidhardware[i] = tbidhardware[j];
tbidhardware[j] = aux;
}
}
}
/* Crea cadena de identificadores de componentes hardware separados por coma */
sprintf(strInt, "%d", tbidhardware[lon - 1]); // Pasa a cadena el último identificador que es de mayor longitud
aux = strlen(strInt); // Calcula longitud de cadena para reservar espacio a todos los perfiles
idhardwares = reservaMemoria(sizeof(aux) * lon + lon);
if (idhardwares == NULL) {
syslog(LOG_ERR, "%s:%d OOM\n", __FILE__, __LINE__);
return false;
}
aux = sprintf(idhardwares, "%d", tbidhardware[0]);
for (i = 1; i < lon; i++)
aux += sprintf(idhardwares + aux, ",%d", tbidhardware[i]);
if (!cuestionPerfilHardware(dbi, idc, ido, idperfilhard, idhardwares,
npc, tbidhardware, lon)) {
syslog(LOG_ERR, "Problem updating client hardware\n");
retval=false;
}
else {
retval=true;
}
liberaMemoria(whard);
liberaMemoria(idhardwares);
return (retval);
}
// ________________________________________________________________________________________________________
// Función: cuestionPerfilHardware
//
// Descripción:
// Comprueba existencia de perfil hardware y actualización de éste para el ordenador
// Parámetros:
// - db: Objeto base de datos (ya operativo)
// - tbl: Objeto tabla
// - idc: Identificador de la Unidad organizativa donde se encuentra el cliente
// - ido: Identificador del ordenador
// - tbidhardware: Identificador del tipo de hardware
// - con: Número de componentes detectados para configurar un el perfil hardware
// - npc: Nombre del cliente
// ________________________________________________________________________________________________________
bool cuestionPerfilHardware(struct og_dbi *dbi, char *idc, char *ido,
int idperfilhardware, char *idhardwares, char *npc, int *tbidhardware,
int lon)
{
const char *msglog;
dbi_result result;
int i;
int nwidperfilhard;
// Busca perfil hard del ordenador que contenga todos los componentes hardware encontrados
result = dbi_conn_queryf(dbi->conn,
"SELECT idperfilhard FROM"
" (SELECT perfileshard_hardwares.idperfilhard as idperfilhard,"
" group_concat(cast(perfileshard_hardwares.idhardware AS char( 11) )"
" ORDER BY perfileshard_hardwares.idhardware SEPARATOR ',' ) AS idhardwares"
" FROM perfileshard_hardwares"
" GROUP BY perfileshard_hardwares.idperfilhard) AS temp"
" WHERE idhardwares LIKE '%s'", idhardwares);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return false;
}
if (!dbi_result_next_row(result)) {
// No existe un perfil hardware con esos componentes de componentes hardware, lo crea
dbi_result_free(result);
result = dbi_conn_queryf(dbi->conn,
"INSERT perfileshard (descripcion,idcentro,grupoid)"
" VALUES('Perfil hardware (%s) ',%s,0)", npc, idc);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return false;
}
dbi_result_free(result);
// Recupera el identificador del nuevo perfil hardware
nwidperfilhard = dbi_conn_sequence_last(dbi->conn, NULL);
// Crea la relación entre perfiles y componenetes hardware
for (i = 0; i < lon; i++) {
result = dbi_conn_queryf(dbi->conn,
"INSERT perfileshard_hardwares (idperfilhard,idhardware)"
" VALUES(%d,%d)", nwidperfilhard, tbidhardware[i]);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return false;
}
dbi_result_free(result);
}
} else { // Existe un perfil con todos esos componentes
nwidperfilhard = dbi_result_get_uint(result, "idperfilhard");
dbi_result_free(result);
}
if (idperfilhardware != nwidperfilhard) { // No coinciden los perfiles
// Actualiza el identificador del perfil hardware del ordenador
result = dbi_conn_queryf(dbi->conn,
"UPDATE ordenadores SET idperfilhard=%d"
" WHERE idordenador=%s", nwidperfilhard, ido);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return false;
}
dbi_result_free(result);
}
/* Eliminar Relación de hardwares con Perfiles hardware que quedan húerfanos */
result = dbi_conn_queryf(dbi->conn,
"DELETE FROM perfileshard_hardwares WHERE idperfilhard IN "
" (SELECT idperfilhard FROM perfileshard WHERE idperfilhard NOT IN"
" (SELECT DISTINCT idperfilhard from ordenadores))");
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return false;
}
dbi_result_free(result);
/* Eliminar Perfiles hardware que quedan húerfanos */
result = dbi_conn_queryf(dbi->conn,
"DELETE FROM perfileshard WHERE idperfilhard NOT IN"
" (SELECT DISTINCT idperfilhard FROM ordenadores)");
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return false;
}
dbi_result_free(result);
/* Eliminar Relación de hardwares con Perfiles hardware que quedan húerfanos */
result = dbi_conn_queryf(dbi->conn,
"DELETE FROM perfileshard_hardwares WHERE idperfilhard NOT IN"
" (SELECT idperfilhard FROM perfileshard)");
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return false;
}
dbi_result_free(result);
return true;
}
// ________________________________________________________________________________________________________
// Función: RESPUESTA_InventarioSoftware
//
// Descripción:
// Respuesta del cliente al comando InventarioSoftware
// Parámetros:
// - socket_c: Socket del cliente que envió el mensaje
// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// ________________________________________________________________________________________________________
static bool RESPUESTA_InventarioSoftware(TRAMA* ptrTrama, struct og_client *cli)
{
bool res;
char *iph, *ido, *npc, *idc, *par, *sft, *buffer;
struct og_dbi *dbi;
dbi = og_dbi_open(&dbi_config);
if (!dbi) {
syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
__func__, __LINE__);
return false;
}
iph = copiaParametro("iph",ptrTrama); // Toma dirección ip
ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) {
og_dbi_close(dbi);
liberaMemoria(iph);
liberaMemoria(ido);
syslog(LOG_ERR, "failed to register notification\n");
return false;
}
npc = copiaParametro("npc",ptrTrama);
idc = copiaParametro("idc",ptrTrama); // Toma identificador del Centro
par = copiaParametro("par",ptrTrama);
sft = copiaParametro("sft",ptrTrama);
buffer = rTrim(leeArchivo(sft));
if (buffer)
res=actualizaSoftware(dbi, buffer, par, ido, npc, idc);
else
res = false;
liberaMemoria(iph);
liberaMemoria(ido);
liberaMemoria(npc);
liberaMemoria(idc);
liberaMemoria(par);
liberaMemoria(sft);
og_dbi_close(dbi);
if (!res)
syslog(LOG_ERR, "cannot update software\n");
return res;
}
// ________________________________________________________________________________________________________
// Función: actualizaSoftware
//
// Descripción:
// Actualiza la base de datos con la configuración software del cliente
// Parámetros:
// - db: Objeto base de datos (ya operativo)
// - tbl: Objeto tabla
// - sft: cadena con el inventario software
// - par: Número de la partición
// - ido: Identificador del ordenador del cliente en la tabla
// - npc: Nombre del ordenador
// - idc: Identificador del centro o Unidad organizativa
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
//
// Versión 1.1.0: Se incluye el sistema operativo. Autora: Irina Gómez - ETSII Universidad Sevilla
// ________________________________________________________________________________________________________
bool actualizaSoftware(struct og_dbi *dbi, char *sft, char *par,char *ido,
char *npc, char *idc)
{
int i, j, lon, aux, idperfilsoft, idnombreso;
bool retval;
char *wsft;
int tbidsoftware[MAXSOFTWARE];
char *tbSoftware[MAXSOFTWARE], strInt[LONINT], *idsoftwares;
const char *msglog;
dbi_result result;
/* Toma Centro (Unidad Organizativa) y perfil software */
result = dbi_conn_queryf(dbi->conn,
"SELECT idperfilsoft,numpar"
" FROM ordenadores_particiones"
" WHERE idordenador=%s", ido);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return false;
}
idperfilsoft = 0; // Por defecto se supone que el ordenador no tiene aún detectado el perfil software
while (dbi_result_next_row(result)) {
aux = dbi_result_get_uint(result, "numpar");
if (aux == atoi(par)) { // Se encuentra la partición
idperfilsoft = dbi_result_get_uint(result, "idperfilsoft");
break;
}
}
dbi_result_free(result);
wsft=escaparCadena(sft); // Codificar comillas simples
if(!wsft)
return false;
/* Recorre componentes software*/
lon = splitCadena(tbSoftware, wsft, '\n');
if (lon == 0)
return true; // No hay lineas que procesar
if (lon > MAXSOFTWARE)
lon = MAXSOFTWARE; // Limita el número de componentes software
idnombreso = 0;
for (i = 0; i < lon; i++) {
// Primera línea es el sistema operativo: se obtiene identificador
if (i == 0) {
idnombreso = checkDato(dbi, rTrim(tbSoftware[i]), "nombresos", "nombreso", "idnombreso");
continue;
}
result = dbi_conn_queryf(dbi->conn,
"SELECT idsoftware FROM softwares WHERE descripcion ='%s'",
rTrim(tbSoftware[i]));
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return false;
}
if (!dbi_result_next_row(result)) {
dbi_result_free(result);
result = dbi_conn_queryf(dbi->conn,
"INSERT INTO softwares (idtiposoftware,descripcion,idcentro,grupoid)"
" VALUES(2,'%s',%s,0)", tbSoftware[i], idc);
if (!result) { // Error al insertar
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return false;
}
// Recupera el identificador del software
tbidsoftware[i] = dbi_conn_sequence_last(dbi->conn, NULL);
} else {
tbidsoftware[i] = dbi_result_get_uint(result, "idsoftware");
}
dbi_result_free(result);
}
// Ordena tabla de identificadores para cosultar si existe un pefil con esas especificaciones
for (i = 0; i < lon - 1; i++) {
for (j = i + 1; j < lon; j++) {
if (tbidsoftware[i] > tbidsoftware[j]) {
aux = tbidsoftware[i];
tbidsoftware[i] = tbidsoftware[j];
tbidsoftware[j] = aux;
}
}
}
/* Crea cadena de identificadores de componentes software separados por coma */
sprintf(strInt, "%d", tbidsoftware[lon - 1]); // Pasa a cadena el último identificador que es de mayor longitud
aux = strlen(strInt); // Calcula longitud de cadena para reservar espacio a todos los perfiles
idsoftwares = reservaMemoria((sizeof(aux)+1) * lon + lon);
if (idsoftwares == NULL) {
syslog(LOG_ERR, "%s:%d OOM\n", __FILE__, __LINE__);
return false;
}
aux = sprintf(idsoftwares, "%d", tbidsoftware[0]);
for (i = 1; i < lon; i++)
aux += sprintf(idsoftwares + aux, ",%d", tbidsoftware[i]);
// Comprueba existencia de perfil software y actualización de éste para el ordenador
if (!cuestionPerfilSoftware(dbi, idc, ido, idperfilsoft, idnombreso, idsoftwares,
npc, par, tbidsoftware, lon)) {
syslog(LOG_ERR, "cannot update software\n");
og_info((char *)msglog);
retval=false;
}
else {
retval=true;
}
liberaMemoria(wsft);
liberaMemoria(idsoftwares);
return (retval);
}
// ________________________________________________________________________________________________________
// Función: CuestionPerfilSoftware
//
// Parámetros:
// - db: Objeto base de datos (ya operativo)
// - tbl: Objeto tabla
// - idcentro: Identificador del centro en la tabla
// - ido: Identificador del ordenador del cliente en la tabla
// - idnombreso: Identificador del sistema operativo
// - idsoftwares: Cadena con los identificadores de componentes software separados por comas
// - npc: Nombre del ordenador del cliente
// - particion: Número de la partición
// - tbidsoftware: Array con los identificadores de componentes software
// - lon: Número de componentes
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
//
// Versión 1.1.0: Se incluye el sistema operativo. Autora: Irina Gómez - ETSII Universidad Sevilla
//_________________________________________________________________________________________________________
bool cuestionPerfilSoftware(struct og_dbi *dbi, char *idc, char *ido,
int idperfilsoftware, int idnombreso,
char *idsoftwares, char *npc, char *par,
int *tbidsoftware, int lon)
{
int i, nwidperfilsoft;
const char *msglog;
dbi_result result;
// Busca perfil soft del ordenador que contenga todos los componentes software encontrados
result = dbi_conn_queryf(dbi->conn,
"SELECT idperfilsoft FROM"
" (SELECT perfilessoft_softwares.idperfilsoft as idperfilsoft,"
" group_concat(cast(perfilessoft_softwares.idsoftware AS char( 11) )"
" ORDER BY perfilessoft_softwares.idsoftware SEPARATOR ',' ) AS idsoftwares"
" FROM perfilessoft_softwares"
" GROUP BY perfilessoft_softwares.idperfilsoft) AS temp"
" WHERE idsoftwares LIKE '%s'", idsoftwares);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return false;
}
if (!dbi_result_next_row(result)) { // No existe un perfil software con esos componentes de componentes software, lo crea
dbi_result_free(result);
result = dbi_conn_queryf(dbi->conn,
"INSERT perfilessoft (descripcion, idcentro, grupoid, idnombreso)"
" VALUES('Perfil Software (%s, Part:%s) ',%s,0,%i)", npc, par, idc,idnombreso);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
og_info((char *)msglog);
return false;
}
dbi_result_free(result);
// Recupera el identificador del nuevo perfil software
nwidperfilsoft = dbi_conn_sequence_last(dbi->conn, NULL);
// Crea la relación entre perfiles y componenetes software
for (i = 0; i < lon; i++) {
result = dbi_conn_queryf(dbi->conn,
"INSERT perfilessoft_softwares (idperfilsoft,idsoftware)"
" VALUES(%d,%d)", nwidperfilsoft, tbidsoftware[i]);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
og_info((char *)msglog);
return false;
}
dbi_result_free(result);
}
} else { // Existe un perfil con todos esos componentes
nwidperfilsoft = dbi_result_get_uint(result, "idperfilsoft");
dbi_result_free(result);
}
if (idperfilsoftware != nwidperfilsoft) { // No coinciden los perfiles
// Actualiza el identificador del perfil software del ordenador
result = dbi_conn_queryf(dbi->conn,
"UPDATE ordenadores_particiones SET idperfilsoft=%d,idimagen=0"
" WHERE idordenador=%s AND numpar=%s", nwidperfilsoft, ido, par);
if (!result) { // Error al insertar
dbi_conn_error(dbi->conn, &msglog);
og_info((char *)msglog);
return false;
}
dbi_result_free(result);
}
/* DEPURACIÓN DE PERFILES SOFTWARE */
/* Eliminar Relación de softwares con Perfiles software que quedan húerfanos */
result = dbi_conn_queryf(dbi->conn,
"DELETE FROM perfilessoft_softwares WHERE idperfilsoft IN "\
" (SELECT idperfilsoft FROM perfilessoft WHERE idperfilsoft NOT IN"\
" (SELECT DISTINCT idperfilsoft from ordenadores_particiones) AND idperfilsoft NOT IN"\
" (SELECT DISTINCT idperfilsoft from imagenes))");
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
og_info((char *)msglog);
return false;
}
dbi_result_free(result),
/* Eliminar Perfiles software que quedan húerfanos */
result = dbi_conn_queryf(dbi->conn,
"DELETE FROM perfilessoft WHERE idperfilsoft NOT IN"
" (SELECT DISTINCT idperfilsoft from ordenadores_particiones)"\
" AND idperfilsoft NOT IN"\
" (SELECT DISTINCT idperfilsoft from imagenes)");
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
og_info((char *)msglog);
return false;
}
dbi_result_free(result),
/* Eliminar Relación de softwares con Perfiles software que quedan húerfanos */
result = dbi_conn_queryf(dbi->conn,
"DELETE FROM perfilessoft_softwares WHERE idperfilsoft NOT IN"
" (SELECT idperfilsoft from perfilessoft)");
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
og_info((char *)msglog);
return false;
}
dbi_result_free(result);
return true;
}
// ________________________________________________________________________________________________________
// Función: enviaArchivo
//
// Descripción:
// Envia un archivo por la red, por bloques
// Parámetros:
// - socket_c: Socket del cliente que envió el mensaje
// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// ________________________________________________________________________________________________________
static bool enviaArchivo(TRAMA *ptrTrama, struct og_client *cli)
{
int socket_c = og_client_socket(cli);
char *nfl;
// Toma parámetros
nfl = copiaParametro("nfl",ptrTrama); // Toma nombre completo del archivo
if (!sendArchivo(&socket_c, nfl)) {
liberaMemoria(nfl);
syslog(LOG_ERR, "Problem sending file\n");
return false;
}
liberaMemoria(nfl);
return true;
}
// ________________________________________________________________________________________________________
// Función: enviaArchivo
//
// Descripción:
// Envia un archivo por la red, por bloques
// Parámetros:
// - socket_c: Socket del cliente que envió el mensaje
// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// ________________________________________________________________________________________________________
static bool recibeArchivo(TRAMA *ptrTrama, struct og_client *cli)
{
int socket_c = og_client_socket(cli);
char *nfl;
// Toma parámetros
nfl = copiaParametro("nfl",ptrTrama); // Toma nombre completo del archivo
ptrTrama->tipo = MSG_NOTIFICACION;
enviaFlag(&socket_c, ptrTrama);
if (!recArchivo(&socket_c, nfl)) {
liberaMemoria(nfl);
syslog(LOG_ERR, "Problem receiving file\n");
return false;
}
liberaMemoria(nfl);
return true;
}
// ________________________________________________________________________________________________________
// Función: envioProgramacion
//
// Descripción:
// Envia un comando de actualización a todos los ordenadores que han sido programados con
// alguna acción para que entren en el bucle de comandos pendientes y las ejecuten
// Parámetros:
// - socket_c: Socket del cliente que envió el mensaje
// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// ________________________________________________________________________________________________________
static bool envioProgramacion(TRAMA *ptrTrama, struct og_client *cli)
{
char *ptrIP[MAXIMOS_CLIENTES],*ptrMacs[MAXIMOS_CLIENTES];
char *idp, *iph, *mac;
int idx,idcomando,lon;
const char *msglog;
struct og_dbi *dbi;
dbi_result result;
dbi = og_dbi_open(&dbi_config);
if (!dbi) {
syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
__func__, __LINE__);
return false;
}
idp = copiaParametro("idp",ptrTrama); // Toma identificador de la programación de la tabla acciones
result = dbi_conn_queryf(dbi->conn,
"SELECT ordenadores.ip,ordenadores.mac,acciones.idcomando FROM acciones "\
" INNER JOIN ordenadores ON ordenadores.ip=acciones.ip"\
" WHERE acciones.idprogramacion=%s",idp);
liberaMemoria(idp);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
og_dbi_close(dbi);
return false;
}
/* Prepara la trama de actualizacion */
initParametros(ptrTrama,0);
ptrTrama->tipo=MSG_COMANDO;
sprintf(ptrTrama->parametros, "nfn=Actualizar\r");
while (dbi_result_next_row(result)) {
iph = (char *)dbi_result_get_string(result, "ip");
idcomando = dbi_result_get_uint(result, "idcomando");
if (idcomando == 1){ // Arrancar
mac = (char *)dbi_result_get_string(result, "mac");
lon = splitCadena(ptrIP, iph, ';');
lon = splitCadena(ptrMacs, mac, ';');
// Se manda por broadcast y por unicast
if (!Levanta(ptrIP, ptrMacs, lon, (char*)"1")) {
dbi_result_free(result);
og_dbi_close(dbi);
return false;
}
if (!Levanta(ptrIP, ptrMacs, lon, (char*)"2")) {
dbi_result_free(result);
og_dbi_close(dbi);
return false;
}
}
if (clienteDisponible(iph, &idx)) { // Si el cliente puede recibir comandos
int sock = tbsockets[idx].cli ? tbsockets[idx].cli->io.fd : -1;
strcpy(tbsockets[idx].estado, CLIENTE_OCUPADO); // Actualiza el estado del cliente
if (sock >= 0 && !mandaTrama(&sock, ptrTrama)) {
syslog(LOG_ERR, "failed to send response: %s\n",
strerror(errno));
}
//close(tbsockets[idx].sock); // Cierra el socket del cliente hasta nueva disponibilidad
}
}
dbi_result_free(result);
og_dbi_close(dbi);
return true; // No existen registros
}
// This object stores function handler for messages
static struct {
const char *nf; // Nombre de la función
bool (*fcn)(TRAMA *, struct og_client *cli);
} tbfuncionesServer[] = {
{ "InclusionCliente", InclusionCliente, },
{ "InclusionClienteWinLnx", InclusionClienteWinLnx, },
{ "AutoexecCliente", AutoexecCliente, },
{ "ComandosPendientes", ComandosPendientes, },
{ "DisponibilidadComandos", DisponibilidadComandos, },
{ "RESPUESTA_Arrancar", RESPUESTA_Arrancar, },
{ "RESPUESTA_Apagar", RESPUESTA_Apagar, },
{ "RESPUESTA_Reiniciar", RESPUESTA_Apagar, },
{ "RESPUESTA_IniciarSesion", RESPUESTA_Apagar, },
{ "RESPUESTA_CrearImagen", RESPUESTA_CrearImagen, },
{ "RESPUESTA_CrearImagenBasica", RESPUESTA_CrearImagenBasica, },
{ "RESPUESTA_CrearSoftIncremental", RESPUESTA_CrearSoftIncremental, },
{ "RESPUESTA_RestaurarImagen", RESPUESTA_RestaurarImagen },
{ "RESPUESTA_RestaurarImagenBasica", RESPUESTA_RestaurarImagenBasica, },
{ "RESPUESTA_RestaurarSoftIncremental", RESPUESTA_RestaurarSoftIncremental, },
{ "RESPUESTA_Configurar", RESPUESTA_EjecutarScript, },
{ "RESPUESTA_EjecutarScript", RESPUESTA_EjecutarScript, },
{ "RESPUESTA_InventarioHardware", RESPUESTA_InventarioHardware, },
{ "RESPUESTA_InventarioSoftware", RESPUESTA_InventarioSoftware, },
{ "enviaArchivo", enviaArchivo, },
{ "recibeArchivo", recibeArchivo, },
{ "envioProgramacion", envioProgramacion, },
{ NULL, NULL, },
};
// ________________________________________________________________________________________________________
// Función: gestionaTrama
//
// Descripción:
// Procesa las tramas recibidas .
// Parametros:
// - s : Socket usado para comunicaciones
// Devuelve:
// true: Si el proceso es correcto
// false: En caso de ocurrir algún error
// ________________________________________________________________________________________________________
static void gestionaTrama(TRAMA *ptrTrama, struct og_client *cli)
{
int i, res;
char *nfn;
if (ptrTrama){
INTROaFINCAD(ptrTrama);
nfn = copiaParametro("nfn",ptrTrama); // Toma nombre de la función
for (i = 0; tbfuncionesServer[i].fcn; i++) {
if (!strncmp(tbfuncionesServer[i].nf, nfn,
strlen(tbfuncionesServer[i].nf))) {
res = tbfuncionesServer[i].fcn(ptrTrama, cli);
if (!res) {
syslog(LOG_ERR, "Failed handling of %s for client %s:%hu\n",
tbfuncionesServer[i].nf,
inet_ntoa(cli->addr.sin_addr),
ntohs(cli->addr.sin_port));
} else {
syslog(LOG_DEBUG, "Successful handling of %s for client %s:%hu\n",
tbfuncionesServer[i].nf,
inet_ntoa(cli->addr.sin_addr),
ntohs(cli->addr.sin_port));
}
break;
}
}
if (!tbfuncionesServer[i].fcn)
syslog(LOG_ERR, "unknown request %s from client %s:%hu\n",
nfn, inet_ntoa(cli->addr.sin_addr),
ntohs(cli->addr.sin_port));
liberaMemoria(nfn);
}
}
static void og_client_release(struct ev_loop *loop, struct og_client *cli)
{
if (cli->keepalive_idx >= 0) {
syslog(LOG_DEBUG, "closing keepalive connection for %s:%hu in slot %d\n",
inet_ntoa(cli->addr.sin_addr),
ntohs(cli->addr.sin_port), cli->keepalive_idx);
tbsockets[cli->keepalive_idx].cli = NULL;
}
list_del(&cli->list);
ev_io_stop(loop, &cli->io);
close(cli->io.fd);
free(cli);
}
static void og_client_keepalive(struct ev_loop *loop, struct og_client *cli)
{
struct og_client *old_cli;
old_cli = tbsockets[cli->keepalive_idx].cli;
if (old_cli && old_cli != cli) {
syslog(LOG_DEBUG, "closing old keepalive connection for %s:%hu\n",
inet_ntoa(old_cli->addr.sin_addr),
ntohs(old_cli->addr.sin_port));
og_client_release(loop, old_cli);
}
tbsockets[cli->keepalive_idx].cli = cli;
}
static void og_client_reset_state(struct og_client *cli)
{
cli->state = OG_CLIENT_RECEIVING_HEADER;
cli->buf_len = 0;
}
static int og_client_state_recv_hdr(struct og_client *cli)
{
char hdrlen[LONHEXPRM];
/* Still too short to validate protocol fingerprint and message
* length.
*/
if (cli->buf_len < 15 + LONHEXPRM)
return 0;
if (strncmp(cli->buf, "@JMMLCAMDJ_MCDJ", 15)) {
syslog(LOG_ERR, "bad fingerprint from client %s:%hu, closing\n",
inet_ntoa(cli->addr.sin_addr),
ntohs(cli->addr.sin_port));
return -1;
}
memcpy(hdrlen, &cli->buf[LONGITUD_CABECERATRAMA], LONHEXPRM);
cli->msg_len = strtol(hdrlen, NULL, 16);
/* Header announces more that we can fit into buffer. */
if (cli->msg_len >= sizeof(cli->buf)) {
syslog(LOG_ERR, "too large message %u bytes from %s:%hu\n",
cli->msg_len, inet_ntoa(cli->addr.sin_addr),
ntohs(cli->addr.sin_port));
return -1;
}
return 1;
}
static TRAMA *og_msg_alloc(char *data, unsigned int len)
{
TRAMA *ptrTrama;
ptrTrama = (TRAMA *)reservaMemoria(sizeof(TRAMA));
if (!ptrTrama) {
syslog(LOG_ERR, "OOM\n");
return NULL;
}
initParametros(ptrTrama, len);
memcpy(ptrTrama, "@JMMLCAMDJ_MCDJ", LONGITUD_CABECERATRAMA);
memcpy(ptrTrama->parametros, data, len);
ptrTrama->lonprm = len;
return ptrTrama;
}
static void og_msg_free(TRAMA *ptrTrama)
{
liberaMemoria(ptrTrama->parametros);
liberaMemoria(ptrTrama);
}
static int og_client_state_process_payload(struct og_client *cli)
{
TRAMA *ptrTrama;
char *data;
int len;
len = cli->msg_len - (LONGITUD_CABECERATRAMA + LONHEXPRM);
data = &cli->buf[LONGITUD_CABECERATRAMA + LONHEXPRM];
ptrTrama = og_msg_alloc(data, len);
if (!ptrTrama)
return -1;
gestionaTrama(ptrTrama, cli);
og_msg_free(ptrTrama);
return 1;
}
#define OG_CLIENTS_MAX 4096
#define OG_PARTITION_MAX 4
struct og_partition {
const char *disk;
const char *number;
const char *code;
const char *size;
const char *filesystem;
const char *format;
const char *os;
const char *used_size;
};
struct og_sync_params {
const char *sync;
const char *diff;
const char *remove;
const char *compress;
const char *cleanup;
const char *cache;
const char *cleanup_cache;
const char *remove_dst;
const char *diff_id;
const char *diff_name;
const char *path;
const char *method;
};
struct og_msg_params {
const char *ips_array[OG_CLIENTS_MAX];
const char *mac_array[OG_CLIENTS_MAX];
unsigned int ips_array_len;
const char *wol_type;
char run_cmd[4096];
const char *disk;
const char *partition;
const char *repository;
const char *name;
const char *id;
const char *code;
const char *type;
const char *profile;
const char *cache;
const char *cache_size;
bool echo;
struct og_partition partition_setup[OG_PARTITION_MAX];
struct og_sync_params sync_setup;
struct og_schedule_time time;
const char *task_id;
uint64_t flags;
};
#define OG_COMPUTER_NAME_MAXLEN 100
struct og_computer {
unsigned int id;
unsigned int center;
unsigned int room;
char name[OG_COMPUTER_NAME_MAXLEN + 1];
};
#define OG_REST_PARAM_ADDR (1UL << 0)
#define OG_REST_PARAM_MAC (1UL << 1)
#define OG_REST_PARAM_WOL_TYPE (1UL << 2)
#define OG_REST_PARAM_RUN_CMD (1UL << 3)
#define OG_REST_PARAM_DISK (1UL << 4)
#define OG_REST_PARAM_PARTITION (1UL << 5)
#define OG_REST_PARAM_REPO (1UL << 6)
#define OG_REST_PARAM_NAME (1UL << 7)
#define OG_REST_PARAM_ID (1UL << 8)
#define OG_REST_PARAM_CODE (1UL << 9)
#define OG_REST_PARAM_TYPE (1UL << 10)
#define OG_REST_PARAM_PROFILE (1UL << 11)
#define OG_REST_PARAM_CACHE (1UL << 12)
#define OG_REST_PARAM_CACHE_SIZE (1UL << 13)
#define OG_REST_PARAM_PART_0 (1UL << 14)
#define OG_REST_PARAM_PART_1 (1UL << 15)
#define OG_REST_PARAM_PART_2 (1UL << 16)
#define OG_REST_PARAM_PART_3 (1UL << 17)
#define OG_REST_PARAM_SYNC_SYNC (1UL << 18)
#define OG_REST_PARAM_SYNC_DIFF (1UL << 19)
#define OG_REST_PARAM_SYNC_REMOVE (1UL << 20)
#define OG_REST_PARAM_SYNC_COMPRESS (1UL << 21)
#define OG_REST_PARAM_SYNC_CLEANUP (1UL << 22)
#define OG_REST_PARAM_SYNC_CACHE (1UL << 23)
#define OG_REST_PARAM_SYNC_CLEANUP_CACHE (1UL << 24)
#define OG_REST_PARAM_SYNC_REMOVE_DST (1UL << 25)
#define OG_REST_PARAM_SYNC_DIFF_ID (1UL << 26)
#define OG_REST_PARAM_SYNC_DIFF_NAME (1UL << 27)
#define OG_REST_PARAM_SYNC_PATH (1UL << 28)
#define OG_REST_PARAM_SYNC_METHOD (1UL << 29)
#define OG_REST_PARAM_ECHO (1UL << 30)
#define OG_REST_PARAM_TASK (1UL << 31)
#define OG_REST_PARAM_TIME_YEARS (1UL << 32)
#define OG_REST_PARAM_TIME_MONTHS (1UL << 33)
#define OG_REST_PARAM_TIME_DAYS (1UL << 34)
#define OG_REST_PARAM_TIME_HOURS (1UL << 35)
#define OG_REST_PARAM_TIME_AM_PM (1UL << 36)
#define OG_REST_PARAM_TIME_MINUTES (1UL << 37)
enum og_rest_method {
OG_METHOD_GET = 0,
OG_METHOD_POST,
};
static struct og_client *og_client_find(const char *ip)
{
struct og_client *client;
struct in_addr addr;
int res;
res = inet_aton(ip, &addr);
if (!res) {
syslog(LOG_ERR, "Invalid IP string: %s\n", ip);
return NULL;
}
list_for_each_entry(client, &client_list, list) {
if (client->addr.sin_addr.s_addr == addr.s_addr && client->agent) {
return client;
}
}
return NULL;
}
static int og_send_request(const char *cmd,
const enum og_rest_method method,
const struct og_msg_params *params,
const json_t *data)
{
const char *content_type = "Content-Type: application/json";
char content [OG_MSG_REQUEST_MAXLEN - 700] = {};
char buf[OG_MSG_REQUEST_MAXLEN] = {};
unsigned int content_length;
char method_str[5] = {};
struct og_client *cli;
unsigned int i;
int client_sd;
if (method == OG_METHOD_GET)
snprintf(method_str, 5, "GET");
else if (method == OG_METHOD_POST)
snprintf(method_str, 5, "POST");
else
return -1;
if (!data)
content_length = 0;
else
content_length = json_dumpb(data, content,
OG_MSG_REQUEST_MAXLEN - 700,
JSON_COMPACT);
snprintf(buf, OG_MSG_REQUEST_MAXLEN,
"%s /%s HTTP/1.1\r\nContent-Length: %d\r\n%s\r\n\r\n%s",
method_str, cmd, content_length, content_type, content);
for (i = 0; i < params->ips_array_len; i++) {
cli = og_client_find(params->ips_array[i]);
if (!cli)
continue;
client_sd = cli->io.fd;
if (client_sd < 0) {
syslog(LOG_INFO, "Client %s not conected\n",
params->ips_array[i]);
continue;
}
if (send(client_sd, buf, strlen(buf), 0) < 0)
continue;
strncpy(cli->last_cmd, cmd, OG_CMD_MAXLEN);
}
return 0;
}
static bool og_msg_params_validate(const struct og_msg_params *params,
const uint64_t flags)
{
return (params->flags & flags) == flags;
}
static int og_json_parse_clients(json_t *element, struct og_msg_params *params)
{
unsigned int i;
json_t *k;
if (json_typeof(element) != JSON_ARRAY)
return -1;
for (i = 0; i < json_array_size(element); i++) {
k = json_array_get(element, i);
if (json_typeof(k) != JSON_STRING)
return -1;
params->ips_array[params->ips_array_len++] =
json_string_value(k);
params->flags |= OG_REST_PARAM_ADDR;
}
return 0;
}
static int og_json_parse_string(json_t *element, const char **str)
{
if (json_typeof(element) != JSON_STRING)
return -1;
*str = json_string_value(element);
return 0;
}
static int og_json_parse_uint(json_t *element, uint32_t *integer)
{
if (json_typeof(element) != JSON_INTEGER)
return -1;
*integer = json_integer_value(element);
return 0;
}
static int og_json_parse_bool(json_t *element, bool *value)
{
if (json_typeof(element) == JSON_TRUE)
*value = true;
else if (json_typeof(element) == JSON_FALSE)
*value = false;
else
return -1;
return 0;
}
static int og_json_parse_sync_params(json_t *element,
struct og_msg_params *params)
{
const char *key;
json_t *value;
int err = 0;
json_object_foreach(element, key, value) {
if (!strcmp(key, "sync")) {
err = og_json_parse_string(value, &params->sync_setup.sync);
params->flags |= OG_REST_PARAM_SYNC_SYNC;
} else if (!strcmp(key, "diff")) {
err = og_json_parse_string(value, &params->sync_setup.diff);
params->flags |= OG_REST_PARAM_SYNC_DIFF;
} else if (!strcmp(key, "remove")) {
err = og_json_parse_string(value, &params->sync_setup.remove);
params->flags |= OG_REST_PARAM_SYNC_REMOVE;
} else if (!strcmp(key, "compress")) {
err = og_json_parse_string(value, &params->sync_setup.compress);
params->flags |= OG_REST_PARAM_SYNC_COMPRESS;
} else if (!strcmp(key, "cleanup")) {
err = og_json_parse_string(value, &params->sync_setup.cleanup);
params->flags |= OG_REST_PARAM_SYNC_CLEANUP;
} else if (!strcmp(key, "cache")) {
err = og_json_parse_string(value, &params->sync_setup.cache);
params->flags |= OG_REST_PARAM_SYNC_CACHE;
} else if (!strcmp(key, "cleanup_cache")) {
err = og_json_parse_string(value, &params->sync_setup.cleanup_cache);
params->flags |= OG_REST_PARAM_SYNC_CLEANUP_CACHE;
} else if (!strcmp(key, "remove_dst")) {
err = og_json_parse_string(value, &params->sync_setup.remove_dst);
params->flags |= OG_REST_PARAM_SYNC_REMOVE_DST;
} else if (!strcmp(key, "diff_id")) {
err = og_json_parse_string(value, &params->sync_setup.diff_id);
params->flags |= OG_REST_PARAM_SYNC_DIFF_ID;
} else if (!strcmp(key, "diff_name")) {
err = og_json_parse_string(value, &params->sync_setup.diff_name);
params->flags |= OG_REST_PARAM_SYNC_DIFF_NAME;
} else if (!strcmp(key, "path")) {
err = og_json_parse_string(value, &params->sync_setup.path);
params->flags |= OG_REST_PARAM_SYNC_PATH;
} else if (!strcmp(key, "method")) {
err = og_json_parse_string(value, &params->sync_setup.method);
params->flags |= OG_REST_PARAM_SYNC_METHOD;
}
if (err != 0)
return err;
}
return err;
}
#define OG_PARAM_PART_NUMBER (1UL << 0)
#define OG_PARAM_PART_CODE (1UL << 1)
#define OG_PARAM_PART_FILESYSTEM (1UL << 2)
#define OG_PARAM_PART_SIZE (1UL << 3)
#define OG_PARAM_PART_FORMAT (1UL << 4)
#define OG_PARAM_PART_DISK (1UL << 5)
#define OG_PARAM_PART_OS (1UL << 6)
#define OG_PARAM_PART_USED_SIZE (1UL << 7)
static int og_json_parse_partition(json_t *element,
struct og_partition *part,
uint64_t required_flags)
{
uint64_t flags = 0UL;
const char *key;
json_t *value;
int err = 0;
json_object_foreach(element, key, value) {
if (!strcmp(key, "partition")) {
err = og_json_parse_string(value, &part->number);
flags |= OG_PARAM_PART_NUMBER;
} else if (!strcmp(key, "code")) {
err = og_json_parse_string(value, &part->code);
flags |= OG_PARAM_PART_CODE;
} else if (!strcmp(key, "filesystem")) {
err = og_json_parse_string(value, &part->filesystem);
flags |= OG_PARAM_PART_FILESYSTEM;
} else if (!strcmp(key, "size")) {
err = og_json_parse_string(value, &part->size);
flags |= OG_PARAM_PART_SIZE;
} else if (!strcmp(key, "format")) {
err = og_json_parse_string(value, &part->format);
flags |= OG_PARAM_PART_FORMAT;
} else if (!strcmp(key, "disk")) {
err = og_json_parse_string(value, &part->disk);
flags |= OG_PARAM_PART_DISK;
} else if (!strcmp(key, "os")) {
err = og_json_parse_string(value, &part->os);
flags |= OG_PARAM_PART_OS;
} else if (!strcmp(key, "used_size")) {
err = og_json_parse_string(value, &part->used_size);
flags |= OG_PARAM_PART_USED_SIZE;
}
if (err < 0)
return err;
}
if (flags != required_flags)
return -1;
return err;
}
static int og_json_parse_partition_setup(json_t *element,
struct og_msg_params *params)
{
unsigned int i;
json_t *k;
if (json_typeof(element) != JSON_ARRAY)
return -1;
for (i = 0; i < json_array_size(element) && i < OG_PARTITION_MAX; ++i) {
k = json_array_get(element, i);
if (json_typeof(k) != JSON_OBJECT)
return -1;
if (og_json_parse_partition(k, &params->partition_setup[i],
OG_PARAM_PART_NUMBER |
OG_PARAM_PART_CODE |
OG_PARAM_PART_FILESYSTEM |
OG_PARAM_PART_SIZE |
OG_PARAM_PART_FORMAT) < 0)
return -1;
params->flags |= (OG_REST_PARAM_PART_0 << i);
}
return 0;
}
static int og_json_parse_time_params(json_t *element,
struct og_msg_params *params)
{
const char *key;
json_t *value;
int err = 0;
json_object_foreach(element, key, value) {
if (!strcmp(key, "years")) {
err = og_json_parse_uint(value, &params->time.years);
params->flags |= OG_REST_PARAM_TIME_YEARS;
} else if (!strcmp(key, "months")) {
err = og_json_parse_uint(value, &params->time.months);
params->flags |= OG_REST_PARAM_TIME_MONTHS;
} else if (!strcmp(key, "days")) {
err = og_json_parse_uint(value, &params->time.days);
params->flags |= OG_REST_PARAM_TIME_DAYS;
} else if (!strcmp(key, "hours")) {
err = og_json_parse_uint(value, &params->time.hours);
params->flags |= OG_REST_PARAM_TIME_HOURS;
} else if (!strcmp(key, "am_pm")) {
err = og_json_parse_uint(value, &params->time.am_pm);
params->flags |= OG_REST_PARAM_TIME_AM_PM;
} else if (!strcmp(key, "minutes")) {
err = og_json_parse_uint(value, &params->time.minutes);
params->flags |= OG_REST_PARAM_TIME_MINUTES;
}
if (err != 0)
return err;
}
return err;
}
static int og_cmd_post_clients(json_t *element, struct og_msg_params *params)
{
const char *key;
json_t *value;
int err = 0;
if (json_typeof(element) != JSON_OBJECT)
return -1;
json_object_foreach(element, key, value) {
if (!strcmp(key, "clients"))
err = og_json_parse_clients(value, params);
if (err < 0)
break;
}
if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
return -1;
return og_send_request("probe", OG_METHOD_POST, params, NULL);
}
struct og_buffer {
char *data;
int len;
};
static int og_json_dump_clients(const char *buffer, size_t size, void *data)
{
struct og_buffer *og_buffer = (struct og_buffer *)data;
memcpy(og_buffer->data + og_buffer->len, buffer, size);
og_buffer->len += size;
return 0;
}
static int og_cmd_get_clients(json_t *element, struct og_msg_params *params,
char *buffer_reply)
{
json_t *root, *array, *addr, *state, *object;
struct og_client *client;
struct og_buffer og_buffer = {
.data = buffer_reply,
};
array = json_array();
if (!array)
return -1;
list_for_each_entry(client, &client_list, list) {
if (!client->agent)
continue;
object = json_object();
if (!object) {
json_decref(array);
return -1;
}
addr = json_string(inet_ntoa(client->addr.sin_addr));
if (!addr) {
json_decref(object);
json_decref(array);
return -1;
}
json_object_set_new(object, "addr", addr);
state = json_string(client->status);
if (!state) {
json_decref(object);
json_decref(array);
return -1;
}
json_object_set_new(object, "state", state);
json_array_append_new(array, object);
}
root = json_pack("{s:o}", "clients", array);
if (!root) {
json_decref(array);
return -1;
}
json_dump_callback(root, og_json_dump_clients, &og_buffer, 0);
json_decref(root);
return 0;
}
static int og_json_parse_target(json_t *element, struct og_msg_params *params)
{
const char *key;
json_t *value;
if (json_typeof(element) != JSON_OBJECT) {
return -1;
}
json_object_foreach(element, key, value) {
if (!strcmp(key, "addr")) {
if (json_typeof(value) != JSON_STRING)
return -1;
params->ips_array[params->ips_array_len] =
json_string_value(value);
params->flags |= OG_REST_PARAM_ADDR;
} else if (!strcmp(key, "mac")) {
if (json_typeof(value) != JSON_STRING)
return -1;
params->mac_array[params->ips_array_len] =
json_string_value(value);
params->flags |= OG_REST_PARAM_MAC;
}
}
return 0;
}
static int og_json_parse_targets(json_t *element, struct og_msg_params *params)
{
unsigned int i;
json_t *k;
int err;
if (json_typeof(element) != JSON_ARRAY)
return -1;
for (i = 0; i < json_array_size(element); i++) {
k = json_array_get(element, i);
if (json_typeof(k) != JSON_OBJECT)
return -1;
err = og_json_parse_target(k, params);
if (err < 0)
return err;
params->ips_array_len++;
}
return 0;
}
static int og_json_parse_type(json_t *element, struct og_msg_params *params)
{
const char *type;
if (json_typeof(element) != JSON_STRING)
return -1;
params->wol_type = json_string_value(element);
type = json_string_value(element);
if (!strcmp(type, "unicast"))
params->wol_type = "2";
else if (!strcmp(type, "broadcast"))
params->wol_type = "1";
params->flags |= OG_REST_PARAM_WOL_TYPE;
return 0;
}
static int og_cmd_wol(json_t *element, struct og_msg_params *params)
{
const char *key;
json_t *value;
int err = 0;
if (json_typeof(element) != JSON_OBJECT)
return -1;
json_object_foreach(element, key, value) {
if (!strcmp(key, "clients")) {
err = og_json_parse_targets(value, params);
} else if (!strcmp(key, "type")) {
err = og_json_parse_type(value, params);
}
if (err < 0)
break;
}
if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
OG_REST_PARAM_MAC |
OG_REST_PARAM_WOL_TYPE))
return -1;
if (!Levanta((char **)params->ips_array, (char **)params->mac_array,
params->ips_array_len, (char *)params->wol_type))
return -1;
return 0;
}
static int og_json_parse_run(json_t *element, struct og_msg_params *params)
{
if (json_typeof(element) != JSON_STRING)
return -1;
snprintf(params->run_cmd, sizeof(params->run_cmd), "%s",
json_string_value(element));
params->flags |= OG_REST_PARAM_RUN_CMD;
return 0;
}
static int og_cmd_run_post(json_t *element, struct og_msg_params *params)
{
json_t *value, *clients;
const char *key;
unsigned int i;
int err = 0;
if (json_typeof(element) != JSON_OBJECT)
return -1;
json_object_foreach(element, key, value) {
if (!strcmp(key, "clients"))
err = og_json_parse_clients(value, params);
else if (!strcmp(key, "run"))
err = og_json_parse_run(value, params);
else if (!strcmp(key, "echo")) {
err = og_json_parse_bool(value, &params->echo);
params->flags |= OG_REST_PARAM_ECHO;
}
if (err < 0)
break;
}
if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
OG_REST_PARAM_RUN_CMD |
OG_REST_PARAM_ECHO))
return -1;
clients = json_copy(element);
json_object_del(clients, "clients");
err = og_send_request("shell/run", OG_METHOD_POST, params, clients);
if (err < 0)
return err;
for (i = 0; i < params->ips_array_len; i++) {
char filename[4096];
FILE *f;
sprintf(filename, "/tmp/_Seconsola_%s", params->ips_array[i]);
f = fopen(filename, "wt");
fclose(f);
}
return 0;
}
static int og_cmd_run_get(json_t *element, struct og_msg_params *params,
char *buffer_reply)
{
struct og_buffer og_buffer = {
.data = buffer_reply,
};
json_t *root, *value, *array;
const char *key;
unsigned int i;
int err = 0;
if (json_typeof(element) != JSON_OBJECT)
return -1;
json_object_foreach(element, key, value) {
if (!strcmp(key, "clients"))
err = og_json_parse_clients(value, params);
if (err < 0)
return err;
}
if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
return -1;
array = json_array();
if (!array)
return -1;
for (i = 0; i < params->ips_array_len; i++) {
json_t *object, *output, *addr;
char data[4096] = {};
char filename[4096];
int fd, numbytes;
sprintf(filename, "/tmp/_Seconsola_%s", params->ips_array[i]);
fd = open(filename, O_RDONLY);
if (!fd)
return -1;
numbytes = read(fd, data, sizeof(data));
if (numbytes < 0) {
close(fd);
return -1;
}
data[sizeof(data) - 1] = '\0';
close(fd);
object = json_object();
if (!object) {
json_decref(array);
return -1;
}
addr = json_string(params->ips_array[i]);
if (!addr) {
json_decref(object);
json_decref(array);
return -1;
}
json_object_set_new(object, "addr", addr);
output = json_string(data);
if (!output) {
json_decref(object);
json_decref(array);
return -1;
}
json_object_set_new(object, "output", output);
json_array_append_new(array, object);
}
root = json_pack("{s:o}", "clients", array);
if (!root)
return -1;
json_dump_callback(root, og_json_dump_clients, &og_buffer, 0);
json_decref(root);
return 0;
}
static int og_cmd_session(json_t *element, struct og_msg_params *params)
{
json_t *clients, *value;
const char *key;
int err = 0;
if (json_typeof(element) != JSON_OBJECT)
return -1;
json_object_foreach(element, key, value) {
if (!strcmp(key, "clients")) {
err = og_json_parse_clients(value, params);
} else if (!strcmp(key, "disk")) {
err = og_json_parse_string(value, &params->disk);
params->flags |= OG_REST_PARAM_DISK;
} else if (!strcmp(key, "partition")) {
err = og_json_parse_string(value, &params->partition);
params->flags |= OG_REST_PARAM_PARTITION;
}
if (err < 0)
return err;
}
if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
OG_REST_PARAM_DISK |
OG_REST_PARAM_PARTITION))
return -1;
clients = json_copy(element);
json_object_del(clients, "clients");
return og_send_request("session", OG_METHOD_POST, params, clients);
}
static int og_cmd_poweroff(json_t *element, struct og_msg_params *params)
{
const char *key;
json_t *value;
int err = 0;
if (json_typeof(element) != JSON_OBJECT)
return -1;
json_object_foreach(element, key, value) {
if (!strcmp(key, "clients"))
err = og_json_parse_clients(value, params);
if (err < 0)
break;
}
if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
return -1;
return og_send_request("poweroff", OG_METHOD_POST, params, NULL);
}
static int og_cmd_refresh(json_t *element, struct og_msg_params *params)
{
const char *key;
json_t *value;
int err = 0;
if (json_typeof(element) != JSON_OBJECT)
return -1;
json_object_foreach(element, key, value) {
if (!strcmp(key, "clients"))
err = og_json_parse_clients(value, params);
if (err < 0)
break;
}
if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
return -1;
return og_send_request("refresh", OG_METHOD_GET, params, NULL);
}
static int og_cmd_reboot(json_t *element, struct og_msg_params *params)
{
const char *key;
json_t *value;
int err = 0;
if (json_typeof(element) != JSON_OBJECT)
return -1;
json_object_foreach(element, key, value) {
if (!strcmp(key, "clients"))
err = og_json_parse_clients(value, params);
if (err < 0)
break;
}
if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
return -1;
return og_send_request("reboot", OG_METHOD_POST, params, NULL);
}
static int og_cmd_stop(json_t *element, struct og_msg_params *params)
{
const char *key;
json_t *value;
int err = 0;
if (json_typeof(element) != JSON_OBJECT)
return -1;
json_object_foreach(element, key, value) {
if (!strcmp(key, "clients"))
err = og_json_parse_clients(value, params);
if (err < 0)
break;
}
if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
return -1;
return og_send_request("stop", OG_METHOD_POST, params, NULL);
}
static int og_cmd_hardware(json_t *element, struct og_msg_params *params)
{
const char *key;
json_t *value;
int err = 0;
if (json_typeof(element) != JSON_OBJECT)
return -1;
json_object_foreach(element, key, value) {
if (!strcmp(key, "clients"))
err = og_json_parse_clients(value, params);
if (err < 0)
break;
}
if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
return -1;
return og_send_request("hardware", OG_METHOD_GET, params, NULL);
}
static int og_cmd_software(json_t *element, struct og_msg_params *params)
{
json_t *clients, *value;
const char *key;
int err = 0;
if (json_typeof(element) != JSON_OBJECT)
return -1;
json_object_foreach(element, key, value) {
if (!strcmp(key, "clients"))
err = og_json_parse_clients(value, params);
else if (!strcmp(key, "disk")) {
err = og_json_parse_string(value, &params->disk);
params->flags |= OG_REST_PARAM_DISK;
}
else if (!strcmp(key, "partition")) {
err = og_json_parse_string(value, &params->partition);
params->flags |= OG_REST_PARAM_PARTITION;
}
if (err < 0)
break;
}
if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
OG_REST_PARAM_DISK |
OG_REST_PARAM_PARTITION))
return -1;
clients = json_copy(element);
json_object_del(clients, "clients");
return og_send_request("software", OG_METHOD_POST, params, clients);
}
static int og_cmd_create_image(json_t *element, struct og_msg_params *params)
{
json_t *value, *clients;
const char *key;
int err = 0;
if (json_typeof(element) != JSON_OBJECT)
return -1;
json_object_foreach(element, key, value) {
if (!strcmp(key, "disk")) {
err = og_json_parse_string(value, &params->disk);
params->flags |= OG_REST_PARAM_DISK;
} else if (!strcmp(key, "partition")) {
err = og_json_parse_string(value, &params->partition);
params->flags |= OG_REST_PARAM_PARTITION;
} else if (!strcmp(key, "name")) {
err = og_json_parse_string(value, &params->name);
params->flags |= OG_REST_PARAM_NAME;
} else if (!strcmp(key, "repository")) {
err = og_json_parse_string(value, &params->repository);
params->flags |= OG_REST_PARAM_REPO;
} else if (!strcmp(key, "clients")) {
err = og_json_parse_clients(value, params);
} else if (!strcmp(key, "id")) {
err = og_json_parse_string(value, &params->id);
params->flags |= OG_REST_PARAM_ID;
} else if (!strcmp(key, "code")) {
err = og_json_parse_string(value, &params->code);
params->flags |= OG_REST_PARAM_CODE;
}
if (err < 0)
break;
}
if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
OG_REST_PARAM_DISK |
OG_REST_PARAM_PARTITION |
OG_REST_PARAM_CODE |
OG_REST_PARAM_ID |
OG_REST_PARAM_NAME |
OG_REST_PARAM_REPO))
return -1;
clients = json_copy(element);
json_object_del(clients, "clients");
return og_send_request("image/create", OG_METHOD_POST, params, clients);
}
static int og_cmd_restore_image(json_t *element, struct og_msg_params *params)
{
json_t *clients, *value;
const char *key;
int err = 0;
if (json_typeof(element) != JSON_OBJECT)
return -1;
json_object_foreach(element, key, value) {
if (!strcmp(key, "disk")) {
err = og_json_parse_string(value, &params->disk);
params->flags |= OG_REST_PARAM_DISK;
} else if (!strcmp(key, "partition")) {
err = og_json_parse_string(value, &params->partition);
params->flags |= OG_REST_PARAM_PARTITION;
} else if (!strcmp(key, "name")) {
err = og_json_parse_string(value, &params->name);
params->flags |= OG_REST_PARAM_NAME;
} else if (!strcmp(key, "repository")) {
err = og_json_parse_string(value, &params->repository);
params->flags |= OG_REST_PARAM_REPO;
} else if (!strcmp(key, "clients")) {
err = og_json_parse_clients(value, params);
} else if (!strcmp(key, "type")) {
err = og_json_parse_string(value, &params->type);
params->flags |= OG_REST_PARAM_TYPE;
} else if (!strcmp(key, "profile")) {
err = og_json_parse_string(value, &params->profile);
params->flags |= OG_REST_PARAM_PROFILE;
} else if (!strcmp(key, "id")) {
err = og_json_parse_string(value, &params->id);
params->flags |= OG_REST_PARAM_ID;
}
if (err < 0)
break;
}
if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
OG_REST_PARAM_DISK |
OG_REST_PARAM_PARTITION |
OG_REST_PARAM_NAME |
OG_REST_PARAM_REPO |
OG_REST_PARAM_TYPE |
OG_REST_PARAM_PROFILE |
OG_REST_PARAM_ID))
return -1;
clients = json_copy(element);
json_object_del(clients, "clients");
return og_send_request("image/restore", OG_METHOD_POST, params, clients);
}
static int og_cmd_setup(json_t *element, struct og_msg_params *params)
{
json_t *value, *clients;
const char *key;
int err = 0;
if (json_typeof(element) != JSON_OBJECT)
return -1;
json_object_foreach(element, key, value) {
if (!strcmp(key, "clients")) {
err = og_json_parse_clients(value, params);
} else if (!strcmp(key, "disk")) {
err = og_json_parse_string(value, &params->disk);
params->flags |= OG_REST_PARAM_DISK;
} else if (!strcmp(key, "cache")) {
err = og_json_parse_string(value, &params->cache);
params->flags |= OG_REST_PARAM_CACHE;
} else if (!strcmp(key, "cache_size")) {
err = og_json_parse_string(value, &params->cache_size);
params->flags |= OG_REST_PARAM_CACHE_SIZE;
} else if (!strcmp(key, "partition_setup")) {
err = og_json_parse_partition_setup(value, params);
}
if (err < 0)
break;
}
if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
OG_REST_PARAM_DISK |
OG_REST_PARAM_CACHE |
OG_REST_PARAM_CACHE_SIZE |
OG_REST_PARAM_PART_0 |
OG_REST_PARAM_PART_1 |
OG_REST_PARAM_PART_2 |
OG_REST_PARAM_PART_3))
return -1;
clients = json_copy(element);
json_object_del(clients, "clients");
return og_send_request("setup", OG_METHOD_POST, params, clients);
}
static int og_cmd_run_schedule(json_t *element, struct og_msg_params *params)
{
const char *key;
json_t *value;
int err = 0;
json_object_foreach(element, key, value) {
if (!strcmp(key, "clients"))
err = og_json_parse_clients(value, params);
if (err < 0)
break;
}
if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
return -1;
return og_send_request("run/schedule", OG_METHOD_GET, params, NULL);
}
static int og_cmd_create_basic_image(json_t *element, struct og_msg_params *params)
{
char buf[4096] = {};
int err = 0, len;
const char *key;
json_t *value;
TRAMA *msg;
if (json_typeof(element) != JSON_OBJECT)
return -1;
json_object_foreach(element, key, value) {
if (!strcmp(key, "clients")) {
err = og_json_parse_clients(value, params);
} else if (!strcmp(key, "disk")) {
err = og_json_parse_string(value, &params->disk);
params->flags |= OG_REST_PARAM_DISK;
} else if (!strcmp(key, "partition")) {
err = og_json_parse_string(value, &params->partition);
params->flags |= OG_REST_PARAM_PARTITION;
} else if (!strcmp(key, "code")) {
err = og_json_parse_string(value, &params->code);
params->flags |= OG_REST_PARAM_CODE;
} else if (!strcmp(key, "id")) {
err = og_json_parse_string(value, &params->id);
params->flags |= OG_REST_PARAM_ID;
} else if (!strcmp(key, "name")) {
err = og_json_parse_string(value, &params->name);
params->flags |= OG_REST_PARAM_NAME;
} else if (!strcmp(key, "repository")) {
err = og_json_parse_string(value, &params->repository);
params->flags |= OG_REST_PARAM_REPO;
} else if (!strcmp(key, "sync_params")) {
err = og_json_parse_sync_params(value, params);
}
if (err < 0)
break;
}
if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
OG_REST_PARAM_DISK |
OG_REST_PARAM_PARTITION |
OG_REST_PARAM_CODE |
OG_REST_PARAM_ID |
OG_REST_PARAM_NAME |
OG_REST_PARAM_REPO |
OG_REST_PARAM_SYNC_SYNC |
OG_REST_PARAM_SYNC_DIFF |
OG_REST_PARAM_SYNC_REMOVE |
OG_REST_PARAM_SYNC_COMPRESS |
OG_REST_PARAM_SYNC_CLEANUP |
OG_REST_PARAM_SYNC_CACHE |
OG_REST_PARAM_SYNC_CLEANUP_CACHE |
OG_REST_PARAM_SYNC_REMOVE_DST))
return -1;
len = snprintf(buf, sizeof(buf),
"nfn=CrearImagenBasica\rdsk=%s\rpar=%s\rcpt=%s\ridi=%s\r"
"nci=%s\ripr=%s\rrti=\rmsy=%s\rwhl=%s\reli=%s\rcmp=%s\rbpi=%s\r"
"cpc=%s\rbpc=%s\rnba=%s\r",
params->disk, params->partition, params->code, params->id,
params->name, params->repository, params->sync_setup.sync,
params->sync_setup.diff, params->sync_setup.remove,
params->sync_setup.compress, params->sync_setup.cleanup,
params->sync_setup.cache, params->sync_setup.cleanup_cache,
params->sync_setup.remove_dst);
msg = og_msg_alloc(buf, len);
if (!msg)
return -1;
og_send_cmd((char **)params->ips_array, params->ips_array_len,
CLIENTE_OCUPADO, msg);
og_msg_free(msg);
return 0;
}
static int og_cmd_create_incremental_image(json_t *element, struct og_msg_params *params)
{
char buf[4096] = {};
int err = 0, len;
const char *key;
json_t *value;
TRAMA *msg;
if (json_typeof(element) != JSON_OBJECT)
return -1;
json_object_foreach(element, key, value) {
if (!strcmp(key, "clients"))
err = og_json_parse_clients(value, params);
else if (!strcmp(key, "disk")) {
err = og_json_parse_string(value, &params->disk);
params->flags |= OG_REST_PARAM_DISK;
} else if (!strcmp(key, "partition")) {
err = og_json_parse_string(value, &params->partition);
params->flags |= OG_REST_PARAM_PARTITION;
} else if (!strcmp(key, "id")) {
err = og_json_parse_string(value, &params->id);
params->flags |= OG_REST_PARAM_ID;
} else if (!strcmp(key, "name")) {
err = og_json_parse_string(value, &params->name);
params->flags |= OG_REST_PARAM_NAME;
} else if (!strcmp(key, "repository")) {
err = og_json_parse_string(value, &params->repository);
params->flags |= OG_REST_PARAM_REPO;
} else if (!strcmp(key, "sync_params")) {
err = og_json_parse_sync_params(value, params);
}
if (err < 0)
break;
}
if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
OG_REST_PARAM_DISK |
OG_REST_PARAM_PARTITION |
OG_REST_PARAM_ID |
OG_REST_PARAM_NAME |
OG_REST_PARAM_REPO |
OG_REST_PARAM_SYNC_SYNC |
OG_REST_PARAM_SYNC_PATH |
OG_REST_PARAM_SYNC_DIFF |
OG_REST_PARAM_SYNC_DIFF_ID |
OG_REST_PARAM_SYNC_DIFF_NAME |
OG_REST_PARAM_SYNC_REMOVE |
OG_REST_PARAM_SYNC_COMPRESS |
OG_REST_PARAM_SYNC_CLEANUP |
OG_REST_PARAM_SYNC_CACHE |
OG_REST_PARAM_SYNC_CLEANUP_CACHE |
OG_REST_PARAM_SYNC_REMOVE_DST))
return -1;
len = snprintf(buf, sizeof(buf),
"nfn=CrearSoftIncremental\rdsk=%s\rpar=%s\ridi=%s\rnci=%s\r"
"rti=%s\ripr=%s\ridf=%s\rncf=%s\rmsy=%s\rwhl=%s\reli=%s\rcmp=%s\r"
"bpi=%s\rcpc=%s\rbpc=%s\rnba=%s\r",
params->disk, params->partition, params->id, params->name,
params->sync_setup.path, params->repository, params->sync_setup.diff_id,
params->sync_setup.diff_name, params->sync_setup.sync,
params->sync_setup.diff, params->sync_setup.remove_dst,
params->sync_setup.compress, params->sync_setup.cleanup,
params->sync_setup.cache, params->sync_setup.cleanup_cache,
params->sync_setup.remove_dst);
msg = og_msg_alloc(buf, len);
if (!msg)
return -1;
og_send_cmd((char **)params->ips_array, params->ips_array_len,
CLIENTE_OCUPADO, msg);
og_msg_free(msg);
return 0;
}
static int og_cmd_restore_basic_image(json_t *element, struct og_msg_params *params)
{
char buf[4096] = {};
int err = 0, len;
const char *key;
json_t *value;
TRAMA *msg;
if (json_typeof(element) != JSON_OBJECT)
return -1;
json_object_foreach(element, key, value) {
if (!strcmp(key, "clients")) {
err = og_json_parse_clients(value, params);
} else if (!strcmp(key, "disk")) {
err = og_json_parse_string(value, &params->disk);
params->flags |= OG_REST_PARAM_DISK;
} else if (!strcmp(key, "partition")) {
err = og_json_parse_string(value, &params->partition);
params->flags |= OG_REST_PARAM_PARTITION;
} else if (!strcmp(key, "id")) {
err = og_json_parse_string(value, &params->id);
params->flags |= OG_REST_PARAM_ID;
} else if (!strcmp(key, "name")) {
err = og_json_parse_string(value, &params->name);
params->flags |= OG_REST_PARAM_NAME;
} else if (!strcmp(key, "repository")) {
err = og_json_parse_string(value, &params->repository);
params->flags |= OG_REST_PARAM_REPO;
} else if (!strcmp(key, "profile")) {
err = og_json_parse_string(value, &params->profile);
params->flags |= OG_REST_PARAM_PROFILE;
} else if (!strcmp(key, "type")) {
err = og_json_parse_string(value, &params->type);
params->flags |= OG_REST_PARAM_TYPE;
} else if (!strcmp(key, "sync_params")) {
err = og_json_parse_sync_params(value, params);
}
if (err < 0)
break;
}
if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
OG_REST_PARAM_DISK |
OG_REST_PARAM_PARTITION |
OG_REST_PARAM_ID |
OG_REST_PARAM_NAME |
OG_REST_PARAM_REPO |
OG_REST_PARAM_PROFILE |
OG_REST_PARAM_TYPE |
OG_REST_PARAM_SYNC_PATH |
OG_REST_PARAM_SYNC_METHOD |
OG_REST_PARAM_SYNC_SYNC |
OG_REST_PARAM_SYNC_DIFF |
OG_REST_PARAM_SYNC_REMOVE |
OG_REST_PARAM_SYNC_COMPRESS |
OG_REST_PARAM_SYNC_CLEANUP |
OG_REST_PARAM_SYNC_CACHE |
OG_REST_PARAM_SYNC_CLEANUP_CACHE |
OG_REST_PARAM_SYNC_REMOVE_DST))
return -1;
len = snprintf(buf, sizeof(buf),
"nfn=RestaurarImagenBasica\rdsk=%s\rpar=%s\ridi=%s\rnci=%s\r"
"ipr=%s\rifs=%s\rrti=%s\rmet=%s\rmsy=%s\rtpt=%s\rwhl=%s\r"
"eli=%s\rcmp=%s\rbpi=%s\rcpc=%s\rbpc=%s\rnba=%s\r",
params->disk, params->partition, params->id, params->name,
params->repository, params->profile, params->sync_setup.path,
params->sync_setup.method, params->sync_setup.sync, params->type,
params->sync_setup.diff, params->sync_setup.remove,
params->sync_setup.compress, params->sync_setup.cleanup,
params->sync_setup.cache, params->sync_setup.cleanup_cache,
params->sync_setup.remove_dst);
msg = og_msg_alloc(buf, len);
if (!msg)
return -1;
og_send_cmd((char **)params->ips_array, params->ips_array_len,
CLIENTE_OCUPADO, msg);
og_msg_free(msg);
return 0;
}
static int og_cmd_restore_incremental_image(json_t *element, struct og_msg_params *params)
{
char buf[4096] = {};
int err = 0, len;
const char *key;
json_t *value;
TRAMA *msg;
if (json_typeof(element) != JSON_OBJECT)
return -1;
json_object_foreach(element, key, value) {
if (!strcmp(key, "clients")) {
err = og_json_parse_clients(value, params);
} else if (!strcmp(key, "disk")) {
err = og_json_parse_string(value, &params->disk);
params->flags |= OG_REST_PARAM_DISK;
} else if (!strcmp(key, "partition")) {
err = og_json_parse_string(value, &params->partition);
params->flags |= OG_REST_PARAM_PARTITION;
} else if (!strcmp(key, "id")) {
err = og_json_parse_string(value, &params->id);
params->flags |= OG_REST_PARAM_ID;
} else if (!strcmp(key, "name")) {
err = og_json_parse_string(value, &params->name);
params->flags |= OG_REST_PARAM_NAME;
} else if (!strcmp(key, "repository")) {
err = og_json_parse_string(value, &params->repository);
params->flags |= OG_REST_PARAM_REPO;
} else if (!strcmp(key, "profile")) {
err = og_json_parse_string(value, &params->profile);
params->flags |= OG_REST_PARAM_PROFILE;
} else if (!strcmp(key, "type")) {
err = og_json_parse_string(value, &params->type);
params->flags |= OG_REST_PARAM_TYPE;
} else if (!strcmp(key, "sync_params")) {
err = og_json_parse_sync_params(value, params);
}
if (err < 0)
break;
}
if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
OG_REST_PARAM_DISK |
OG_REST_PARAM_PARTITION |
OG_REST_PARAM_ID |
OG_REST_PARAM_NAME |
OG_REST_PARAM_REPO |
OG_REST_PARAM_PROFILE |
OG_REST_PARAM_TYPE |
OG_REST_PARAM_SYNC_DIFF_ID |
OG_REST_PARAM_SYNC_DIFF_NAME |
OG_REST_PARAM_SYNC_PATH |
OG_REST_PARAM_SYNC_METHOD |
OG_REST_PARAM_SYNC_SYNC |
OG_REST_PARAM_SYNC_DIFF |
OG_REST_PARAM_SYNC_REMOVE |
OG_REST_PARAM_SYNC_COMPRESS |
OG_REST_PARAM_SYNC_CLEANUP |
OG_REST_PARAM_SYNC_CACHE |
OG_REST_PARAM_SYNC_CLEANUP_CACHE |
OG_REST_PARAM_SYNC_REMOVE_DST))
return -1;
len = snprintf(buf, sizeof(buf),
"nfn=RestaurarSoftIncremental\rdsk=%s\rpar=%s\ridi=%s\rnci=%s\r"
"ipr=%s\rifs=%s\ridf=%s\rncf=%s\rrti=%s\rmet=%s\rmsy=%s\r"
"tpt=%s\rwhl=%s\reli=%s\rcmp=%s\rbpi=%s\rcpc=%s\rbpc=%s\r"
"nba=%s\r",
params->disk, params->partition, params->id, params->name,
params->repository, params->profile, params->sync_setup.diff_id,
params->sync_setup.diff_name, params->sync_setup.path,
params->sync_setup.method, params->sync_setup.sync, params->type,
params->sync_setup.diff, params->sync_setup.remove,
params->sync_setup.compress, params->sync_setup.cleanup,
params->sync_setup.cache, params->sync_setup.cleanup_cache,
params->sync_setup.remove_dst);
msg = og_msg_alloc(buf, len);
if (!msg)
return -1;
og_send_cmd((char **)params->ips_array, params->ips_array_len,
CLIENTE_OCUPADO, msg);
og_msg_free(msg);
return 0;
}
static int og_queue_task_command(struct og_dbi *dbi, const struct og_task *task,
char *query)
{
struct og_cmd *cmd;
const char *msglog;
dbi_result result;
result = dbi_conn_queryf(dbi->conn, query);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return -1;
}
while (dbi_result_next_row(result)) {
cmd = (struct og_cmd *)calloc(1, sizeof(struct og_cmd));
if (!cmd) {
dbi_result_free(result);
return -1;
}
cmd->client_id = dbi_result_get_uint(result, "idordenador");
cmd->params = task->params;
cmd->ip = strdup(dbi_result_get_string(result, "ip"));
cmd->mac = strdup(dbi_result_get_string(result, "mac"));
list_add_tail(&cmd->list, &cmd_list);
}
dbi_result_free(result);
return 0;
}
static int og_queue_task_group_clients(struct og_dbi *dbi, struct og_task *task,
char *query)
{
const char *msglog;
dbi_result result;
result = dbi_conn_queryf(dbi->conn, query);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return -1;
}
while (dbi_result_next_row(result)) {
uint32_t group_id = dbi_result_get_uint(result, "idgrupo");
sprintf(query, "SELECT idgrupo FROM gruposordenadores "
"WHERE grupoid=%d", group_id);
if (og_queue_task_group_clients(dbi, task, query)) {
dbi_result_free(result);
return -1;
}
sprintf(query,"SELECT ip, mac, idordenador FROM ordenadores "
"WHERE grupoid=%d", group_id);
if (og_queue_task_command(dbi, task, query)) {
dbi_result_free(result);
return -1;
}
}
dbi_result_free(result);
return 0;
}
static int og_queue_task_classrooms(struct og_dbi *dbi, struct og_task *task,
char *query)
{
const char *msglog;
dbi_result result;
result = dbi_conn_queryf(dbi->conn, query);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return -1;
}
while (dbi_result_next_row(result)) {
uint32_t classroom_id = dbi_result_get_uint(result, "idaula");
sprintf(query, "SELECT idgrupo FROM gruposordenadores "
"WHERE idaula=%d AND grupoid=0", classroom_id);
if (og_queue_task_group_clients(dbi, task, query)) {
dbi_result_free(result);
return -1;
}
sprintf(query,"SELECT ip, mac, idordenador FROM ordenadores "
"WHERE idaula=%d AND grupoid=0", classroom_id);
if (og_queue_task_command(dbi, task, query)) {
dbi_result_free(result);
return -1;
}
}
dbi_result_free(result);
return 0;
}
static int og_queue_task_group_classrooms(struct og_dbi *dbi,
struct og_task *task, char *query)
{
const char *msglog;
dbi_result result;
result = dbi_conn_queryf(dbi->conn, query);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return -1;
}
while (dbi_result_next_row(result)) {
uint32_t group_id = dbi_result_get_uint(result, "idgrupo");
sprintf(query, "SELECT idgrupo FROM grupos "
"WHERE grupoid=%d AND tipo=%d", group_id, AMBITO_GRUPOSAULAS);
if (og_queue_task_group_classrooms(dbi, task, query)) {
dbi_result_free(result);
return -1;
}
sprintf(query,"SELECT idaula FROM aulas WHERE grupoid=%d", group_id);
if (og_queue_task_classrooms(dbi, task, query)) {
dbi_result_free(result);
return -1;
}
}
dbi_result_free(result);
return 0;
}
static int og_queue_task_center(struct og_dbi *dbi, struct og_task *task,
char *query)
{
sprintf(query,"SELECT idgrupo FROM grupos WHERE idcentro=%i AND grupoid=0 AND tipo=%d",
task->scope, AMBITO_GRUPOSAULAS);
if (og_queue_task_group_classrooms(dbi, task, query))
return -1;
sprintf(query,"SELECT idaula FROM aulas WHERE idcentro=%i AND grupoid=0",
task->scope);
if (og_queue_task_classrooms(dbi, task, query))
return -1;
return 0;
}
static int og_queue_task_clients(struct og_dbi *dbi, struct og_task *task)
{
char query[4096];
switch (task->type_scope) {
case AMBITO_CENTROS:
return og_queue_task_center(dbi, task, query);
case AMBITO_GRUPOSAULAS:
sprintf(query, "SELECT idgrupo FROM grupos "
"WHERE idgrupo=%i AND tipo=%d",
task->scope, AMBITO_GRUPOSAULAS);
return og_queue_task_group_classrooms(dbi, task, query);
case AMBITO_AULAS:
sprintf(query, "SELECT idaula FROM aulas "
"WHERE idaula = %d", task->scope);
return og_queue_task_classrooms(dbi, task, query);
case AMBITO_GRUPOSORDENADORES:
sprintf(query, "SELECT idgrupo FROM gruposordenadores "
"WHERE idgrupo = %d", task->scope);
return og_queue_task_group_clients(dbi, task, query);
case AMBITO_ORDENADORES:
sprintf(query, "SELECT ip, mac, idordenador "
"FROM ordenadores "
"WHERE idordenador = %d", task->scope);
return og_queue_task_command(dbi, task, query);
}
return 0;
}
static int og_dbi_queue_procedure(struct og_dbi *dbi, struct og_task *task)
{
uint32_t procedure_id;
const char *msglog;
dbi_result result;
result = dbi_conn_queryf(dbi->conn,
"SELECT parametros, procedimientoid "
"FROM procedimientos_acciones "
"WHERE idprocedimiento=%d ORDER BY orden", task->procedure_id);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return -1;
}
while (dbi_result_next_row(result)) {
procedure_id = dbi_result_get_uint(result, "procedimientoid");
if (procedure_id > 0) {
task->procedure_id = procedure_id;
if (og_dbi_queue_procedure(dbi, task))
return -1;
continue;
}
task->params = strdup(dbi_result_get_string(result, "parametros"));
if (og_queue_task_clients(dbi, task))
return -1;
}
dbi_result_free(result);
return 0;
}
static int og_dbi_queue_task(struct og_dbi *dbi, uint32_t task_id)
{
struct og_task task = {};
uint32_t task_id_next;
const char *msglog;
dbi_result result;
result = dbi_conn_queryf(dbi->conn,
"SELECT tareas_acciones.orden, "
"tareas_acciones.idprocedimiento, "
"tareas_acciones.tareaid, "
"tareas.ambito, "
"tareas.idambito, "
"tareas.restrambito "
" FROM tareas"
" INNER JOIN tareas_acciones ON tareas_acciones.idtarea=tareas.idtarea"
" WHERE tareas_acciones.idtarea=%u ORDER BY tareas_acciones.orden ASC", task_id);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return -1;
}
while (dbi_result_next_row(result)) {
task_id_next = dbi_result_get_uint(result, "procedimientoid");
if (task_id_next > 0) {
if (og_dbi_queue_task(dbi, task_id_next))
return -1;
continue;
}
task.procedure_id = dbi_result_get_uint(result, "idprocedimiento");
task.type_scope = dbi_result_get_uint(result, "ambito");
task.scope = dbi_result_get_uint(result, "idambito");
task.filtered_scope = dbi_result_get_string(result, "restrambito");
og_dbi_queue_procedure(dbi, &task);
}
dbi_result_free(result);
return 0;
}
void og_dbi_schedule_task(unsigned int task_id)
{
struct og_msg_params params = {};
bool duplicated = false;
struct og_cmd *cmd;
struct og_dbi *dbi;
unsigned int i;
dbi = og_dbi_open(&dbi_config);
if (!dbi) {
syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
__func__, __LINE__);
return;
}
og_dbi_queue_task(dbi, task_id);
og_dbi_close(dbi);
list_for_each_entry(cmd, &cmd_list, list) {
for (i = 0; i < params.ips_array_len; i++) {
if (!strncmp(cmd->ip, params.ips_array[i],
OG_DB_IP_MAXLEN)) {
duplicated = true;
break;
}
}
if (!duplicated)
params.ips_array[params.ips_array_len++] = cmd->ip;
else
duplicated = false;
}
og_send_request("run/schedule", OG_METHOD_GET, &params, NULL);
}
static int og_cmd_task_post(json_t *element, struct og_msg_params *params)
{
struct og_cmd *cmd;
struct og_dbi *dbi;
const char *key;
json_t *value;
int err;
if (json_typeof(element) != JSON_OBJECT)
return -1;
json_object_foreach(element, key, value) {
if (!strcmp(key, "task")) {
err = og_json_parse_string(value, &params->task_id);
params->flags |= OG_REST_PARAM_TASK;
}
if (err < 0)
break;
}
if (!og_msg_params_validate(params, OG_REST_PARAM_TASK))
return -1;
dbi = og_dbi_open(&dbi_config);
if (!dbi) {
syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
__func__, __LINE__);
return -1;
}
og_dbi_queue_task(dbi, atoi(params->task_id));
og_dbi_close(dbi);
list_for_each_entry(cmd, &cmd_list, list)
params->ips_array[params->ips_array_len++] = cmd->ip;
return og_send_request("run/schedule", OG_METHOD_GET, params, NULL);
}
static int og_dbi_schedule_get(void)
{
uint32_t schedule_id, task_id;
struct og_schedule_time time;
struct og_dbi *dbi;
const char *msglog;
dbi_result result;
dbi = og_dbi_open(&dbi_config);
if (!dbi) {
syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
__func__, __LINE__);
return -1;
}
result = dbi_conn_queryf(dbi->conn,
"SELECT idprogramacion, tipoaccion, identificador, "
"sesion, annos, meses, diario, dias, semanas, horas, "
"ampm, minutos FROM programaciones "
"WHERE suspendida = 0");
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return -1;
}
while (dbi_result_next_row(result)) {
memset(&time, 0, sizeof(time));
schedule_id = dbi_result_get_uint(result, "idprogramacion");
task_id = dbi_result_get_uint(result, "identificador");
time.years = dbi_result_get_uint(result, "annos");
time.months = dbi_result_get_uint(result, "meses");
time.weeks = dbi_result_get_uint(result, "semanas");
time.week_days = dbi_result_get_uint(result, "dias");
time.days = dbi_result_get_uint(result, "diario");
time.hours = dbi_result_get_uint(result, "horas");
time.am_pm = dbi_result_get_uint(result, "ampm");
time.minutes = dbi_result_get_uint(result, "minutos");
og_schedule_create(schedule_id, task_id, &time);
}
dbi_result_free(result);
return 0;
}
static int og_dbi_schedule_create(struct og_dbi *dbi,
struct og_msg_params *params,
uint32_t *schedule_id)
{
const char *msglog;
dbi_result result;
uint8_t suspended = 0;
uint8_t type = 3;
result = dbi_conn_queryf(dbi->conn,
"INSERT INTO programaciones (tipoaccion,"
" identificador, nombrebloque, annos, meses,"
" diario, horas, ampm, minutos, suspendida) VALUES (%d,"
" %s, '%s', %d, %d, %d, %d, %d, %d, %d)", type,
params->task_id, params->name, params->time.years,
params->time.months, params->time.days,
params->time.hours, params->time.am_pm,
params->time.minutes, suspended);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return -1;
}
dbi_result_free(result);
*schedule_id = dbi_conn_sequence_last(dbi->conn, NULL);
return 0;
}
static int og_dbi_schedule_update(struct og_dbi *dbi,
struct og_msg_params *params)
{
const char *msglog;
dbi_result result;
uint8_t type = 3;
result = dbi_conn_queryf(dbi->conn,
"UPDATE programaciones SET tipoaccion=%d, "
"identificador='%s', nombrebloque='%s', "
"annos=%d, meses=%d, "
"diario=%d, horas=%d, ampm=%d, minutos=%d "
"WHERE idprogramacion='%s'",
type, params->task_id, params->name,
params->time.years, params->time.months,
params->time.days, params->time.hours,
params->time.am_pm, params->time.minutes,
params->id);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return -1;
}
dbi_result_free(result);
return 0;
}
static int og_dbi_schedule_delete(struct og_dbi *dbi, uint32_t id)
{
const char *msglog;
dbi_result result;
result = dbi_conn_queryf(dbi->conn,
"DELETE FROM programaciones WHERE idprogramacion=%d",
id);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return -1;
}
dbi_result_free(result);
return 0;
}
struct og_db_schedule {
uint32_t id;
uint32_t task_id;
const char *name;
struct og_schedule_time time;
uint32_t week_days;
uint32_t weeks;
uint32_t suspended;
uint32_t session;
};
static int og_dbi_schedule_get_json(struct og_dbi *dbi, json_t *root,
const char *task_id, const char *schedule_id)
{
struct og_db_schedule schedule;
json_t *obj, *array;
const char *msglog;
dbi_result result;
int err = 0;
if (task_id) {
result = dbi_conn_queryf(dbi->conn,
"SELECT idprogramacion,"
" identificador, nombrebloque,"
" annos, meses, diario, dias,"
" semanas, horas, ampm,"
" minutos,suspendida, sesion "
"FROM programaciones "
"WHERE identificador=%d",
atoi(task_id));
} else if (schedule_id) {
result = dbi_conn_queryf(dbi->conn,
"SELECT idprogramacion,"
" identificador, nombrebloque,"
" annos, meses, diario, dias,"
" semanas, horas, ampm,"
" minutos,suspendida, sesion "
"FROM programaciones "
"WHERE idprogramacion=%d",
atoi(schedule_id));
} else {
result = dbi_conn_queryf(dbi->conn,
"SELECT idprogramacion,"
" identificador, nombrebloque,"
" annos, meses, diario, dias,"
" semanas, horas, ampm,"
" minutos,suspendida, sesion "
"FROM programaciones");
}
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return -1;
}
array = json_array();
if (!array)
return -1;
while (dbi_result_next_row(result)) {
schedule.id = dbi_result_get_uint(result, "idprogramacion");
schedule.task_id = dbi_result_get_uint(result, "identificador");
schedule.name = dbi_result_get_string(result, "nombrebloque");
schedule.time.years = dbi_result_get_uint(result, "annos");
schedule.time.months = dbi_result_get_uint(result, "meses");
schedule.time.days = dbi_result_get_uint(result, "diario");
schedule.time.hours = dbi_result_get_uint(result, "horas");
schedule.time.am_pm = dbi_result_get_uint(result, "ampm");
schedule.time.minutes = dbi_result_get_uint(result, "minutos");
schedule.week_days = dbi_result_get_uint(result, "dias");
schedule.weeks = dbi_result_get_uint(result, "semanas");
schedule.suspended = dbi_result_get_uint(result, "suspendida");
schedule.session = dbi_result_get_uint(result, "sesion");
obj = json_object();
if (!obj) {
err = -1;
break;
}
json_object_set_new(obj, "id", json_integer(schedule.id));
json_object_set_new(obj, "task", json_integer(schedule.task_id));
json_object_set_new(obj, "name", json_string(schedule.name));
json_object_set_new(obj, "years", json_integer(schedule.time.years));
json_object_set_new(obj, "months", json_integer(schedule.time.months));
json_object_set_new(obj, "days", json_integer(schedule.time.days));
json_object_set_new(obj, "hours", json_integer(schedule.time.hours));
json_object_set_new(obj, "am_pm", json_integer(schedule.time.am_pm));
json_object_set_new(obj, "minutes", json_integer(schedule.time.minutes));
json_object_set_new(obj, "week_days", json_integer(schedule.week_days));
json_object_set_new(obj, "weeks", json_integer(schedule.weeks));
json_object_set_new(obj, "suspended", json_integer(schedule.suspended));
json_object_set_new(obj, "session", json_integer(schedule.session));
json_array_append_new(array, obj);
}
json_object_set_new(root, "schedule", array);
dbi_result_free(result);
return err;
}
static struct ev_loop *og_loop;
static int og_cmd_schedule_create(json_t *element, struct og_msg_params *params)
{
uint32_t schedule_id;
struct og_dbi *dbi;
const char *key;
json_t *value;
int err;
if (json_typeof(element) != JSON_OBJECT)
return -1;
json_object_foreach(element, key, value) {
if (!strcmp(key, "task")) {
err = og_json_parse_string(value, &params->task_id);
params->flags |= OG_REST_PARAM_TASK;
} else if (!strcmp(key, "name")) {
err = og_json_parse_string(value, &params->name);
params->flags |= OG_REST_PARAM_NAME;
} else if (!strcmp(key, "when"))
err = og_json_parse_time_params(value, params);
if (err < 0)
break;
}
if (!og_msg_params_validate(params, OG_REST_PARAM_TASK |
OG_REST_PARAM_NAME |
OG_REST_PARAM_TIME_YEARS |
OG_REST_PARAM_TIME_MONTHS |
OG_REST_PARAM_TIME_DAYS |
OG_REST_PARAM_TIME_HOURS |
OG_REST_PARAM_TIME_MINUTES |
OG_REST_PARAM_TIME_AM_PM))
return -1;
dbi = og_dbi_open(&dbi_config);
if (!dbi) {
syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
__func__, __LINE__);
return -1;
}
err = og_dbi_schedule_create(dbi, params, &schedule_id);
og_dbi_close(dbi);
if (err < 0)
return -1;
og_schedule_create(schedule_id, atoi(params->task_id), &params->time);
og_schedule_refresh(og_loop);
return err;
}
static int og_cmd_schedule_update(json_t *element, struct og_msg_params *params)
{
struct og_dbi *dbi;
const char *key;
json_t *value;
int err;
if (json_typeof(element) != JSON_OBJECT)
return -1;
json_object_foreach(element, key, value) {
if (!strcmp(key, "id")) {
err = og_json_parse_string(value, &params->id);
params->flags |= OG_REST_PARAM_ID;
} else if (!strcmp(key, "task")) {
err = og_json_parse_string(value, &params->task_id);
params->flags |= OG_REST_PARAM_TASK;
} else if (!strcmp(key, "name")) {
err = og_json_parse_string(value, &params->name);
params->flags |= OG_REST_PARAM_NAME;
} else if (!strcmp(key, "when"))
err = og_json_parse_time_params(value, params);
if (err < 0)
break;
}
if (!og_msg_params_validate(params, OG_REST_PARAM_ID |
OG_REST_PARAM_TASK |
OG_REST_PARAM_NAME |
OG_REST_PARAM_TIME_YEARS |
OG_REST_PARAM_TIME_MONTHS |
OG_REST_PARAM_TIME_DAYS |
OG_REST_PARAM_TIME_HOURS |
OG_REST_PARAM_TIME_MINUTES |
OG_REST_PARAM_TIME_AM_PM))
return -1;
dbi = og_dbi_open(&dbi_config);
if (!dbi) {
syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
__func__, __LINE__);
return -1;
}
err = og_dbi_schedule_update(dbi, params);
og_dbi_close(dbi);
if (err < 0)
return err;
og_schedule_update(og_loop, atoi(params->id), atoi(params->task_id),
&params->time);
og_schedule_refresh(og_loop);
return err;
}
static int og_cmd_schedule_delete(json_t *element, struct og_msg_params *params)
{
struct og_dbi *dbi;
const char *key;
json_t *value;
int err;
if (json_typeof(element) != JSON_OBJECT)
return -1;
json_object_foreach(element, key, value) {
if (!strcmp(key, "id")) {
err = og_json_parse_string(value, &params->id);
params->flags |= OG_REST_PARAM_ID;
} else {
return -1;
}
if (err < 0)
break;
}
if (!og_msg_params_validate(params, OG_REST_PARAM_ID))
return -1;
dbi = og_dbi_open(&dbi_config);
if (!dbi) {
syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
__func__, __LINE__);
return -1;
}
err = og_dbi_schedule_delete(dbi, atoi(params->id));
og_dbi_close(dbi);
og_schedule_delete(og_loop, atoi(params->id));
return err;
}
static int og_cmd_schedule_get(json_t *element, struct og_msg_params *params,
char *buffer_reply)
{
struct og_buffer og_buffer = {
.data = buffer_reply,
};
json_t *schedule_root;
struct og_dbi *dbi;
const char *key;
json_t *value;
int err;
if (element) {
if (json_typeof(element) != JSON_OBJECT)
return -1;
json_object_foreach(element, key, value) {
if (!strcmp(key, "task")) {
err = og_json_parse_string(value,
&params->task_id);
} else if (!strcmp(key, "id")) {
err = og_json_parse_string(value, &params->id);
} else {
return -1;
}
if (err < 0)
break;
}
}
dbi = og_dbi_open(&dbi_config);
if (!dbi) {
syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
__func__, __LINE__);
return -1;
}
schedule_root = json_object();
if (!schedule_root) {
og_dbi_close(dbi);
return -1;
}
err = og_dbi_schedule_get_json(dbi, schedule_root,
params->task_id, params->id);
og_dbi_close(dbi);
if (err >= 0)
json_dump_callback(schedule_root, og_json_dump_clients, &og_buffer, 0);
json_decref(schedule_root);
return err;
}
static int og_client_method_not_found(struct og_client *cli)
{
/* To meet RFC 7231, this function MUST generate an Allow header field
* containing the correct methods. For example: "Allow: POST\r\n"
*/
char buf[] = "HTTP/1.1 405 Method Not Allowed\r\n"
"Content-Length: 0\r\n\r\n";
send(og_client_socket(cli), buf, strlen(buf), 0);
return -1;
}
static int og_client_bad_request(struct og_client *cli)
{
char buf[] = "HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n";
send(og_client_socket(cli), buf, strlen(buf), 0);
return -1;
}
static int og_client_not_found(struct og_client *cli)
{
char buf[] = "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n";
send(og_client_socket(cli), buf, strlen(buf), 0);
return -1;
}
static int og_client_not_authorized(struct og_client *cli)
{
char buf[] = "HTTP/1.1 401 Unauthorized\r\n"
"WWW-Authenticate: Basic\r\n"
"Content-Length: 0\r\n\r\n";
send(og_client_socket(cli), buf, strlen(buf), 0);
return -1;
}
static int og_server_internal_error(struct og_client *cli)
{
char buf[] = "HTTP/1.1 500 Internal Server Error\r\n"
"Content-Length: 0\r\n\r\n";
send(og_client_socket(cli), buf, strlen(buf), 0);
return -1;
}
static int og_client_payload_too_large(struct og_client *cli)
{
char buf[] = "HTTP/1.1 413 Payload Too Large\r\n"
"Content-Length: 0\r\n\r\n";
send(og_client_socket(cli), buf, strlen(buf), 0);
return -1;
}
#define OG_MSG_RESPONSE_MAXLEN 65536
static int og_client_ok(struct og_client *cli, char *buf_reply)
{
char buf[OG_MSG_RESPONSE_MAXLEN] = {};
int err = 0, len;
len = snprintf(buf, sizeof(buf),
"HTTP/1.1 200 OK\r\nContent-Length: %ld\r\n\r\n%s",
strlen(buf_reply), buf_reply);
if (len >= (int)sizeof(buf))
err = og_server_internal_error(cli);
send(og_client_socket(cli), buf, strlen(buf), 0);
return err;
}
static int og_client_state_process_payload_rest(struct og_client *cli)
{
char buf_reply[OG_MSG_RESPONSE_MAXLEN] = {};
struct og_msg_params params = {};
enum og_rest_method method;
const char *cmd, *body;
json_error_t json_err;
json_t *root = NULL;
int err = 0;
syslog(LOG_DEBUG, "%s:%hu %.32s ...\n",
inet_ntoa(cli->addr.sin_addr),
ntohs(cli->addr.sin_port), cli->buf);
if (!strncmp(cli->buf, "GET", strlen("GET"))) {
method = OG_METHOD_GET;
cmd = cli->buf + strlen("GET") + 2;
} else if (!strncmp(cli->buf, "POST", strlen("POST"))) {
method = OG_METHOD_POST;
cmd = cli->buf + strlen("POST") + 2;
} else
return og_client_method_not_found(cli);
body = strstr(cli->buf, "\r\n\r\n") + 4;
if (strcmp(cli->auth_token, auth_token)) {
syslog(LOG_ERR, "wrong Authentication key\n");
return og_client_not_authorized(cli);
}
if (cli->content_length) {
root = json_loads(body, 0, &json_err);
if (!root) {
syslog(LOG_ERR, "malformed json line %d: %s\n",
json_err.line, json_err.text);
return og_client_not_found(cli);
}
}
if (!strncmp(cmd, "clients", strlen("clients"))) {
if (method != OG_METHOD_POST &&
method != OG_METHOD_GET)
return og_client_method_not_found(cli);
if (method == OG_METHOD_POST && !root) {
syslog(LOG_ERR, "command clients with no payload\n");
return og_client_bad_request(cli);
}
switch (method) {
case OG_METHOD_POST:
err = og_cmd_post_clients(root, &params);
break;
case OG_METHOD_GET:
err = og_cmd_get_clients(root, &params, buf_reply);
break;
}
} else if (!strncmp(cmd, "wol", strlen("wol"))) {
if (method != OG_METHOD_POST)
return og_client_method_not_found(cli);
if (!root) {
syslog(LOG_ERR, "command wol with no payload\n");
return og_client_bad_request(cli);
}
err = og_cmd_wol(root, &params);
} else if (!strncmp(cmd, "shell/run", strlen("shell/run"))) {
if (method != OG_METHOD_POST)
return og_client_method_not_found(cli);
if (!root) {
syslog(LOG_ERR, "command run with no payload\n");
return og_client_bad_request(cli);
}
err = og_cmd_run_post(root, &params);
} else if (!strncmp(cmd, "shell/output", strlen("shell/output"))) {
if (method != OG_METHOD_POST)
return og_client_method_not_found(cli);
if (!root) {
syslog(LOG_ERR, "command output with no payload\n");
return og_client_bad_request(cli);
}
err = og_cmd_run_get(root, &params, buf_reply);
} else if (!strncmp(cmd, "session", strlen("session"))) {
if (method != OG_METHOD_POST)
return og_client_method_not_found(cli);
if (!root) {
syslog(LOG_ERR, "command session with no payload\n");
return og_client_bad_request(cli);
}
err = og_cmd_session(root, &params);
} else if (!strncmp(cmd, "poweroff", strlen("poweroff"))) {
if (method != OG_METHOD_POST)
return og_client_method_not_found(cli);
if (!root) {
syslog(LOG_ERR, "command poweroff with no payload\n");
return og_client_bad_request(cli);
}
err = og_cmd_poweroff(root, &params);
} else if (!strncmp(cmd, "reboot", strlen("reboot"))) {
if (method != OG_METHOD_POST)
return og_client_method_not_found(cli);
if (!root) {
syslog(LOG_ERR, "command reboot with no payload\n");
return og_client_bad_request(cli);
}
err = og_cmd_reboot(root, &params);
} else if (!strncmp(cmd, "stop", strlen("stop"))) {
if (method != OG_METHOD_POST)
return og_client_method_not_found(cli);
if (!root) {
syslog(LOG_ERR, "command stop with no payload\n");
return og_client_bad_request(cli);
}
err = og_cmd_stop(root, &params);
} else if (!strncmp(cmd, "refresh", strlen("refresh"))) {
if (method != OG_METHOD_POST)
return og_client_method_not_found(cli);
if (!root) {
syslog(LOG_ERR, "command refresh with no payload\n");
return og_client_bad_request(cli);
}
err = og_cmd_refresh(root, &params);
} else if (!strncmp(cmd, "hardware", strlen("hardware"))) {
if (method != OG_METHOD_POST)
return og_client_method_not_found(cli);
if (!root) {
syslog(LOG_ERR, "command hardware with no payload\n");
return og_client_bad_request(cli);
}
err = og_cmd_hardware(root, &params);
} else if (!strncmp(cmd, "software", strlen("software"))) {
if (method != OG_METHOD_POST)
return og_client_method_not_found(cli);
if (!root) {
syslog(LOG_ERR, "command software with no payload\n");
return og_client_bad_request(cli);
}
err = og_cmd_software(root, &params);
} else if (!strncmp(cmd, "image/create/basic",
strlen("image/create/basic"))) {
if (method != OG_METHOD_POST)
return og_client_method_not_found(cli);
if (!root) {
syslog(LOG_ERR, "command create with no payload\n");
return og_client_bad_request(cli);
}
err = og_cmd_create_basic_image(root, &params);
} else if (!strncmp(cmd, "image/create/incremental",
strlen("image/create/incremental"))) {
if (method != OG_METHOD_POST)
return og_client_method_not_found(cli);
if (!root) {
syslog(LOG_ERR, "command create with no payload\n");
return og_client_bad_request(cli);
}
err = og_cmd_create_incremental_image(root, &params);
} else if (!strncmp(cmd, "image/create", strlen("image/create"))) {
if (method != OG_METHOD_POST)
return og_client_method_not_found(cli);
if (!root) {
syslog(LOG_ERR, "command create with no payload\n");
return og_client_bad_request(cli);
}
err = og_cmd_create_image(root, &params);
} else if (!strncmp(cmd, "image/restore/basic",
strlen("image/restore/basic"))) {
if (method != OG_METHOD_POST)
return og_client_method_not_found(cli);
if (!root) {
syslog(LOG_ERR, "command create with no payload\n");
return og_client_bad_request(cli);
}
err = og_cmd_restore_basic_image(root, &params);
} else if (!strncmp(cmd, "image/restore/incremental",
strlen("image/restore/incremental"))) {
if (method != OG_METHOD_POST)
return og_client_method_not_found(cli);
if (!root) {
syslog(LOG_ERR, "command create with no payload\n");
return og_client_bad_request(cli);
}
err = og_cmd_restore_incremental_image(root, &params);
} else if (!strncmp(cmd, "image/restore", strlen("image/restore"))) {
if (method != OG_METHOD_POST)
return og_client_method_not_found(cli);
if (!root) {
syslog(LOG_ERR, "command create with no payload\n");
return og_client_bad_request(cli);
}
err = og_cmd_restore_image(root, &params);
} else if (!strncmp(cmd, "setup", strlen("setup"))) {
if (method != OG_METHOD_POST)
return og_client_method_not_found(cli);
if (!root) {
syslog(LOG_ERR, "command create with no payload\n");
return og_client_bad_request(cli);
}
err = og_cmd_setup(root, &params);
} else if (!strncmp(cmd, "run/schedule", strlen("run/schedule"))) {
if (method != OG_METHOD_POST)
return og_client_method_not_found(cli);
if (!root) {
syslog(LOG_ERR, "command create with no payload\n");
return og_client_bad_request(cli);
}
err = og_cmd_run_schedule(root, &params);
} else if (!strncmp(cmd, "task/run", strlen("task/run"))) {
if (method != OG_METHOD_POST)
return og_client_method_not_found(cli);
if (!root) {
syslog(LOG_ERR, "command task with no payload\n");
return og_client_bad_request(cli);
}
err = og_cmd_task_post(root, &params);
} else if (!strncmp(cmd, "schedule/create",
strlen("schedule/create"))) {
if (method != OG_METHOD_POST)
return og_client_method_not_found(cli);
if (!root) {
syslog(LOG_ERR, "command task with no payload\n");
return og_client_bad_request(cli);
}
err = og_cmd_schedule_create(root, &params);
} else if (!strncmp(cmd, "schedule/delete",
strlen("schedule/delete"))) {
if (method != OG_METHOD_POST)
return og_client_method_not_found(cli);
if (!root) {
syslog(LOG_ERR, "command task with no payload\n");
return og_client_bad_request(cli);
}
err = og_cmd_schedule_delete(root, &params);
} else if (!strncmp(cmd, "schedule/update",
strlen("schedule/update"))) {
if (method != OG_METHOD_POST)
return og_client_method_not_found(cli);
if (!root) {
syslog(LOG_ERR, "command task with no payload\n");
return og_client_bad_request(cli);
}
err = og_cmd_schedule_update(root, &params);
} else if (!strncmp(cmd, "schedule/get",
strlen("schedule/get"))) {
if (method != OG_METHOD_POST)
return og_client_method_not_found(cli);
err = og_cmd_schedule_get(root, &params, buf_reply);
} else {
syslog(LOG_ERR, "unknown command: %.32s ...\n", cmd);
err = og_client_not_found(cli);
}
if (root)
json_decref(root);
if (err < 0)
return og_client_bad_request(cli);
err = og_client_ok(cli, buf_reply);
if (err < 0) {
syslog(LOG_ERR, "HTTP response to %s:%hu is too large\n",
inet_ntoa(cli->addr.sin_addr),
ntohs(cli->addr.sin_port));
}
return err;
}
static int og_client_state_recv_hdr_rest(struct og_client *cli)
{
char *ptr;
ptr = strstr(cli->buf, "\r\n\r\n");
if (!ptr)
return 0;
cli->msg_len = ptr - cli->buf + 4;
ptr = strstr(cli->buf, "Content-Length: ");
if (ptr) {
sscanf(ptr, "Content-Length: %i[^\r\n]", &cli->content_length);
if (cli->content_length < 0)
return -1;
cli->msg_len += cli->content_length;
}
ptr = strstr(cli->buf, "Authorization: ");
if (ptr)
sscanf(ptr, "Authorization: %63[^\r\n]", cli->auth_token);
return 1;
}
static int og_client_recv(struct og_client *cli, int events)
{
struct ev_io *io = &cli->io;
int ret;
if (events & EV_ERROR) {
syslog(LOG_ERR, "unexpected error event from client %s:%hu\n",
inet_ntoa(cli->addr.sin_addr),
ntohs(cli->addr.sin_port));
return 0;
}
ret = recv(io->fd, cli->buf + cli->buf_len,
sizeof(cli->buf) - cli->buf_len, 0);
if (ret <= 0) {
if (ret < 0) {
syslog(LOG_ERR, "error reading from client %s:%hu (%s)\n",
inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port),
strerror(errno));
} else {
syslog(LOG_DEBUG, "closed connection by %s:%hu\n",
inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
}
return ret;
}
return ret;
}
static void og_client_read_cb(struct ev_loop *loop, struct ev_io *io, int events)
{
struct og_client *cli;
int ret;
cli = container_of(io, struct og_client, io);
ret = og_client_recv(cli, events);
if (ret <= 0)
goto close;
if (cli->keepalive_idx >= 0)
return;
ev_timer_again(loop, &cli->timer);
cli->buf_len += ret;
if (cli->buf_len >= sizeof(cli->buf)) {
syslog(LOG_ERR, "client request from %s:%hu is too long\n",
inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
og_client_payload_too_large(cli);
goto close;
}
switch (cli->state) {
case OG_CLIENT_RECEIVING_HEADER:
if (cli->rest)
ret = og_client_state_recv_hdr_rest(cli);
else
ret = og_client_state_recv_hdr(cli);
if (ret < 0)
goto close;
if (!ret)
return;
cli->state = OG_CLIENT_RECEIVING_PAYLOAD;
/* Fall through. */
case OG_CLIENT_RECEIVING_PAYLOAD:
/* Still not enough data to process request. */
if (cli->buf_len < cli->msg_len)
return;
cli->state = OG_CLIENT_PROCESSING_REQUEST;
/* fall through. */
case OG_CLIENT_PROCESSING_REQUEST:
if (cli->rest) {
ret = og_client_state_process_payload_rest(cli);
if (ret < 0) {
syslog(LOG_ERR, "Failed to process HTTP request from %s:%hu\n",
inet_ntoa(cli->addr.sin_addr),
ntohs(cli->addr.sin_port));
}
} else {
ret = og_client_state_process_payload(cli);
}
if (ret < 0)
goto close;
if (cli->keepalive_idx < 0) {
syslog(LOG_DEBUG, "server closing connection to %s:%hu\n",
inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
goto close;
} else {
syslog(LOG_DEBUG, "leaving client %s:%hu in keepalive mode\n",
inet_ntoa(cli->addr.sin_addr),
ntohs(cli->addr.sin_port));
og_client_keepalive(loop, cli);
og_client_reset_state(cli);
}
break;
default:
syslog(LOG_ERR, "unknown state, critical internal error\n");
goto close;
}
return;
close:
ev_timer_stop(loop, &cli->timer);
og_client_release(loop, cli);
}
enum og_agent_state {
OG_AGENT_RECEIVING_HEADER = 0,
OG_AGENT_RECEIVING_PAYLOAD,
OG_AGENT_PROCESSING_RESPONSE,
};
static int og_agent_state_recv_hdr_rest(struct og_client *cli)
{
char *ptr;
ptr = strstr(cli->buf, "\r\n\r\n");
if (!ptr)
return 0;
cli->msg_len = ptr - cli->buf + 4;
ptr = strstr(cli->buf, "Content-Length: ");
if (ptr) {
sscanf(ptr, "Content-Length: %i[^\r\n]", &cli->content_length);
if (cli->content_length < 0)
return -1;
cli->msg_len += cli->content_length;
}
return 1;
}
static void og_agent_reset_state(struct og_client *cli)
{
cli->state = OG_AGENT_RECEIVING_HEADER;
cli->buf_len = 0;
cli->content_length = 0;
memset(cli->buf, 0, sizeof(cli->buf));
}
static int og_dbi_get_computer_info(struct og_computer *computer,
struct in_addr addr)
{
const char *msglog;
struct og_dbi *dbi;
dbi_result result;
dbi = og_dbi_open(&dbi_config);
if (!dbi) {
syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
__func__, __LINE__);
return -1;
}
result = dbi_conn_queryf(dbi->conn,
"SELECT ordenadores.idordenador,"
" ordenadores.nombreordenador,"
" ordenadores.idaula,"
" centros.idcentro FROM ordenadores "
"INNER JOIN aulas ON aulas.idaula=ordenadores.idaula "
"INNER JOIN centros ON centros.idcentro=aulas.idcentro "
"WHERE ordenadores.ip='%s'", inet_ntoa(addr));
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return -1;
}
if (!dbi_result_next_row(result)) {
syslog(LOG_ERR, "client does not exist in database (%s:%d)\n",
__func__, __LINE__);
dbi_result_free(result);
return -1;
}
computer->id = dbi_result_get_uint(result, "idordenador");
computer->center = dbi_result_get_uint(result, "idcentro");
computer->room = dbi_result_get_uint(result, "idaula");
strncpy(computer->name,
dbi_result_get_string(result, "nombreordenador"),
OG_COMPUTER_NAME_MAXLEN);
dbi_result_free(result);
og_dbi_close(dbi);
return 0;
}
static int og_resp_probe(struct og_client *cli, json_t *data)
{
bool status = false;
const char *key;
json_t *value;
int err = 0;
if (json_typeof(data) != JSON_OBJECT)
return -1;
json_object_foreach(data, key, value) {
if (!strcmp(key, "status")) {
err = og_json_parse_string(value, &cli->status);
if (err < 0)
return err;
status = true;
} else {
return -1;
}
}
return status ? 0 : -1;
}
static int og_resp_shell_run(struct og_client *cli, json_t *data)
{
const char *output = NULL;
char filename[4096];
const char *key;
json_t *value;
int err = -1;
FILE *file;
if (json_typeof(data) != JSON_OBJECT)
return -1;
json_object_foreach(data, key, value) {
if (!strcmp(key, "out")) {
err = og_json_parse_string(value, &output);
if (err < 0)
return err;
} else {
return -1;
}
}
if (!output) {
syslog(LOG_ERR, "%s:%d: malformed json response\n",
__FILE__, __LINE__);
return -1;
}
sprintf(filename, "/tmp/_Seconsola_%s", inet_ntoa(cli->addr.sin_addr));
file = fopen(filename, "wt");
if (!file) {
syslog(LOG_ERR, "cannot open file %s: %s\n",
filename, strerror(errno));
return -1;
}
fprintf(file, "%s", output);
fclose(file);
return 0;
}
#define OG_DB_INT_MAXLEN 11
struct og_computer_legacy {
char center[OG_DB_INT_MAXLEN + 1];
char id[OG_DB_INT_MAXLEN + 1];
char hardware[8192];
};
static int og_resp_hardware(json_t *data, struct og_client *cli)
{
struct og_computer_legacy legacy = {};
const char *hardware = NULL;
struct og_computer computer;
struct og_dbi *dbi;
const char *key;
json_t *value;
int err = 0;
bool res;
if (json_typeof(data) != JSON_OBJECT)
return -1;
json_object_foreach(data, key, value) {
if (!strcmp(key, "hardware")) {
err = og_json_parse_string(value, &hardware);
if (err < 0)
return -1;
} else {
return -1;
}
}
if (!hardware) {
syslog(LOG_ERR, "malformed response json\n");
return -1;
}
err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr);
if (err < 0)
return -1;
snprintf(legacy.center, sizeof(legacy.center), "%d", computer.center);
snprintf(legacy.id, sizeof(legacy.id), "%d", computer.id);
snprintf(legacy.hardware, sizeof(legacy.hardware), "%s", hardware);
dbi = og_dbi_open(&dbi_config);
if (!dbi) {
syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
__func__, __LINE__);
return -1;
}
res = actualizaHardware(dbi, legacy.hardware, legacy.id, computer.name,
legacy.center);
og_dbi_close(dbi);
if (!res) {
syslog(LOG_ERR, "Problem updating client configuration\n");
return -1;
}
return 0;
}
#define OG_DB_SMALLINT_MAXLEN 6
struct og_software_legacy {
char software[8192];
char center[OG_DB_INT_MAXLEN + 1];
char part[OG_DB_SMALLINT_MAXLEN + 1];
char id[OG_DB_INT_MAXLEN + 1];
};
static int og_resp_software(json_t *data, struct og_client *cli)
{
struct og_software_legacy legacy = {};
const char *partition = NULL;
const char *software = NULL;
struct og_computer computer;
struct og_dbi *dbi;
const char *key;
json_t *value;
int err = 0;
bool res;
if (json_typeof(data) != JSON_OBJECT)
return -1;
json_object_foreach(data, key, value) {
if (!strcmp(key, "software"))
err = og_json_parse_string(value, &software);
else if (!strcmp(key, "partition"))
err = og_json_parse_string(value, &partition);
else
return -1;
if (err < 0)
return -1;
}
if (!software || !partition) {
syslog(LOG_ERR, "malformed response json\n");
return -1;
}
err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr);
if (err < 0)
return -1;
snprintf(legacy.software, sizeof(legacy.software), "%s", software);
snprintf(legacy.part, sizeof(legacy.part), "%s", partition);
snprintf(legacy.id, sizeof(legacy.id), "%d", computer.id);
snprintf(legacy.center, sizeof(legacy.center), "%d", computer.center);
dbi = og_dbi_open(&dbi_config);
if (!dbi) {
syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
__func__, __LINE__);
return -1;
}
res = actualizaSoftware(dbi, legacy.software, legacy.part, legacy.id,
computer.name, legacy.center);
og_dbi_close(dbi);
if (!res) {
syslog(LOG_ERR, "Problem updating client configuration\n");
return -1;
}
return 0;
}
#define OG_PARAMS_RESP_REFRESH (OG_PARAM_PART_DISK | \
OG_PARAM_PART_NUMBER | \
OG_PARAM_PART_CODE | \
OG_PARAM_PART_FILESYSTEM | \
OG_PARAM_PART_OS | \
OG_PARAM_PART_SIZE | \
OG_PARAM_PART_USED_SIZE)
static int og_json_parse_partition_array(json_t *value,
struct og_partition *partitions)
{
json_t *element;
int i, err;
if (json_typeof(value) != JSON_ARRAY)
return -1;
for (i = 0; i < json_array_size(value) && i < OG_PARTITION_MAX; i++) {
element = json_array_get(value, i);
err = og_json_parse_partition(element, &partitions[i],
OG_PARAMS_RESP_REFRESH);
if (err < 0)
return err;
}
return 0;
}
static int og_resp_refresh(json_t *data, struct og_client *cli)
{
struct og_partition partitions[OG_PARTITION_MAX] = {};
const char *serial_number = NULL;
struct og_partition disk_setup;
struct og_computer computer;
char cfg[1024] = {};
struct og_dbi *dbi;
const char *key;
unsigned int i;
json_t *value;
int err = 0;
bool res;
if (json_typeof(data) != JSON_OBJECT)
return -1;
json_object_foreach(data, key, value) {
if (!strcmp(key, "disk_setup")) {
err = og_json_parse_partition(value,
&disk_setup,
OG_PARAMS_RESP_REFRESH);
} else if (!strcmp(key, "partition_setup")) {
err = og_json_parse_partition_array(value, partitions);
} else if (!strcmp(key, "serial_number")) {
err = og_json_parse_string(value, &serial_number);
} else {
return -1;
}
if (err < 0)
return err;
}
err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr);
if (err < 0)
return -1;
if (strlen(serial_number) > 0)
snprintf(cfg, sizeof(cfg), "ser=%s\n", serial_number);
if (!disk_setup.disk || !disk_setup.number || !disk_setup.code ||
!disk_setup.filesystem || !disk_setup.os || !disk_setup.size ||
!disk_setup.used_size)
return -1;
snprintf(cfg + strlen(cfg), sizeof(cfg) - strlen(cfg),
"disk=%s\tpar=%s\tcpt=%s\tfsi=%s\tsoi=%s\ttam=%s\tuso=%s\n",
disk_setup.disk, disk_setup.number, disk_setup.code,
disk_setup.filesystem, disk_setup.os, disk_setup.size,
disk_setup.used_size);
for (i = 0; i < OG_PARTITION_MAX; i++) {
if (!partitions[i].disk || !partitions[i].number ||
!partitions[i].code || !partitions[i].filesystem ||
!partitions[i].os || !partitions[i].size ||
!partitions[i].used_size)
continue;
snprintf(cfg + strlen(cfg), sizeof(cfg) - strlen(cfg),
"disk=%s\tpar=%s\tcpt=%s\tfsi=%s\tsoi=%s\ttam=%s\tuso=%s\n",
partitions[i].disk, partitions[i].number,
partitions[i].code, partitions[i].filesystem,
partitions[i].os, partitions[i].size,
partitions[i].used_size);
}
dbi = og_dbi_open(&dbi_config);
if (!dbi) {
syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
__func__, __LINE__);
return -1;
}
res = actualizaConfiguracion(dbi, cfg, computer.id);
og_dbi_close(dbi);
if (!res) {
syslog(LOG_ERR, "Problem updating client configuration\n");
return -1;
}
return 0;
}
static int og_resp_setup(struct og_client *cli)
{
struct og_msg_params params;
params.ips_array[0] = inet_ntoa(cli->addr.sin_addr);
params.ips_array_len = 1;
return og_send_request("refresh", OG_METHOD_GET, &params, NULL);
}
#define OG_DB_IMAGE_NAME_MAXLEN 50
#define OG_DB_IP_MAXLEN 15
#define OG_DB_INT8_MAXLEN 8
struct og_image_legacy {
char software_id[OG_DB_INT_MAXLEN + 1];
char image_id[OG_DB_INT_MAXLEN + 1];
char name[OG_DB_IMAGE_NAME_MAXLEN + 1];
char repo[OG_DB_IP_MAXLEN + 1];
char part[OG_DB_SMALLINT_MAXLEN + 1];
char disk[OG_DB_SMALLINT_MAXLEN + 1];
char code[OG_DB_INT8_MAXLEN + 1];
};
static int og_resp_image_create(json_t *data, struct og_client *cli)
{
struct og_software_legacy soft_legacy;
struct og_image_legacy img_legacy;
const char *partition = NULL;
const char *software = NULL;
const char *image_id = NULL;
struct og_computer computer;
const char *disk = NULL;
const char *code = NULL;
const char *name = NULL;
const char *repo = NULL;
struct og_dbi *dbi;
const char *key;
json_t *value;
int err = 0;
bool res;
if (json_typeof(data) != JSON_OBJECT)
return -1;
json_object_foreach(data, key, value) {
if (!strcmp(key, "software"))
err = og_json_parse_string(value, &software);
else if (!strcmp(key, "partition"))
err = og_json_parse_string(value, &partition);
else if (!strcmp(key, "disk"))
err = og_json_parse_string(value, &disk);
else if (!strcmp(key, "code"))
err = og_json_parse_string(value, &code);
else if (!strcmp(key, "id"))
err = og_json_parse_string(value, &image_id);
else if (!strcmp(key, "name"))
err = og_json_parse_string(value, &name);
else if (!strcmp(key, "repository"))
err = og_json_parse_string(value, &repo);
else
return -1;
if (err < 0)
return err;
}
if (!software || !partition || !disk || !code || !image_id || !name ||
!repo) {
syslog(LOG_ERR, "malformed response json\n");
return -1;
}
err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr);
if (err < 0)
return -1;
snprintf(soft_legacy.center, sizeof(soft_legacy.center), "%d",
computer.center);
snprintf(soft_legacy.software, sizeof(soft_legacy.software), "%s",
software);
snprintf(img_legacy.image_id, sizeof(img_legacy.image_id), "%s",
image_id);
snprintf(soft_legacy.id, sizeof(soft_legacy.id), "%d", computer.id);
snprintf(img_legacy.part, sizeof(img_legacy.part), "%s", partition);
snprintf(img_legacy.disk, sizeof(img_legacy.disk), "%s", disk);
snprintf(img_legacy.code, sizeof(img_legacy.code), "%s", code);
snprintf(img_legacy.name, sizeof(img_legacy.name), "%s", name);
snprintf(img_legacy.repo, sizeof(img_legacy.repo), "%s", repo);
dbi = og_dbi_open(&dbi_config);
if (!dbi) {
syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
__func__, __LINE__);
return -1;
}
res = actualizaSoftware(dbi,
soft_legacy.software,
img_legacy.part,
soft_legacy.id,
computer.name,
soft_legacy.center);
if (!res) {
og_dbi_close(dbi);
syslog(LOG_ERR, "Problem updating client configuration\n");
return -1;
}
res = actualizaCreacionImagen(dbi,
img_legacy.image_id,
img_legacy.disk,
img_legacy.part,
img_legacy.code,
img_legacy.repo,
soft_legacy.id);
og_dbi_close(dbi);
if (!res) {
syslog(LOG_ERR, "Problem updating client configuration\n");
return -1;
}
return 0;
}
static int og_resp_image_restore(json_t *data, struct og_client *cli)
{
struct og_software_legacy soft_legacy;
struct og_image_legacy img_legacy;
const char *partition = NULL;
const char *image_id = NULL;
struct og_computer computer;
const char *disk = NULL;
dbi_result query_result;
struct og_dbi *dbi;
const char *key;
json_t *value;
int err = 0;
bool res;
if (json_typeof(data) != JSON_OBJECT)
return -1;
json_object_foreach(data, key, value) {
if (!strcmp(key, "partition"))
err = og_json_parse_string(value, &partition);
else if (!strcmp(key, "disk"))
err = og_json_parse_string(value, &disk);
else if (!strcmp(key, "image_id"))
err = og_json_parse_string(value, &image_id);
else
return -1;
if (err < 0)
return err;
}
if (!partition || !disk || !image_id) {
syslog(LOG_ERR, "malformed response json\n");
return -1;
}
err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr);
if (err < 0)
return -1;
snprintf(img_legacy.image_id, sizeof(img_legacy.image_id), "%s",
image_id);
snprintf(img_legacy.part, sizeof(img_legacy.part), "%s", partition);
snprintf(img_legacy.disk, sizeof(img_legacy.disk), "%s", disk);
snprintf(soft_legacy.id, sizeof(soft_legacy.id), "%d", computer.id);
dbi = og_dbi_open(&dbi_config);
if (!dbi) {
syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
__func__, __LINE__);
return -1;
}
query_result = dbi_conn_queryf(dbi->conn,
"SELECT idperfilsoft FROM imagenes "
" WHERE idimagen='%s'",
image_id);
if (!query_result) {
og_dbi_close(dbi);
syslog(LOG_ERR, "failed to query database\n");
return -1;
}
if (!dbi_result_next_row(query_result)) {
dbi_result_free(query_result);
og_dbi_close(dbi);
syslog(LOG_ERR, "software profile does not exist in database\n");
return -1;
}
snprintf(img_legacy.software_id, sizeof(img_legacy.software_id),
"%d", dbi_result_get_uint(query_result, "idperfilsoft"));
dbi_result_free(query_result);
res = actualizaRestauracionImagen(dbi,
img_legacy.image_id,
img_legacy.disk,
img_legacy.part,
soft_legacy.id,
img_legacy.software_id);
og_dbi_close(dbi);
if (!res) {
syslog(LOG_ERR, "Problem updating client configuration\n");
return -1;
}
return 0;
}
static int og_agent_state_process_response(struct og_client *cli)
{
json_error_t json_err;
json_t *root;
int err = -1;
char *body;
if (strncmp(cli->buf, "HTTP/1.0 200 OK", strlen("HTTP/1.0 200 OK")))
return -1;
if (!cli->content_length)
return 0;
body = strstr(cli->buf, "\r\n\r\n") + 4;
root = json_loads(body, 0, &json_err);
if (!root) {
syslog(LOG_ERR, "%s:%d: malformed json line %d: %s\n",
__FILE__, __LINE__, json_err.line, json_err.text);
return -1;
}
if (!strncmp(cli->last_cmd, "probe", strlen("probe")))
err = og_resp_probe(cli, root);
else if (!strncmp(cli->last_cmd, "shell/run", strlen("shell/run")))
err = og_resp_shell_run(cli, root);
else if (!strncmp(cli->last_cmd, "hardware", strlen("hardware")))
err = og_resp_hardware(root, cli);
else if (!strncmp(cli->last_cmd, "software", strlen("software")))
err = og_resp_software(root, cli);
else if (!strncmp(cli->last_cmd, "refresh", strlen("refresh")))
err = og_resp_refresh(root, cli);
else if (!strncmp(cli->last_cmd, "setup", strlen("setup")))
err = og_resp_setup(cli);
else if (!strncmp(cli->last_cmd, "image/create", strlen("image/create")))
err = og_resp_image_create(root, cli);
else if (!strncmp(cli->last_cmd, "image/restore", strlen("image/restore")))
err = og_resp_image_restore(root, cli);
else
err = -1;
return err;
}
static void og_agent_read_cb(struct ev_loop *loop, struct ev_io *io, int events)
{
struct og_client *cli;
int ret;
cli = container_of(io, struct og_client, io);
ret = og_client_recv(cli, events);
if (ret <= 0)
goto close;
ev_timer_again(loop, &cli->timer);
cli->buf_len += ret;
if (cli->buf_len >= sizeof(cli->buf)) {
syslog(LOG_ERR, "client request from %s:%hu is too long\n",
inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
goto close;
}
switch (cli->state) {
case OG_AGENT_RECEIVING_HEADER:
ret = og_agent_state_recv_hdr_rest(cli);
if (ret < 0)
goto close;
if (!ret)
return;
cli->state = OG_AGENT_RECEIVING_PAYLOAD;
/* Fall through. */
case OG_AGENT_RECEIVING_PAYLOAD:
/* Still not enough data to process request. */
if (cli->buf_len < cli->msg_len)
return;
cli->state = OG_AGENT_PROCESSING_RESPONSE;
/* fall through. */
case OG_AGENT_PROCESSING_RESPONSE:
ret = og_agent_state_process_response(cli);
if (ret < 0) {
syslog(LOG_ERR, "Failed to process HTTP request from %s:%hu\n",
inet_ntoa(cli->addr.sin_addr),
ntohs(cli->addr.sin_port));
goto close;
}
syslog(LOG_DEBUG, "leaving client %s:%hu in keepalive mode\n",
inet_ntoa(cli->addr.sin_addr),
ntohs(cli->addr.sin_port));
og_agent_reset_state(cli);
break;
default:
syslog(LOG_ERR, "unknown state, critical internal error\n");
goto close;
}
return;
close:
ev_timer_stop(loop, &cli->timer);
og_client_release(loop, cli);
}
static void og_client_timer_cb(struct ev_loop *loop, ev_timer *timer, int events)
{
struct og_client *cli;
cli = container_of(timer, struct og_client, timer);
if (cli->keepalive_idx >= 0) {
ev_timer_again(loop, &cli->timer);
return;
}
syslog(LOG_ERR, "timeout request for client %s:%hu\n",
inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
og_client_release(loop, cli);
}
static void og_agent_send_probe(struct og_client *cli)
{
json_t *id, *name, *center, *room, *object;
struct og_msg_params params;
struct og_computer computer;
int err;
err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr);
if (err < 0)
return;
params.ips_array[0] = inet_ntoa(cli->addr.sin_addr);
params.ips_array_len = 1;
id = json_integer(computer.id);
center = json_integer(computer.center);
room = json_integer(computer.room);
name = json_string(computer.name);
object = json_object();
json_object_set_new(object, "id", id);
json_object_set_new(object, "name", name);
json_object_set_new(object, "center", center);
json_object_set_new(object, "room", room);
err = og_send_request("probe", OG_METHOD_POST, &params, object);
if (err < 0) {
syslog(LOG_ERR, "Can't send probe to: %s\n",
params.ips_array[0]);
} else {
syslog(LOG_INFO, "Sent probe to: %s\n",
params.ips_array[0]);
}
}
static int socket_s, socket_rest, socket_agent_rest;
static void og_server_accept_cb(struct ev_loop *loop, struct ev_io *io,
int events)
{
struct sockaddr_in client_addr;
socklen_t addrlen = sizeof(client_addr);
struct og_client *cli;
int client_sd;
if (events & EV_ERROR)
return;
client_sd = accept(io->fd, (struct sockaddr *)&client_addr, &addrlen);
if (client_sd < 0) {
syslog(LOG_ERR, "cannot accept client connection\n");
return;
}
cli = (struct og_client *)calloc(1, sizeof(struct og_client));
if (!cli) {
close(client_sd);
return;
}
memcpy(&cli->addr, &client_addr, sizeof(client_addr));
if (io->fd == socket_agent_rest)
cli->keepalive_idx = 0;
else
cli->keepalive_idx = -1;
if (io->fd == socket_rest)
cli->rest = true;
else if (io->fd == socket_agent_rest)
cli->agent = true;
syslog(LOG_DEBUG, "connection from client %s:%hu\n",
inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
if (io->fd == socket_agent_rest)
ev_io_init(&cli->io, og_agent_read_cb, client_sd, EV_READ);
else
ev_io_init(&cli->io, og_client_read_cb, client_sd, EV_READ);
ev_io_start(loop, &cli->io);
if (io->fd == socket_agent_rest) {
ev_timer_init(&cli->timer, og_client_timer_cb,
OG_AGENT_CLIENT_TIMEOUT, 0.);
} else {
ev_timer_init(&cli->timer, og_client_timer_cb,
OG_CLIENT_TIMEOUT, 0.);
}
ev_timer_start(loop, &cli->timer);
list_add(&cli->list, &client_list);
if (io->fd == socket_agent_rest)
og_agent_send_probe(cli);
}
static int og_socket_server_init(const char *port)
{
struct sockaddr_in local;
int sd, on = 1;
sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sd < 0) {
syslog(LOG_ERR, "cannot create main socket\n");
return -1;
}
setsockopt(sd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(int));
local.sin_addr.s_addr = htonl(INADDR_ANY);
local.sin_family = AF_INET;
local.sin_port = htons(atoi(port));
if (bind(sd, (struct sockaddr *) &local, sizeof(local)) < 0) {
close(sd);
syslog(LOG_ERR, "cannot bind socket\n");
return -1;
}
listen(sd, 250);
return sd;
}
int main(int argc, char *argv[])
{
struct ev_io ev_io_server, ev_io_server_rest, ev_io_agent_rest;
int i;
og_loop = ev_default_loop(0);
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
exit(EXIT_FAILURE);
openlog("ogAdmServer", LOG_PID, LOG_DAEMON);
/*--------------------------------------------------------------------------------------------------------
Validación de parámetros de ejecución y lectura del fichero de configuración del servicio
---------------------------------------------------------------------------------------------------------*/
if (!validacionParametros(argc, argv, 1)) // Valida parámetros de ejecución
exit(EXIT_FAILURE);
if (!tomaConfiguracion(szPathFileCfg)) { // Toma parametros de configuracion
exit(EXIT_FAILURE);
}
/*--------------------------------------------------------------------------------------------------------
// Inicializa array de información de los clientes
---------------------------------------------------------------------------------------------------------*/
for (i = 0; i < MAXIMOS_CLIENTES; i++) {
tbsockets[i].ip[0] = '\0';
tbsockets[i].cli = NULL;
}
/*--------------------------------------------------------------------------------------------------------
Creación y configuración del socket del servicio
---------------------------------------------------------------------------------------------------------*/
socket_s = og_socket_server_init(puerto);
if (socket_s < 0)
exit(EXIT_FAILURE);
ev_io_init(&ev_io_server, og_server_accept_cb, socket_s, EV_READ);
ev_io_start(og_loop, &ev_io_server);
socket_rest = og_socket_server_init("8888");
if (socket_rest < 0)
exit(EXIT_FAILURE);
ev_io_init(&ev_io_server_rest, og_server_accept_cb, socket_rest, EV_READ);
ev_io_start(og_loop, &ev_io_server_rest);
socket_agent_rest = og_socket_server_init("8889");
if (socket_agent_rest < 0)
exit(EXIT_FAILURE);
ev_io_init(&ev_io_agent_rest, og_server_accept_cb, socket_agent_rest, EV_READ);
ev_io_start(og_loop, &ev_io_agent_rest);
if (og_dbi_schedule_get() < 0)
exit(EXIT_FAILURE);
og_schedule_next(og_loop);
infoLog(1); // Inicio de sesión
/* old log file has been deprecated. */
og_log(97, false);
syslog(LOG_INFO, "Waiting for connections\n");
while (1)
ev_loop(og_loop, 0);
exit(EXIT_SUCCESS);
}