source: ogServer-Git/sources/ogAdmServer.c @ 83937b8

Last change on this file since 83937b8 was 04ca20e, checked in by OpenGnSys Support Team <soporte-og@…>, 4 years ago

#971 split into smaller file

Split ogAdmServer into several files:

  • sources/rest.c that implements the server REST API.
  • sources/client.c that implements the client REST API.
  • sources/json.c that provides a few JSON helpers.
  • Property mode set to 100644
File size: 54.6 KB
RevLine 
[6fc28cd]1// *******************************************************************************************************
[b9eb98b]2// Servicio: ogAdmServer
3// Autor: José Manuel Alonso (E.T.S.I.I.) Universidad de Sevilla
4// Fecha Creación: Marzo-2010
5// Fecha Última modificación: Marzo-2010
6// Nombre del fichero: ogAdmServer.cpp
7// Descripción :Este fichero implementa el servicio de administración general del sistema
[6fc28cd]8// *******************************************************************************************************
[b9eb98b]9#include "ogAdmServer.h"
[0fbdcf2]10#include "dbi.h"
[f4e7832]11#include "utils.h"
[96b9bb8]12#include "list.h"
[04ca20e]13#include "rest.h"
14#include "client.h"
15#include "json.h"
[83b242c]16#include "schedule.h"
[ef6e3d2]17#include <syslog.h>
[2baf362]18#include <sys/ioctl.h>
19#include <ifaddrs.h>
[c6020f2]20#include <sys/types.h>
21#include <sys/stat.h>
22#include <fcntl.h>
[95e6520]23#include <jansson.h>
[83b242c]24#include <time.h>
[2427e9d]25
26static char usuario[LONPRM]; // Usuario de acceso a la base de datos
27static char pasguor[LONPRM]; // Password del usuario
28static char datasource[LONPRM]; // Dirección IP del gestor de base de datos
29static char catalog[LONPRM]; // Nombre de la base de datos
[2baf362]30static char interface[LONPRM]; // Interface name
[04ca20e]31char auth_token[LONPRM]; // API token
[2427e9d]32
[04ca20e]33struct og_dbi_config dbi_config = {
[0fbdcf2]34        .user           = usuario,
35        .passwd         = pasguor,
36        .host           = datasource,
37        .database       = catalog,
38};
39
[b9eb98b]40//________________________________________________________________________________________________________
41//      Función: tomaConfiguracion
42//
43//      Descripción:
44//              Lee el fichero de configuración del servicio
45//      Parámetros:
46//              filecfg : Ruta completa al fichero de configuración
47//      Devuelve:
[9dea2d6]48//              true: Si el proceso es correcto
49//              false: En caso de ocurrir algún error
[b9eb98b]50//________________________________________________________________________________________________________
[59fb4d5]51static bool tomaConfiguracion(const char *filecfg)
52{
[20fa7b9]53        char buf[1024], *line;
54        char *key, *value;
55        FILE *fcfg;
[b9eb98b]56
57        if (filecfg == NULL || strlen(filecfg) == 0) {
[b56cbeb]58                syslog(LOG_ERR, "No configuration file has been specified\n");
[9dea2d6]59                return false;
[b9eb98b]60        }
61
62        fcfg = fopen(filecfg, "rt");
63        if (fcfg == NULL) {
[b56cbeb]64                syslog(LOG_ERR, "Cannot open configuration file `%s'\n",
65                       filecfg);
[9dea2d6]66                return false;
[b9eb98b]67        }
68
[3b5ec70]69        servidoradm[0] = '\0'; //inicializar variables globales
[b9eb98b]70
[20fa7b9]71        line = fgets(buf, sizeof(buf), fcfg);
72        while (line != NULL) {
73                const char *delim = "=";
74
75                line[strlen(line) - 1] = '\0';
76
77                key = strtok(line, delim);
78                value = strtok(NULL, delim);
79
[f4e7832]80                if (!strcmp(str_toupper(key), "SERVIDORADM"))
[20fa7b9]81                        snprintf(servidoradm, sizeof(servidoradm), "%s", value);
[f4e7832]82                else if (!strcmp(str_toupper(key), "PUERTO"))
[20fa7b9]83                        snprintf(puerto, sizeof(puerto), "%s", value);
[f4e7832]84                else if (!strcmp(str_toupper(key), "USUARIO"))
[20fa7b9]85                        snprintf(usuario, sizeof(usuario), "%s", value);
[f4e7832]86                else if (!strcmp(str_toupper(key), "PASSWORD"))
[20fa7b9]87                        snprintf(pasguor, sizeof(pasguor), "%s", value);
[f4e7832]88                else if (!strcmp(str_toupper(key), "DATASOURCE"))
[20fa7b9]89                        snprintf(datasource, sizeof(datasource), "%s", value);
[f4e7832]90                else if (!strcmp(str_toupper(key), "CATALOG"))
[20fa7b9]91                        snprintf(catalog, sizeof(catalog), "%s", value);
[f4e7832]92                else if (!strcmp(str_toupper(key), "INTERFACE"))
[2baf362]93                        snprintf(interface, sizeof(interface), "%s", value);
[f4e7832]94                else if (!strcmp(str_toupper(key), "APITOKEN"))
[fd30540]95                        snprintf(auth_token, sizeof(auth_token), "%s", value);
[20fa7b9]96
97                line = fgets(buf, sizeof(buf), fcfg);
[b9eb98b]98        }
[20fa7b9]99
[a927e14]100        fclose(fcfg);
101
[aff4cfd]102        if (!servidoradm[0]) {
[b56cbeb]103                syslog(LOG_ERR, "Missing SERVIDORADM in configuration file\n");
[9dea2d6]104                return false;
[b9eb98b]105        }
[aff4cfd]106        if (!puerto[0]) {
[b56cbeb]107                syslog(LOG_ERR, "Missing PUERTO in configuration file\n");
[9dea2d6]108                return false;
[b9eb98b]109        }
[aff4cfd]110        if (!usuario[0]) {
[b56cbeb]111                syslog(LOG_ERR, "Missing USUARIO in configuration file\n");
[9dea2d6]112                return false;
[b9eb98b]113        }
[aff4cfd]114        if (!pasguor[0]) {
[b56cbeb]115                syslog(LOG_ERR, "Missing PASSWORD in configuration file\n");
[9dea2d6]116                return false;
[b9eb98b]117        }
[aff4cfd]118        if (!datasource[0]) {
[b56cbeb]119                syslog(LOG_ERR, "Missing DATASOURCE in configuration file\n");
[9dea2d6]120                return false;
[b9eb98b]121        }
[aff4cfd]122        if (!catalog[0]) {
[b56cbeb]123                syslog(LOG_ERR, "Missing CATALOG in configuration file\n");
[9dea2d6]124                return false;
[b9eb98b]125        }
[2baf362]126        if (!interface[0])
127                syslog(LOG_ERR, "Missing INTERFACE in configuration file\n");
[eb99080]128
[9dea2d6]129        return true;
[b9eb98b]130}
[eb99080]131
[af30cc7]132#define OG_CMD_MAXLEN           64
[20dcb0a]133
[212280e]134/* Shut down connection if there is no complete message after 10 seconds. */
135#define OG_CLIENT_TIMEOUT       10
136
[af30cc7]137/* Agent client operation might take longer, shut down after 30 seconds. */
138#define OG_AGENT_CLIENT_TIMEOUT 30
139
[b9eb98b]140// ________________________________________________________________________________________________________
141// Función: clienteDisponible
142//
143//      Descripción:
144//              Comprueba la disponibilidad del cliente para recibir comandos interactivos
145//      Parametros:
146//              - ip : La ip del cliente a buscar
147//              - idx: (Salida)  Indice que ocupa el cliente, de estar ya registrado
148//      Devuelve:
[9dea2d6]149//              true: Si el cliente está disponible
150//              false: En caso contrario
[b9eb98b]151// ________________________________________________________________________________________________________
[59fb4d5]152bool clienteDisponible(char *ip, int* idx)
153{
[b9eb98b]154        int estado;
155
156        if (clienteExistente(ip, idx)) {
157                estado = strcmp(tbsockets[*idx].estado, CLIENTE_OCUPADO); // Cliente ocupado
158                if (estado == 0)
[9dea2d6]159                        return false;
[b9eb98b]160
161                estado = strcmp(tbsockets[*idx].estado, CLIENTE_APAGADO); // Cliente apagado
162                if (estado == 0)
[9dea2d6]163                        return false;
[b9eb98b]164
165                estado = strcmp(tbsockets[*idx].estado, CLIENTE_INICIANDO); // Cliente en proceso de inclusión
166                if (estado == 0)
[9dea2d6]167                        return false;
[b9eb98b]168
[9dea2d6]169                return true; // En caso contrario el cliente está disponible
[b9eb98b]170        }
[9dea2d6]171        return false; // Cliente no está registrado en el sistema
[b9eb98b]172}
173// ________________________________________________________________________________________________________
174// Función: clienteExistente
175//
176//      Descripción:
177//              Comprueba si el cliente está registrado en la tabla de socket del sistema
178//      Parametros:
179//              - ip : La ip del cliente a buscar
180//              - idx:(Salida)  Indice que ocupa el cliente, de estar ya registrado
181//      Devuelve:
[9dea2d6]182//              true: Si el cliente está registrado
183//              false: En caso contrario
[b9eb98b]184// ________________________________________________________________________________________________________
[59fb4d5]185bool clienteExistente(char *ip, int* idx)
186{
[b9eb98b]187        int i;
188        for (i = 0; i < MAXIMOS_CLIENTES; i++) {
189                if (contieneIP(ip, tbsockets[i].ip)) { // Si existe la IP en la cadena
190                        *idx = i;
[9dea2d6]191                        return true;
[b9eb98b]192                }
193        }
[9dea2d6]194        return false;
[b9eb98b]195}
196// ________________________________________________________________________________________________________
197// Función: actualizaConfiguracion
198//
199//      Descripción:
200//              Esta función actualiza la base de datos con la configuracion de particiones de un cliente
201//      Parámetros:
202//              - db: Objeto base de datos (ya operativo)
203//              - tbl: Objeto tabla
204//              - cfg: cadena con una Configuración
205//              - ido: Identificador del ordenador cliente
206//      Devuelve:
[9dea2d6]207//              true: Si el proceso es correcto
208//              false: En caso de ocurrir algún error
[b9eb98b]209//      Especificaciones:
210//              Los parametros de la configuración son:
211//                      par= Número de partición
212//                      cpt= Codigo o tipo de partición
213//                      sfi= Sistema de ficheros que está implementado en la partición
214//                      soi= Nombre del sistema de ficheros instalado en la partición
215//                      tam= Tamaño de la partición
216// ________________________________________________________________________________________________________
[fa6b891]217bool actualizaConfiguracion(struct og_dbi *dbi, char *cfg, int ido)
[b9eb98b]218{
[827bac5]219        int lon, p, c,i, dato, swu, idsoi, idsfi,k;
[3de93a9]220        char *ptrPar[MAXPAR], *ptrCfg[7], *ptrDual[2], tbPar[LONSTD];
[24df599]221        char *ser, *disk, *par, *cpt, *sfi, *soi, *tam, *uso; // Parametros de configuración.
[fa6b891]222        dbi_result result, result_update;
223        const char *msglog;
[b9eb98b]224
[9a2dc88]225        lon = 0;
[b9eb98b]226        p = splitCadena(ptrPar, cfg, '\n');
227        for (i = 0; i < p; i++) {
228                c = splitCadena(ptrCfg, ptrPar[i], '\t');
[24df599]229
230                // Si la 1ª línea solo incluye el número de serie del equipo; actualizar BD.
231                if (i == 0 && c == 1) {
232                        splitCadena(ptrDual, ptrCfg[0], '=');
233                        ser = ptrDual[1];
234                        if (strlen(ser) > 0) {
235                                // Solo actualizar si número de serie no existía.
[fa6b891]236                                result = dbi_conn_queryf(dbi->conn,
237                                                "UPDATE ordenadores SET numserie='%s'"
[b502279]238                                                " WHERE idordenador=%d AND numserie IS NULL",
[24df599]239                                                ser, ido);
[fa6b891]240                                if (!result) {
241                                        dbi_conn_error(dbi->conn, &msglog);
[bf8ba6c]242                                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
243                                               __func__, __LINE__, msglog);
[9dea2d6]244                                        return false;
[24df599]245                                }
[bf8ba6c]246                                dbi_result_free(result);
[24df599]247                        }
248                        continue;
249                }
250
251                // Distribución de particionado.
[c4b75b1]252                disk = par = cpt = sfi = soi = tam = uso = NULL;
[24df599]253
[b9eb98b]254                splitCadena(ptrDual, ptrCfg[0], '=');
[99f74d8]255                disk = ptrDual[1]; // Número de disco
[b9eb98b]256
257                splitCadena(ptrDual, ptrCfg[1], '=');
[99f74d8]258                par = ptrDual[1]; // Número de partición
259
[d1e9613]260                k=splitCadena(ptrDual, ptrCfg[2], '=');
261                if(k==2){
262                        cpt = ptrDual[1]; // Código de partición
263                }else{
[24df599]264                        cpt = (char*)"0";
[d1e9613]265                }
[b9eb98b]266
[99f74d8]267                k=splitCadena(ptrDual, ptrCfg[3], '=');
[b9eb98b]268                if(k==2){
269                        sfi = ptrDual[1]; // Sistema de ficheros
[eb99080]270                        /* Comprueba existencia del s0xistema de ficheros instalado */
[fa6b891]271                        idsfi = checkDato(dbi, sfi, "sistemasficheros", "descripcion","idsistemafichero");
[b9eb98b]272                }
273                else
274                        idsfi=0;
275
[99f74d8]276                k=splitCadena(ptrDual, ptrCfg[4], '=');
[b9eb98b]277                if(k==2){ // Sistema operativo detecdtado
278                        soi = ptrDual[1]; // Nombre del S.O. instalado
279                        /* Comprueba existencia del sistema operativo instalado */
[fa6b891]280                        idsoi = checkDato(dbi, soi, "nombresos", "nombreso", "idnombreso");
[b9eb98b]281                }
282                else
283                        idsoi=0;
284
[99f74d8]285                splitCadena(ptrDual, ptrCfg[5], '=');
[b9eb98b]286                tam = ptrDual[1]; // Tamaño de la partición
287
[c4b75b1]288                splitCadena(ptrDual, ptrCfg[6], '=');
289                uso = ptrDual[1]; // Porcentaje de uso del S.F.
290
[9a2dc88]291                lon += sprintf(tbPar + lon, "(%s, %s),", disk, par);
[b9eb98b]292
[fa6b891]293                result = dbi_conn_queryf(dbi->conn,
294                                "SELECT numdisk, numpar, tamano, uso, idsistemafichero, idnombreso"
[c4b75b1]295                                "  FROM ordenadores_particiones"
296                                " WHERE idordenador=%d AND numdisk=%s AND numpar=%s",
[99f74d8]297                                ido, disk, par);
[fa6b891]298                if (!result) {
299                        dbi_conn_error(dbi->conn, &msglog);
[b56cbeb]300                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
301                               __func__, __LINE__, msglog);
[9dea2d6]302                        return false;
[b9eb98b]303                }
[fa6b891]304                if (!dbi_result_next_row(result)) {
305                        result_update = dbi_conn_queryf(dbi->conn,
306                                        "INSERT INTO ordenadores_particiones(idordenador,numdisk,numpar,codpar,tamano,uso,idsistemafichero,idnombreso,idimagen)"
[c4b75b1]307                                        " VALUES(%d,%s,%s,0x%s,%s,%s,%d,%d,0)",
308                                        ido, disk, par, cpt, tam, uso, idsfi, idsoi);
[fa6b891]309                        if (!result_update) {
310                                dbi_conn_error(dbi->conn, &msglog);
[bf8ba6c]311                                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
312                                       __func__, __LINE__, msglog);
[9dea2d6]313                                return false;
[b9eb98b]314                        }
[fa6b891]315                        dbi_result_free(result_update);
316
[b9eb98b]317                } else { // Existe el registro
[9dea2d6]318                        swu = true; // Se supone que algún dato ha cambiado
[fa6b891]319
320                        dato = dbi_result_get_uint(result, "tamano");
321                        if (atoi(tam) == dato) {// Parámetro tamaño igual al almacenado
322                                dato = dbi_result_get_uint(result, "idsistemafichero");
323                                if (idsfi == dato) {// Parámetro sistema de fichero igual al almacenado
324                                        dato = dbi_result_get_uint(result, "idnombreso");
325                                        if (idsoi == dato) {// Parámetro sistema de fichero distinto al almacenado
[1845104]326                                                swu = false; // Todos los parámetros de la partición son iguales, no se actualiza
[b9eb98b]327                                        }
328                                }
329                        }
330                        if (swu) { // Hay que actualizar los parámetros de la partición
[fa6b891]331                                result_update = dbi_conn_queryf(dbi->conn,
332                                        "UPDATE ordenadores_particiones SET "
[b9eb98b]333                                        " codpar=0x%s,"
334                                        " tamano=%s,"
[c4b75b1]335                                        " uso=%s,"
[b9eb98b]336                                        " idsistemafichero=%d,"
337                                        " idnombreso=%d,"
[599c505]338                                        " idimagen=0,"
339                                        " idperfilsoft=0,"
340                                        " fechadespliegue=NULL"
[99f74d8]341                                        " WHERE idordenador=%d AND numdisk=%s AND numpar=%s",
[c4b75b1]342                                        cpt, tam, uso, idsfi, idsoi, ido, disk, par);
[d56675d]343                        } else {  // Actualizar porcentaje de uso.
[fa6b891]344                                result_update = dbi_conn_queryf(dbi->conn,
345                                        "UPDATE ordenadores_particiones SET "
[696c5bb]346                                        " codpar=0x%s,"
[d56675d]347                                        " uso=%s"
348                                        " WHERE idordenador=%d AND numdisk=%s AND numpar=%s",
[696c5bb]349                                        cpt, uso, ido, disk, par);
[d56675d]350                        }
[fa6b891]351                        if (!result_update) {
352                                dbi_conn_error(dbi->conn, &msglog);
[b56cbeb]353                                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
354                                       __func__, __LINE__, msglog);
[9dea2d6]355                                return false;
[b9eb98b]356                        }
[fa6b891]357
358                        dbi_result_free(result_update);
[b9eb98b]359                }
[bf8ba6c]360                dbi_result_free(result);
[b9eb98b]361        }
[9a2dc88]362        lon += sprintf(tbPar + lon, "(0,0)");
[b9eb98b]363        // Eliminar particiones almacenadas que ya no existen
[fa6b891]364        result_update = dbi_conn_queryf(dbi->conn,
365                "DELETE FROM ordenadores_particiones WHERE idordenador=%d AND (numdisk, numpar) NOT IN (%s)",
[9a2dc88]366                        ido, tbPar);
[fa6b891]367        if (!result_update) {
368                dbi_conn_error(dbi->conn, &msglog);
[b56cbeb]369                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
370                       __func__, __LINE__, msglog);
[9dea2d6]371                return false;
[b9eb98b]372        }
[fa6b891]373        dbi_result_free(result_update);
374
[9dea2d6]375        return true;
[b9eb98b]376}
377// ________________________________________________________________________________________________________
378// Función: checkDato
379//
380//      Descripción:
381//               Esta función comprueba si existe un dato en una tabla y si no es así lo incluye. devuelve en
382//              cualquier caso el identificador del registro existenet o del insertado
383//      Parámetros:
384//              - db: Objeto base de datos (ya operativo)
385//              - tbl: Objeto tabla
386//              - dato: Dato
387//              - tabla: Nombre de la tabla
388//              - nomdato: Nombre del dato en la tabla
389//              - nomidentificador: Nombre del identificador en la tabla
390//      Devuelve:
391//              El identificador del registro existente o el del insertado
392//
393//      Especificaciones:
394//              En caso de producirse algún error se devuelve el valor 0
395// ________________________________________________________________________________________________________
396
[fa6b891]397int checkDato(struct og_dbi *dbi, char *dato, const char *tabla,
[59fb4d5]398                     const char *nomdato, const char *nomidentificador)
399{
[fa6b891]400        const char *msglog;
[b9eb98b]401        int identificador;
[fa6b891]402        dbi_result result;
[b9eb98b]403
404        if (strlen(dato) == 0)
405                return (0); // EL dato no tiene valor
[fa6b891]406        result = dbi_conn_queryf(dbi->conn,
407                        "SELECT %s FROM %s WHERE %s ='%s'", nomidentificador,
[b9eb98b]408                        tabla, nomdato, dato);
409
410        // Ejecuta consulta
[fa6b891]411        if (!result) {
412                dbi_conn_error(dbi->conn, &msglog);
[b56cbeb]413                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
414                       __func__, __LINE__, msglog);
[b9eb98b]415                return (0);
416        }
[fa6b891]417        if (!dbi_result_next_row(result)) { //  Software NO existente
418                dbi_result_free(result);
419
420                result = dbi_conn_queryf(dbi->conn,
421                                "INSERT INTO %s (%s) VALUES('%s')", tabla, nomdato, dato);
422                if (!result) {
423                        dbi_conn_error(dbi->conn, &msglog);
[9c8a139]424                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
425                               __func__, __LINE__, msglog);
[b9eb98b]426                        return (0);
427                }
428                // Recupera el identificador del software
[fa6b891]429                identificador = dbi_conn_sequence_last(dbi->conn, NULL);
[b9eb98b]430        } else {
[fa6b891]431                identificador = dbi_result_get_uint(result, nomidentificador);
[b9eb98b]432        }
[fa6b891]433        dbi_result_free(result);
434
[b9eb98b]435        return (identificador);
436}
[96b9bb8]437
[b9eb98b]438// ________________________________________________________________________________________________________
439// Función: Levanta
440//
441//      Descripción:
442//              Enciende ordenadores a través de la red cuyas macs se pasan como parámetro
443//      Parámetros:
[0cee7a6]444//              - iph: Cadena de direcciones ip separadas por ";"
[b9eb98b]445//              - mac: Cadena de direcciones mac separadas por ";"
[0cee7a6]446//              - mar: Método de arranque (1=Broadcast, 2=Unicast)
[b9eb98b]447//      Devuelve:
[9dea2d6]448//              true: Si el proceso es correcto
449//              false: En caso de ocurrir algún error
[b9eb98b]450// ________________________________________________________________________________________________________
[507c75c]451
452bool Levanta(char *ptrIP[], char *ptrMacs[], int lon, char *mar)
[0cee7a6]453{
[63a3d4d]454        unsigned int on = 1;
[3b5ec70]455        struct sockaddr_in local;
[507c75c]456        int i, res;
[b38ed0d]457        int s;
[b9eb98b]458
459        /* Creación de socket para envío de magig packet */
460        s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
[28b435c]461        if (s < 0) {
[b56cbeb]462                syslog(LOG_ERR, "cannot create socket for magic packet\n");
[9dea2d6]463                return false;
[b9eb98b]464        }
[63a3d4d]465        res = setsockopt(s, SOL_SOCKET, SO_BROADCAST, (unsigned int *) &on,
466                         sizeof(on));
[28b435c]467        if (res < 0) {
[b56cbeb]468                syslog(LOG_ERR, "cannot set broadcast socket\n");
[9dea2d6]469                return false;
[b9eb98b]470        }
[63a3d4d]471        memset(&local, 0, sizeof(local));
[b9eb98b]472        local.sin_family = AF_INET;
[63a3d4d]473        local.sin_port = htons(PUERTO_WAKEUP);
474        local.sin_addr.s_addr = htonl(INADDR_ANY);
475
[b9eb98b]476        for (i = 0; i < lon; i++) {
[b38ed0d]477                if (!WakeUp(s, ptrIP[i], ptrMacs[i], mar)) {
[b56cbeb]478                        syslog(LOG_ERR, "problem sending magic packet\n");
[b9eb98b]479                        close(s);
[9dea2d6]480                        return false;
[b9eb98b]481                }
482        }
483        close(s);
[9dea2d6]484        return true;
[b9eb98b]485}
[2baf362]486
487#define OG_WOL_SEQUENCE         6
488#define OG_WOL_MACADDR_LEN      6
489#define OG_WOL_REPEAT           16
490
491struct wol_msg {
492        char secuencia_FF[OG_WOL_SEQUENCE];
493        char macbin[OG_WOL_REPEAT][OG_WOL_MACADDR_LEN];
494};
495
496static bool wake_up_broadcast(int sd, struct sockaddr_in *client,
497                              const struct wol_msg *msg)
498{
499        struct sockaddr_in *broadcast_addr;
500        struct ifaddrs *ifaddr, *ifa;
501        int ret;
502
503        if (getifaddrs(&ifaddr) < 0) {
504                syslog(LOG_ERR, "cannot get list of addresses\n");
505                return false;
506        }
507
508        client->sin_addr.s_addr = htonl(INADDR_BROADCAST);
509
510        for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
511                if (ifa->ifa_addr == NULL ||
512                    ifa->ifa_addr->sa_family != AF_INET ||
513                    strcmp(ifa->ifa_name, interface) != 0)
514                        continue;
515
516                broadcast_addr =
517                        (struct sockaddr_in *)ifa->ifa_ifu.ifu_broadaddr;
518                client->sin_addr.s_addr = broadcast_addr->sin_addr.s_addr;
519                break;
520        }
[8322fd6]521        freeifaddrs(ifaddr);
[2baf362]522
523        ret = sendto(sd, msg, sizeof(*msg), 0,
[3b5ec70]524                     (struct sockaddr *)client, sizeof(*client));
[2baf362]525        if (ret < 0) {
526                syslog(LOG_ERR, "failed to send broadcast wol\n");
527                return false;
528        }
529
530        return true;
531}
532
533static bool wake_up_unicast(int sd, struct sockaddr_in *client,
534                            const struct wol_msg *msg,
535                            const struct in_addr *addr)
536{
537        int ret;
538
539        client->sin_addr.s_addr = addr->s_addr;
540
541        ret = sendto(sd, msg, sizeof(*msg), 0,
[3b5ec70]542                     (struct sockaddr *)client, sizeof(*client));
[2baf362]543        if (ret < 0) {
544                syslog(LOG_ERR, "failed to send unicast wol\n");
545                return false;
546        }
547
548        return true;
549}
550
551enum wol_delivery_type {
552        OG_WOL_BROADCAST = 1,
553        OG_WOL_UNICAST = 2
554};
555
[b9eb98b]556//_____________________________________________________________________________________________________________
557// Función: WakeUp
558//
559//       Descripción:
560//              Enciende el ordenador cuya MAC se pasa como parámetro
561//      Parámetros:
562//              - s : Socket para enviar trama magic packet
[0cee7a6]563//              - iph : Cadena con la dirección ip
[b9eb98b]564//              - mac : Cadena con la dirección mac en formato XXXXXXXXXXXX
[0cee7a6]565//              - mar: Método de arranque (1=Broadcast, 2=Unicast)
[b9eb98b]566//      Devuelve:
[9dea2d6]567//              true: Si el proceso es correcto
568//              false: En caso de ocurrir algún error
[b9eb98b]569//_____________________________________________________________________________________________________________
[0cee7a6]570//
[b38ed0d]571bool WakeUp(int s, char* iph, char *mac, char *mar)
[0cee7a6]572{
[429bd36]573        unsigned int macaddr[OG_WOL_MACADDR_LEN];
[2baf362]574        char HDaddress_bin[OG_WOL_MACADDR_LEN];
575        struct sockaddr_in WakeUpCliente;
576        struct wol_msg Trama_WakeUp;
577        struct in_addr addr;
578        bool ret;
579        int i;
[b9eb98b]580
581        for (i = 0; i < 6; i++) // Primera secuencia de la trama Wake Up (0xFFFFFFFFFFFF)
582                Trama_WakeUp.secuencia_FF[i] = 0xFF;
583
[63a3d4d]584        sscanf(mac, "%02x%02x%02x%02x%02x%02x",
[429bd36]585               &macaddr[0], &macaddr[1], &macaddr[2],
586               &macaddr[3], &macaddr[4], &macaddr[5]);
587
588        for (i = 0; i < 6; i++)
589                HDaddress_bin[i] = (uint8_t)macaddr[i];
[b9eb98b]590
591        for (i = 0; i < 16; i++) // Segunda secuencia de la trama Wake Up , repetir 16 veces su la MAC
592                memcpy(&Trama_WakeUp.macbin[i][0], &HDaddress_bin, 6);
593
594        /* Creación de socket del cliente que recibe la trama magic packet */
595        WakeUpCliente.sin_family = AF_INET;
596        WakeUpCliente.sin_port = htons((short) PUERTO_WAKEUP);
597
[2baf362]598        switch (atoi(mar)) {
599        case OG_WOL_BROADCAST:
[b38ed0d]600                ret = wake_up_broadcast(s, &WakeUpCliente, &Trama_WakeUp);
[2baf362]601                break;
602        case OG_WOL_UNICAST:
603                if (inet_aton(iph, &addr) < 0) {
604                        syslog(LOG_ERR, "bad IP address for unicast wol\n");
605                        ret = false;
606                        break;
607                }
[b38ed0d]608                ret = wake_up_unicast(s, &WakeUpCliente, &Trama_WakeUp, &addr);
[2baf362]609                break;
610        default:
611                syslog(LOG_ERR, "unknown wol type\n");
612                ret = false;
613                break;
614        }
615        return ret;
[b9eb98b]616}
617
618// ________________________________________________________________________________________________________
619// Función: actualizaCreacionImagen
620//
621//      Descripción:
622//              Esta función actualiza la base de datos con el resultado de la creación de una imagen
623//      Parámetros:
624//              - db: Objeto base de datos (ya operativo)
625//              - tbl: Objeto tabla
626//              - idi: Identificador de la imagen
[599c505]627//              - dsk: Disco de donde se creó
[b9eb98b]628//              - par: Partición de donde se creó
629//              - cpt: Código de partición
630//              - ipr: Ip del repositorio
631//              - ido: Identificador del ordenador modelo
632//      Devuelve:
[9dea2d6]633//              true: Si el proceso es correcto
634//              false: En caso de ocurrir algún error
[b9eb98b]635// ________________________________________________________________________________________________________
[9cc156c]636bool actualizaCreacionImagen(struct og_dbi *dbi, char *idi, char *dsk,
[59fb4d5]637                             char *par, char *cpt, char *ipr, char *ido)
638{
[9cc156c]639        const char *msglog;
640        dbi_result result;
[ed05cd5]641        int idr,ifs;
[b9eb98b]642
[80d1dfd]643        /* Toma identificador del repositorio correspondiente al ordenador modelo */
[9cc156c]644        result = dbi_conn_queryf(dbi->conn,
[599c505]645                        "SELECT repositorios.idrepositorio"
[80d1dfd]646                        "  FROM repositorios"
647                        "  LEFT JOIN ordenadores USING (idrepositorio)"
648                        " WHERE repositorios.ip='%s' AND ordenadores.idordenador=%s", ipr, ido);
[b9eb98b]649
[9cc156c]650        if (!result) {
651                dbi_conn_error(dbi->conn, &msglog);
[b56cbeb]652                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
653                       __func__, __LINE__, msglog);
[9dea2d6]654                return false;
[b9eb98b]655        }
[9cc156c]656        if (!dbi_result_next_row(result)) {
657                syslog(LOG_ERR,
658                       "repository does not exist in database (%s:%d)\n",
659                       __func__, __LINE__);
660                dbi_result_free(result);
[9dea2d6]661                return false;
[b9eb98b]662        }
[9cc156c]663        idr = dbi_result_get_uint(result, "idrepositorio");
664        dbi_result_free(result);
[b9eb98b]665
666        /* Toma identificador del perfilsoftware */
[9cc156c]667        result = dbi_conn_queryf(dbi->conn,
[599c505]668                        "SELECT idperfilsoft"
669                        "  FROM ordenadores_particiones"
670                        " WHERE idordenador=%s AND numdisk=%s AND numpar=%s", ido, dsk, par);
[b9eb98b]671
[9cc156c]672        if (!result) {
673                dbi_conn_error(dbi->conn, &msglog);
[b56cbeb]674                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
675                       __func__, __LINE__, msglog);
[9dea2d6]676                return false;
[b9eb98b]677        }
[9cc156c]678        if (!dbi_result_next_row(result)) {
679                syslog(LOG_ERR,
680                       "software profile does not exist in database (%s:%d)\n",
681                       __func__, __LINE__);
682                dbi_result_free(result);
[9dea2d6]683                return false;
[b9eb98b]684        }
[9cc156c]685        ifs = dbi_result_get_uint(result, "idperfilsoft");
686        dbi_result_free(result);
[b9eb98b]687
688        /* Actualizar los datos de la imagen */
[9cc156c]689        result = dbi_conn_queryf(dbi->conn,
[faee12e]690                "UPDATE imagenes"
691                "   SET idordenador=%s, numdisk=%s, numpar=%s, codpar=%s,"
692                "       idperfilsoft=%d, idrepositorio=%d,"
693                "       fechacreacion=NOW(), revision=revision+1"
694                " WHERE idimagen=%s", ido, dsk, par, cpt, ifs, idr, idi);
[b9eb98b]695
[9cc156c]696        if (!result) {
697                dbi_conn_error(dbi->conn, &msglog);
[b56cbeb]698                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
699                       __func__, __LINE__, msglog);
[9dea2d6]700                return false;
[b9eb98b]701        }
[9cc156c]702        dbi_result_free(result);
703
[faee12e]704        /* Actualizar los datos en el cliente */
[9cc156c]705        result = dbi_conn_queryf(dbi->conn,
[faee12e]706                "UPDATE ordenadores_particiones"
[ed05cd5]707                "   SET idimagen=%s, revision=(SELECT revision FROM imagenes WHERE idimagen=%s),"
708                "       fechadespliegue=NOW()"
[faee12e]709                " WHERE idordenador=%s AND numdisk=%s AND numpar=%s",
[ed05cd5]710                idi, idi, ido, dsk, par);
[9cc156c]711        if (!result) {
712                dbi_conn_error(dbi->conn, &msglog);
[b56cbeb]713                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
714                       __func__, __LINE__, msglog);
[9dea2d6]715                return false;
[faee12e]716        }
[e81d230]717        dbi_result_free(result);
[b9eb98b]718
[e81d230]719        return true;
[eb99080]720}
[e81d230]721
[eb99080]722// ________________________________________________________________________________________________________
[b9eb98b]723// Función: actualizaRestauracionImagen
724//
725//      Descripción:
[eb99080]726//              Esta función actualiza la base de datos con el resultado de la restauración de una imagen
[b9eb98b]727//      Parámetros:
728//              - db: Objeto base de datos (ya operativo)
729//              - tbl: Objeto tabla
730//              - idi: Identificador de la imagen
[599c505]731//              - dsk: Disco de donde se restauró
[b9eb98b]732//              - par: Partición de donde se restauró
733//              - ido: Identificador del cliente donde se restauró
734//              - ifs: Identificador del perfil software contenido      en la imagen
735//      Devuelve:
[9dea2d6]736//              true: Si el proceso es correcto
737//              false: En caso de ocurrir algún error
[b9eb98b]738// ________________________________________________________________________________________________________
[fa6b891]739bool actualizaRestauracionImagen(struct og_dbi *dbi, char *idi,
[59fb4d5]740                                 char *dsk, char *par, char *ido, char *ifs)
741{
[fa6b891]742        const char *msglog;
743        dbi_result result;
[b9eb98b]744
745        /* Actualizar los datos de la imagen */
[fa6b891]746        result = dbi_conn_queryf(dbi->conn,
[599c505]747                        "UPDATE ordenadores_particiones"
[60bbc25]748                        "   SET idimagen=%s, idperfilsoft=%s, fechadespliegue=NOW(),"
[9e3c02a]749                        "       revision=(SELECT revision FROM imagenes WHERE idimagen=%s),"
750                        "       idnombreso=IFNULL((SELECT idnombreso FROM perfilessoft WHERE idperfilsoft=%s),0)"
[c20cf9c]751                        " WHERE idordenador=%s AND numdisk=%s AND numpar=%s", idi, ifs, idi, ifs, ido, dsk, par);
[b9eb98b]752
[fa6b891]753        if (!result) {
754                dbi_conn_error(dbi->conn, &msglog);
[b56cbeb]755                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
756                       __func__, __LINE__, msglog);
[9dea2d6]757                return false;
[b9eb98b]758        }
[fa6b891]759        dbi_result_free(result);
760
[9dea2d6]761        return true;
[b9eb98b]762}
763// ________________________________________________________________________________________________________
764// Función: actualizaHardware
765//
766//              Descripción:
767//                      Actualiza la base de datos con la configuracion hardware del cliente
768//              Parámetros:
769//                      - db: Objeto base de datos (ya operativo)
770//                      - tbl: Objeto tabla
771//                      - hrd: cadena con el inventario hardware
772//                      - ido: Identificador del ordenador
773//                      - npc: Nombre del ordenador
774//                      - idc: Identificador del centro o Unidad organizativa
775// ________________________________________________________________________________________________________
[eb99080]776//
[03f1941]777bool actualizaHardware(struct og_dbi *dbi, char *hrd, char *ido, char *npc,
[59fb4d5]778                       char *idc)
[eb99080]779{
[03f1941]780        const char *msglog;
[b9eb98b]781        int idtipohardware, idperfilhard;
782        int lon, i, j, aux;
[7f46c45]783        bool retval;
[eb99080]784        char *whard;
[b9eb98b]785        int tbidhardware[MAXHARDWARE];
[03f1941]786        char *tbHardware[MAXHARDWARE],*dualHardware[2], strInt[LONINT], *idhardwares;
787        dbi_result result;
[b9eb98b]788
789        /* Toma Centro (Unidad Organizativa) */
[03f1941]790        result = dbi_conn_queryf(dbi->conn,
791                                 "SELECT idperfilhard FROM ordenadores WHERE idordenador=%s",
792                                 ido);
793        if (!result) {
794                dbi_conn_error(dbi->conn, &msglog);
[b56cbeb]795                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
796                       __func__, __LINE__, msglog);
[9dea2d6]797                return false;
[b9eb98b]798        }
[03f1941]799        if (!dbi_result_next_row(result)) {
800                syslog(LOG_ERR, "client does not exist in database (%s:%d)\n",
801                       __func__, __LINE__);
802                dbi_result_free(result);
[9dea2d6]803                return false;
[b9eb98b]804        }
[03f1941]805        idperfilhard = dbi_result_get_uint(result, "idperfilhard");
806        dbi_result_free(result);
807
[eb99080]808        whard=escaparCadena(hrd); // Codificar comillas simples
809        if(!whard)
[9dea2d6]810                return false;
[b9eb98b]811        /* Recorre componentes hardware*/
[eb99080]812        lon = splitCadena(tbHardware, whard, '\n');
[b9eb98b]813        if (lon > MAXHARDWARE)
814                lon = MAXHARDWARE; // Limita el número de componentes hardware
815        /*
816         for (i=0;i<lon;i++){
817         sprintf(msglog,"Linea de inventario: %s",tbHardware[i]);
[9dea2d6]818         RegistraLog(msglog,false);
[b9eb98b]819         }
820         */
821        for (i = 0; i < lon; i++) {
822                splitCadena(dualHardware, rTrim(tbHardware[i]), '=');
823                //sprintf(msglog,"nemonico: %s",dualHardware[0]);
[9dea2d6]824                //RegistraLog(msglog,false);
[b9eb98b]825                //sprintf(msglog,"valor: %s",dualHardware[1]);
[9dea2d6]826                //RegistraLog(msglog,false);
[03f1941]827                result = dbi_conn_queryf(dbi->conn,
828                                         "SELECT idtipohardware,descripcion FROM tipohardwares WHERE nemonico='%s'",
829                                         dualHardware[0]);
830                if (!result) {
831                        dbi_conn_error(dbi->conn, &msglog);
[b56cbeb]832                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
833                               __func__, __LINE__, msglog);
[9dea2d6]834                        return false;
[b9eb98b]835                }
[03f1941]836                if (!dbi_result_next_row(result)) { //  Tipo de Hardware NO existente
837                        dbi_result_free(result);
[9dea2d6]838                        return false;
[b9eb98b]839                } else { //  Tipo de Hardware Existe
[03f1941]840                        idtipohardware = dbi_result_get_uint(result, "idtipohardware");
841                        dbi_result_free(result);
[b9eb98b]842
[03f1941]843                        result = dbi_conn_queryf(dbi->conn,
844                                                 "SELECT idhardware FROM hardwares WHERE idtipohardware=%d AND descripcion='%s'",
845                                                 idtipohardware, dualHardware[1]);
[b9eb98b]846
[03f1941]847                        if (!result) {
848                                dbi_conn_error(dbi->conn, &msglog);
[b56cbeb]849                                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
850                                       __func__, __LINE__, msglog);
[9dea2d6]851                                return false;
[b9eb98b]852                        }
853
[03f1941]854                        if (!dbi_result_next_row(result)) { //  Hardware NO existente
855                                dbi_result_free(result);
856                                result = dbi_conn_queryf(dbi->conn,
857                                                        "INSERT hardwares (idtipohardware,descripcion,idcentro,grupoid) "
[b9eb98b]858                                                        " VALUES(%d,'%s',%s,0)", idtipohardware,
859                                                dualHardware[1], idc);
[03f1941]860                                if (!result) {
861                                        dbi_conn_error(dbi->conn, &msglog);
[b56cbeb]862                                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
863                                               __func__, __LINE__, msglog);
[9dea2d6]864                                        return false;
[b9eb98b]865                                }
[03f1941]866
867                                // Recupera el identificador del hardware
868                                tbidhardware[i] = dbi_conn_sequence_last(dbi->conn, NULL);
[b9eb98b]869                        } else {
[03f1941]870                                tbidhardware[i] = dbi_result_get_uint(result, "idhardware");
[b9eb98b]871                        }
[03f1941]872                        dbi_result_free(result);
[b9eb98b]873                }
874        }
875        // Ordena tabla de identificadores para cosultar si existe un pefil con esas especificaciones
876
877        for (i = 0; i < lon - 1; i++) {
878                for (j = i + 1; j < lon; j++) {
879                        if (tbidhardware[i] > tbidhardware[j]) {
880                                aux = tbidhardware[i];
881                                tbidhardware[i] = tbidhardware[j];
882                                tbidhardware[j] = aux;
883                        }
884                }
885        }
886        /* Crea cadena de identificadores de componentes hardware separados por coma */
887        sprintf(strInt, "%d", tbidhardware[lon - 1]); // Pasa a cadena el último identificador que es de mayor longitud
888        aux = strlen(strInt); // Calcula longitud de cadena para reservar espacio a todos los perfiles
[eba3c79]889        idhardwares = calloc(1, sizeof(aux) * lon + lon);
[b9eb98b]890        if (idhardwares == NULL) {
[b56cbeb]891                syslog(LOG_ERR, "%s:%d OOM\n", __FILE__, __LINE__);
[9dea2d6]892                return false;
[b9eb98b]893        }
894        aux = sprintf(idhardwares, "%d", tbidhardware[0]);
895        for (i = 1; i < lon; i++)
896                aux += sprintf(idhardwares + aux, ",%d", tbidhardware[i]);
897
[03f1941]898        if (!cuestionPerfilHardware(dbi, idc, ido, idperfilhard, idhardwares,
[b9eb98b]899                        npc, tbidhardware, lon)) {
[b56cbeb]900                syslog(LOG_ERR, "Problem updating client hardware\n");
[9dea2d6]901                retval=false;
[01586d6]902        } else {
[9dea2d6]903                retval=true;
[7f46c45]904        }
[01586d6]905        free(whard);
906        free(idhardwares);
907
[7f46c45]908        return (retval);
[b9eb98b]909}
910// ________________________________________________________________________________________________________
911// Función: cuestionPerfilHardware
912//
913//              Descripción:
914//                      Comprueba existencia de perfil hardware y actualización de éste para el ordenador
915//              Parámetros:
916//                      - db: Objeto base de datos (ya operativo)
917//                      - tbl: Objeto tabla
918//                      - idc: Identificador de la Unidad organizativa donde se encuentra el cliente
919//                      - ido: Identificador del ordenador
920//                      - tbidhardware: Identificador del tipo de hardware
921//                      - con: Número de componentes detectados para configurar un el perfil hardware
922//                      - npc: Nombre del cliente
923// ________________________________________________________________________________________________________
[03f1941]924bool cuestionPerfilHardware(struct og_dbi *dbi, char *idc, char *ido,
[59fb4d5]925                int idperfilhardware, char *idhardwares, char *npc, int *tbidhardware,
[b9eb98b]926                int lon)
927{
[03f1941]928        const char *msglog;
929        dbi_result result;
[b9eb98b]930        int i;
931        int nwidperfilhard;
932
933        // Busca perfil hard del ordenador que contenga todos los componentes hardware encontrados
[03f1941]934        result = dbi_conn_queryf(dbi->conn,
935                "SELECT idperfilhard FROM"
[b9eb98b]936                " (SELECT perfileshard_hardwares.idperfilhard as idperfilhard,"
937                "       group_concat(cast(perfileshard_hardwares.idhardware AS char( 11) )"
938                "       ORDER BY perfileshard_hardwares.idhardware SEPARATOR ',' ) AS idhardwares"
939                " FROM  perfileshard_hardwares"
940                " GROUP BY perfileshard_hardwares.idperfilhard) AS temp"
941                " WHERE idhardwares LIKE '%s'", idhardwares);
[b56cbeb]942
[03f1941]943        if (!result) {
944                dbi_conn_error(dbi->conn, &msglog);
[b56cbeb]945                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
946                       __func__, __LINE__, msglog);
[9dea2d6]947                return false;
[b9eb98b]948        }
[03f1941]949        if (!dbi_result_next_row(result)) {
950                // No existe un perfil hardware con esos componentes de componentes hardware, lo crea
951                dbi_result_free(result);
952                result = dbi_conn_queryf(dbi->conn,
953                                "INSERT perfileshard  (descripcion,idcentro,grupoid)"
[bde1389]954                                " VALUES('Perfil hardware (%s) ',%s,0)", npc, idc);
[03f1941]955                if (!result) {
956                        dbi_conn_error(dbi->conn, &msglog);
957                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
958                               __func__, __LINE__, msglog);
[9dea2d6]959                        return false;
[b9eb98b]960                }
[03f1941]961                dbi_result_free(result);
962
[b9eb98b]963                // Recupera el identificador del nuevo perfil hardware
[03f1941]964                nwidperfilhard = dbi_conn_sequence_last(dbi->conn, NULL);
965
[b9eb98b]966                // Crea la relación entre perfiles y componenetes hardware
967                for (i = 0; i < lon; i++) {
[03f1941]968                        result = dbi_conn_queryf(dbi->conn,
969                                        "INSERT perfileshard_hardwares  (idperfilhard,idhardware)"
[b9eb98b]970                                                " VALUES(%d,%d)", nwidperfilhard, tbidhardware[i]);
[03f1941]971                        if (!result) {
972                                dbi_conn_error(dbi->conn, &msglog);
973                                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
974                                       __func__, __LINE__, msglog);
[9dea2d6]975                                return false;
[b9eb98b]976                        }
[03f1941]977                        dbi_result_free(result);
[b9eb98b]978                }
979        } else { // Existe un perfil con todos esos componentes
[03f1941]980                nwidperfilhard = dbi_result_get_uint(result, "idperfilhard");
981                dbi_result_free(result);
[b9eb98b]982        }
983        if (idperfilhardware != nwidperfilhard) { // No coinciden los perfiles
984                // Actualiza el identificador del perfil hardware del ordenador
[03f1941]985                result = dbi_conn_queryf(dbi->conn,
986                        "UPDATE ordenadores SET idperfilhard=%d"
[b9eb98b]987                        " WHERE idordenador=%s", nwidperfilhard, ido);
[03f1941]988                if (!result) {
989                        dbi_conn_error(dbi->conn, &msglog);
990                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
991                               __func__, __LINE__, msglog);
[9dea2d6]992                        return false;
[b9eb98b]993                }
[03f1941]994                dbi_result_free(result);
[b9eb98b]995        }
996        /* Eliminar Relación de hardwares con Perfiles hardware que quedan húerfanos */
[03f1941]997        result = dbi_conn_queryf(dbi->conn,
998                "DELETE FROM perfileshard_hardwares WHERE idperfilhard IN "
[b9eb98b]999                " (SELECT idperfilhard FROM perfileshard WHERE idperfilhard NOT IN"
1000                " (SELECT DISTINCT idperfilhard from ordenadores))");
[03f1941]1001        if (!result) {
1002                dbi_conn_error(dbi->conn, &msglog);
1003                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1004                       __func__, __LINE__, msglog);
[9dea2d6]1005                return false;
[b9eb98b]1006        }
[03f1941]1007        dbi_result_free(result);
[b9eb98b]1008
1009        /* Eliminar Perfiles hardware que quedan húerfanos */
[03f1941]1010        result = dbi_conn_queryf(dbi->conn,
1011                        "DELETE FROM perfileshard WHERE idperfilhard NOT IN"
[7f46c45]1012                        " (SELECT DISTINCT idperfilhard FROM ordenadores)");
[03f1941]1013        if (!result) {
1014                dbi_conn_error(dbi->conn, &msglog);
1015                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1016                       __func__, __LINE__, msglog);
[9dea2d6]1017                return false;
[b9eb98b]1018        }
[03f1941]1019        dbi_result_free(result);
1020
[b9eb98b]1021        /* Eliminar Relación de hardwares con Perfiles hardware que quedan húerfanos */
[03f1941]1022        result = dbi_conn_queryf(dbi->conn,
1023                        "DELETE FROM perfileshard_hardwares WHERE idperfilhard NOT IN"
[7f46c45]1024                        " (SELECT idperfilhard FROM perfileshard)");
[03f1941]1025        if (!result) {
1026                dbi_conn_error(dbi->conn, &msglog);
1027                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1028                       __func__, __LINE__, msglog);
[9dea2d6]1029                return false;
[b9eb98b]1030        }
[03f1941]1031        dbi_result_free(result);
1032
[9dea2d6]1033        return true;
[b9eb98b]1034}
1035// ________________________________________________________________________________________________________
1036// Función: actualizaSoftware
1037//
1038//      Descripción:
1039//              Actualiza la base de datos con la configuración software del cliente
1040//      Parámetros:
1041//              - db: Objeto base de datos (ya operativo)
1042//              - tbl: Objeto tabla
1043//              - sft: cadena con el inventario software
1044//              - par: Número de la partición
1045//              - ido: Identificador del ordenador del cliente en la tabla
1046//              - npc: Nombre del ordenador
1047//              - idc: Identificador del centro o Unidad organizativa
1048//      Devuelve:
[9dea2d6]1049//              true: Si el proceso es correcto
1050//              false: En caso de ocurrir algún error
[8712fd9]1051//
1052//      Versión 1.1.0: Se incluye el sistema operativo. Autora: Irina Gómez - ETSII Universidad Sevilla
[b9eb98b]1053// ________________________________________________________________________________________________________
[fa6b891]1054bool actualizaSoftware(struct og_dbi *dbi, char *sft, char *par,char *ido,
[59fb4d5]1055                       char *npc, char *idc)
[eb99080]1056{
[8712fd9]1057        int i, j, lon, aux, idperfilsoft, idnombreso;
[7f46c45]1058        bool retval;
[eb99080]1059        char *wsft;
[b9eb98b]1060        int tbidsoftware[MAXSOFTWARE];
[fa6b891]1061        char *tbSoftware[MAXSOFTWARE], strInt[LONINT], *idsoftwares;
1062        const char *msglog;
1063        dbi_result result;
[b9eb98b]1064
1065        /* Toma Centro (Unidad Organizativa) y perfil software */
[fa6b891]1066        result = dbi_conn_queryf(dbi->conn,
1067                "SELECT idperfilsoft,numpar"
[b9eb98b]1068                " FROM ordenadores_particiones"
1069                " WHERE idordenador=%s", ido);
[fa6b891]1070        if (!result) {
1071                dbi_conn_error(dbi->conn, &msglog);
[b56cbeb]1072                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1073                       __func__, __LINE__, msglog);
[9dea2d6]1074                return false;
[b9eb98b]1075        }
1076        idperfilsoft = 0; // Por defecto se supone que el ordenador no tiene aún detectado el perfil software
[fa6b891]1077        while (dbi_result_next_row(result)) {
1078                aux = dbi_result_get_uint(result, "numpar");
[b9eb98b]1079                if (aux == atoi(par)) { // Se encuentra la partición
[fa6b891]1080                        idperfilsoft = dbi_result_get_uint(result, "idperfilsoft");
[b9eb98b]1081                        break;
1082                }
1083        }
[fa6b891]1084        dbi_result_free(result);
[eb99080]1085        wsft=escaparCadena(sft); // Codificar comillas simples
1086        if(!wsft)
[9dea2d6]1087                return false;
[b9eb98b]1088
1089        /* Recorre componentes software*/
[eb99080]1090        lon = splitCadena(tbSoftware, wsft, '\n');
1091
[b9eb98b]1092        if (lon == 0)
[9dea2d6]1093                return true; // No hay lineas que procesar
[b9eb98b]1094        if (lon > MAXSOFTWARE)
1095                lon = MAXSOFTWARE; // Limita el número de componentes software
1096
[1c0eaf2]1097        idnombreso = 0;
[b9eb98b]1098        for (i = 0; i < lon; i++) {
[8712fd9]1099                // Primera línea es el sistema operativo: se obtiene identificador
1100                if (i == 0) {
[fa6b891]1101                        idnombreso = checkDato(dbi, rTrim(tbSoftware[i]), "nombresos", "nombreso", "idnombreso");
[8712fd9]1102                        continue;
1103                }
1104
[fa6b891]1105                result = dbi_conn_queryf(dbi->conn,
[b9eb98b]1106                                "SELECT idsoftware FROM softwares WHERE descripcion ='%s'",
1107                                rTrim(tbSoftware[i]));
[fa6b891]1108                if (!result) {
1109                        dbi_conn_error(dbi->conn, &msglog);
[b56cbeb]1110                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1111                               __func__, __LINE__, msglog);
[9dea2d6]1112                        return false;
[b9eb98b]1113                }
1114
[fa6b891]1115                if (!dbi_result_next_row(result)) {
1116                        dbi_result_free(result);
1117                        result = dbi_conn_queryf(dbi->conn,
1118                                                "INSERT INTO softwares (idtiposoftware,descripcion,idcentro,grupoid)"
[b9eb98b]1119                                                " VALUES(2,'%s',%s,0)", tbSoftware[i], idc);
[fa6b891]1120                        if (!result) { // Error al insertar
1121                                dbi_conn_error(dbi->conn, &msglog);
[26736ed]1122                                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1123                                       __func__, __LINE__, msglog);
[9dea2d6]1124                                return false;
[b9eb98b]1125                        }
[fa6b891]1126
[b9eb98b]1127                        // Recupera el identificador del software
[fa6b891]1128                        tbidsoftware[i] = dbi_conn_sequence_last(dbi->conn, NULL);
[b9eb98b]1129                } else {
[fa6b891]1130                        tbidsoftware[i] = dbi_result_get_uint(result, "idsoftware");
[b9eb98b]1131                }
[26736ed]1132                dbi_result_free(result);
[b9eb98b]1133        }
1134
1135        // Ordena tabla de identificadores para cosultar si existe un pefil con esas especificaciones
1136
1137        for (i = 0; i < lon - 1; i++) {
1138                for (j = i + 1; j < lon; j++) {
1139                        if (tbidsoftware[i] > tbidsoftware[j]) {
1140                                aux = tbidsoftware[i];
1141                                tbidsoftware[i] = tbidsoftware[j];
1142                                tbidsoftware[j] = aux;
1143                        }
1144                }
1145        }
1146        /* Crea cadena de identificadores de componentes software separados por coma */
1147        sprintf(strInt, "%d", tbidsoftware[lon - 1]); // Pasa a cadena el último identificador que es de mayor longitud
1148        aux = strlen(strInt); // Calcula longitud de cadena para reservar espacio a todos los perfiles
[eba3c79]1149        idsoftwares = calloc(1, (sizeof(aux)+1) * lon + lon);
[b9eb98b]1150        if (idsoftwares == NULL) {
[b56cbeb]1151                syslog(LOG_ERR, "%s:%d OOM\n", __FILE__, __LINE__);
[9dea2d6]1152                return false;
[b9eb98b]1153        }
1154        aux = sprintf(idsoftwares, "%d", tbidsoftware[0]);
1155        for (i = 1; i < lon; i++)
1156                aux += sprintf(idsoftwares + aux, ",%d", tbidsoftware[i]);
1157
1158        // Comprueba existencia de perfil software y actualización de éste para el ordenador
[fa6b891]1159        if (!cuestionPerfilSoftware(dbi, idc, ido, idperfilsoft, idnombreso, idsoftwares,
[b9eb98b]1160                        npc, par, tbidsoftware, lon)) {
[9c8a139]1161                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1162                       __func__, __LINE__, msglog);
[9dea2d6]1163                retval=false;
[01586d6]1164        } else {
[9dea2d6]1165                retval=true;
[7f46c45]1166        }
[01586d6]1167        free(wsft);
1168        free(idsoftwares);
1169
1170        return retval;
[b9eb98b]1171}
1172// ________________________________________________________________________________________________________
1173// Función: CuestionPerfilSoftware
1174//
1175//      Parámetros:
1176//              - db: Objeto base de datos (ya operativo)
1177//              - tbl: Objeto tabla
1178//              - idcentro: Identificador del centro en la tabla
1179//              - ido: Identificador del ordenador del cliente en la tabla
[8712fd9]1180//              - idnombreso: Identificador del sistema operativo
[b9eb98b]1181//              - idsoftwares: Cadena con los identificadores de componentes software separados por comas
1182//              - npc: Nombre del ordenador del cliente
1183//              - particion: Número de la partición
1184//              - tbidsoftware: Array con los identificadores de componentes software
1185//              - lon: Número de componentes
1186//      Devuelve:
[9dea2d6]1187//              true: Si el proceso es correcto
1188//              false: En caso de ocurrir algún error
[8712fd9]1189//
1190//      Versión 1.1.0: Se incluye el sistema operativo. Autora: Irina Gómez - ETSII Universidad Sevilla
1191//_________________________________________________________________________________________________________
[fa6b891]1192bool cuestionPerfilSoftware(struct og_dbi *dbi, char *idc, char *ido,
[59fb4d5]1193                            int idperfilsoftware, int idnombreso,
1194                            char *idsoftwares, char *npc, char *par,
1195                            int *tbidsoftware, int lon)
1196{
[b9eb98b]1197        int i, nwidperfilsoft;
[fa6b891]1198        const char *msglog;
1199        dbi_result result;
[b9eb98b]1200
1201        // Busca perfil soft del ordenador que contenga todos los componentes software encontrados
[fa6b891]1202        result = dbi_conn_queryf(dbi->conn,
1203                "SELECT idperfilsoft FROM"
[b9eb98b]1204                " (SELECT perfilessoft_softwares.idperfilsoft as idperfilsoft,"
1205                "       group_concat(cast(perfilessoft_softwares.idsoftware AS char( 11) )"
1206                "       ORDER BY perfilessoft_softwares.idsoftware SEPARATOR ',' ) AS idsoftwares"
1207                " FROM  perfilessoft_softwares"
1208                " GROUP BY perfilessoft_softwares.idperfilsoft) AS temp"
1209                " WHERE idsoftwares LIKE '%s'", idsoftwares);
[b56cbeb]1210
[fa6b891]1211        if (!result) {
1212                dbi_conn_error(dbi->conn, &msglog);
[b56cbeb]1213                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1214                       __func__, __LINE__, msglog);
[9dea2d6]1215                return false;
[b9eb98b]1216        }
[fa6b891]1217        if (!dbi_result_next_row(result)) { // No existe un perfil software con esos componentes de componentes software, lo crea
1218                dbi_result_free(result);
1219                result = dbi_conn_queryf(dbi->conn,
1220                                "INSERT perfilessoft  (descripcion, idcentro, grupoid, idnombreso)"
[8712fd9]1221                                " VALUES('Perfil Software (%s, Part:%s) ',%s,0,%i)", npc, par, idc,idnombreso);
[fa6b891]1222                if (!result) {
1223                        dbi_conn_error(dbi->conn, &msglog);
[9c8a139]1224                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1225                               __func__, __LINE__, msglog);
[9dea2d6]1226                        return false;
[b9eb98b]1227                }
[fa6b891]1228
1229                dbi_result_free(result);
[b9eb98b]1230                // Recupera el identificador del nuevo perfil software
[fa6b891]1231                nwidperfilsoft = dbi_conn_sequence_last(dbi->conn, NULL);
1232
[b9eb98b]1233                // Crea la relación entre perfiles y componenetes software
1234                for (i = 0; i < lon; i++) {
[fa6b891]1235                        result = dbi_conn_queryf(dbi->conn,
1236                                                "INSERT perfilessoft_softwares (idperfilsoft,idsoftware)"
[b9eb98b]1237                                                " VALUES(%d,%d)", nwidperfilsoft, tbidsoftware[i]);
[fa6b891]1238                        if (!result) {
1239                                dbi_conn_error(dbi->conn, &msglog);
[9c8a139]1240                                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1241                                       __func__, __LINE__, msglog);
[9dea2d6]1242                                return false;
[b9eb98b]1243                        }
[fa6b891]1244                        dbi_result_free(result);
[b9eb98b]1245                }
1246        } else { // Existe un perfil con todos esos componentes
[fa6b891]1247                nwidperfilsoft = dbi_result_get_uint(result, "idperfilsoft");
1248                dbi_result_free(result);
[b9eb98b]1249        }
1250
1251        if (idperfilsoftware != nwidperfilsoft) { // No coinciden los perfiles
1252                // Actualiza el identificador del perfil software del ordenador
[fa6b891]1253                result = dbi_conn_queryf(dbi->conn,
1254                                "UPDATE ordenadores_particiones SET idperfilsoft=%d,idimagen=0"
[7f46c45]1255                                " WHERE idordenador=%s AND numpar=%s", nwidperfilsoft, ido, par);
[fa6b891]1256                if (!result) { // Error al insertar
1257                        dbi_conn_error(dbi->conn, &msglog);
[9c8a139]1258                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1259                               __func__, __LINE__, msglog);
[9dea2d6]1260                        return false;
[b9eb98b]1261                }
[fa6b891]1262                dbi_result_free(result);
[b9eb98b]1263        }
1264
1265        /* DEPURACIÓN DE PERFILES SOFTWARE */
1266
1267         /* Eliminar Relación de softwares con Perfiles software que quedan húerfanos */
[fa6b891]1268        result = dbi_conn_queryf(dbi->conn,
1269                "DELETE FROM perfilessoft_softwares WHERE idperfilsoft IN "\
[b9eb98b]1270                " (SELECT idperfilsoft FROM perfilessoft WHERE idperfilsoft NOT IN"\
1271                " (SELECT DISTINCT idperfilsoft from ordenadores_particiones) AND idperfilsoft NOT IN"\
1272                " (SELECT DISTINCT idperfilsoft from imagenes))");
[fa6b891]1273        if (!result) {
1274                dbi_conn_error(dbi->conn, &msglog);
[9c8a139]1275                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1276                       __func__, __LINE__, msglog);
[9dea2d6]1277                return false;
[b9eb98b]1278        }
[fa6b891]1279        dbi_result_free(result),
[b9eb98b]1280        /* Eliminar Perfiles software que quedan húerfanos */
[fa6b891]1281        result = dbi_conn_queryf(dbi->conn,
1282                "DELETE FROM perfilessoft WHERE idperfilsoft NOT IN"
[b9eb98b]1283                " (SELECT DISTINCT idperfilsoft from ordenadores_particiones)"\
1284                " AND  idperfilsoft NOT IN"\
1285                " (SELECT DISTINCT idperfilsoft from imagenes)");
[fa6b891]1286        if (!result) {
1287                dbi_conn_error(dbi->conn, &msglog);
[9c8a139]1288                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1289                       __func__, __LINE__, msglog);
[9dea2d6]1290                return false;
[b9eb98b]1291        }
[fa6b891]1292        dbi_result_free(result),
1293
[b9eb98b]1294        /* Eliminar Relación de softwares con Perfiles software que quedan húerfanos */
[fa6b891]1295        result = dbi_conn_queryf(dbi->conn,
1296                        "DELETE FROM perfilessoft_softwares WHERE idperfilsoft NOT IN"
[7f46c45]1297                        " (SELECT idperfilsoft from perfilessoft)");
[fa6b891]1298        if (!result) {
1299                dbi_conn_error(dbi->conn, &msglog);
[9c8a139]1300                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1301                       __func__, __LINE__, msglog);
[9dea2d6]1302                return false;
[b9eb98b]1303        }
[fa6b891]1304        dbi_result_free(result);
1305
[9dea2d6]1306        return true;
[b9eb98b]1307}
[212280e]1308
[f09aca6]1309static void og_client_release(struct ev_loop *loop, struct og_client *cli)
1310{
1311        if (cli->keepalive_idx >= 0) {
[2ed3a0c]1312                syslog(LOG_DEBUG, "closing keepalive connection for %s:%hu in slot %d\n",
[f09aca6]1313                       inet_ntoa(cli->addr.sin_addr),
1314                       ntohs(cli->addr.sin_port), cli->keepalive_idx);
1315                tbsockets[cli->keepalive_idx].cli = NULL;
1316        }
1317
[af30cc7]1318        list_del(&cli->list);
[f09aca6]1319        ev_io_stop(loop, &cli->io);
1320        close(cli->io.fd);
1321        free(cli);
1322}
1323
1324static void og_client_keepalive(struct ev_loop *loop, struct og_client *cli)
1325{
1326        struct og_client *old_cli;
1327
1328        old_cli = tbsockets[cli->keepalive_idx].cli;
1329        if (old_cli && old_cli != cli) {
[2ed3a0c]1330                syslog(LOG_DEBUG, "closing old keepalive connection for %s:%hu\n",
[f09aca6]1331                       inet_ntoa(old_cli->addr.sin_addr),
1332                       ntohs(old_cli->addr.sin_port));
1333
1334                og_client_release(loop, old_cli);
1335        }
1336        tbsockets[cli->keepalive_idx].cli = cli;
1337}
1338
1339static void og_client_reset_state(struct og_client *cli)
1340{
1341        cli->state = OG_CLIENT_RECEIVING_HEADER;
1342        cli->buf_len = 0;
1343}
1344
[04ca20e]1345static int og_client_payload_too_large(struct og_client *cli)
[d491dfd]1346{
[04ca20e]1347        char buf[] = "HTTP/1.1 413 Payload Too Large\r\n"
1348                     "Content-Length: 0\r\n\r\n";
[107b17a]1349
[04ca20e]1350        send(og_client_socket(cli), buf, strlen(buf), 0);
[107b17a]1351
[04ca20e]1352        return -1;
[2226378]1353}
[107b17a]1354
[04ca20e]1355static int og_client_state_recv_hdr_rest(struct og_client *cli)
[2226378]1356{
[04ca20e]1357        char *ptr;
[881f532]1358
[04ca20e]1359        ptr = strstr(cli->buf, "\r\n\r\n");
1360        if (!ptr)
1361                return 0;
[01e77f4]1362
[04ca20e]1363        cli->msg_len = ptr - cli->buf + 4;
[95e6520]1364
[04ca20e]1365        ptr = strstr(cli->buf, "Content-Length: ");
1366        if (ptr) {
1367                sscanf(ptr, "Content-Length: %i[^\r\n]", &cli->content_length);
1368                if (cli->content_length < 0)
1369                        return -1;
1370                cli->msg_len += cli->content_length;
1371        }
[af30cc7]1372
[04ca20e]1373        ptr = strstr(cli->buf, "Authorization: ");
1374        if (ptr)
1375                sscanf(ptr, "Authorization: %63[^\r\n]", cli->auth_token);
[af30cc7]1376
[04ca20e]1377        return 1;
1378}
[af30cc7]1379
[04ca20e]1380static int og_client_recv(struct og_client *cli, int events)
[af30cc7]1381{
[04ca20e]1382        struct ev_io *io = &cli->io;
1383        int ret;
[af30cc7]1384
[04ca20e]1385        if (events & EV_ERROR) {
1386                syslog(LOG_ERR, "unexpected error event from client %s:%hu\n",
1387                               inet_ntoa(cli->addr.sin_addr),
1388                               ntohs(cli->addr.sin_port));
1389                return 0;
[af30cc7]1390        }
1391
[04ca20e]1392        ret = recv(io->fd, cli->buf + cli->buf_len,
1393                   sizeof(cli->buf) - cli->buf_len, 0);
1394        if (ret <= 0) {
1395                if (ret < 0) {
1396                        syslog(LOG_ERR, "error reading from client %s:%hu (%s)\n",
1397                               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port),
1398                               strerror(errno));
1399                } else {
1400                        syslog(LOG_DEBUG, "closed connection by %s:%hu\n",
1401                               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
[af30cc7]1402                }
[04ca20e]1403                return ret;
[af30cc7]1404        }
1405
[04ca20e]1406        return ret;
[af30cc7]1407}
1408
[04ca20e]1409static void og_client_read_cb(struct ev_loop *loop, struct ev_io *io, int events)
[54ecdbb]1410{
[04ca20e]1411        struct og_client *cli;
1412        int ret;
[54ecdbb]1413
[04ca20e]1414        cli = container_of(io, struct og_client, io);
[95e6520]1415
[04ca20e]1416        ret = og_client_recv(cli, events);
1417        if (ret <= 0)
1418                goto close;
[95e6520]1419
[04ca20e]1420        if (cli->keepalive_idx >= 0)
1421                return;
[95e6520]1422
[04ca20e]1423        ev_timer_again(loop, &cli->timer);
[54ecdbb]1424
[04ca20e]1425        cli->buf_len += ret;
1426        if (cli->buf_len >= sizeof(cli->buf)) {
1427                syslog(LOG_ERR, "client request from %s:%hu is too long\n",
1428                       inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
1429                og_client_payload_too_large(cli);
1430                goto close;
[280df58]1431        }
[54ecdbb]1432
[04ca20e]1433        switch (cli->state) {
1434        case OG_CLIENT_RECEIVING_HEADER:
1435                ret = og_client_state_recv_hdr_rest(cli);
1436                if (ret < 0)
1437                        goto close;
1438                if (!ret)
1439                        return;
[ffd2965]1440
[04ca20e]1441                cli->state = OG_CLIENT_RECEIVING_PAYLOAD;
1442                /* Fall through. */
1443        case OG_CLIENT_RECEIVING_PAYLOAD:
1444                /* Still not enough data to process request. */
1445                if (cli->buf_len < cli->msg_len)
1446                        return;
[ffd2965]1447
[04ca20e]1448                cli->state = OG_CLIENT_PROCESSING_REQUEST;
1449                /* fall through. */
1450        case OG_CLIENT_PROCESSING_REQUEST:
1451                ret = og_client_state_process_payload_rest(cli);
1452                if (ret < 0) {
1453                        syslog(LOG_ERR, "Failed to process HTTP request from %s:%hu\n",
1454                               inet_ntoa(cli->addr.sin_addr),
1455                               ntohs(cli->addr.sin_port));
[82a1d5a]1456                }
[04ca20e]1457                if (ret < 0)
1458                        goto close;
[01e77f4]1459
[04ca20e]1460                if (cli->keepalive_idx < 0) {
1461                        syslog(LOG_DEBUG, "server closing connection to %s:%hu\n",
1462                               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
1463                        goto close;
1464                } else {
1465                        syslog(LOG_DEBUG, "leaving client %s:%hu in keepalive mode\n",
1466                               inet_ntoa(cli->addr.sin_addr),
1467                               ntohs(cli->addr.sin_port));
1468                        og_client_keepalive(loop, cli);
1469                        og_client_reset_state(cli);
[3bc3b45]1470                }
[04ca20e]1471                break;
1472        default:
1473                syslog(LOG_ERR, "unknown state, critical internal error\n");
1474                goto close;
[e3af7ee]1475        }
[04ca20e]1476        return;
1477close:
1478        ev_timer_stop(loop, &cli->timer);
1479        og_client_release(loop, cli);
[dbcc83d]1480}
1481
[04ca20e]1482enum og_agent_state {
1483        OG_AGENT_RECEIVING_HEADER       = 0,
1484        OG_AGENT_RECEIVING_PAYLOAD,
1485        OG_AGENT_PROCESSING_RESPONSE,
1486};
[dbcc83d]1487
[04ca20e]1488static int og_agent_state_recv_hdr_rest(struct og_client *cli)
1489{
1490        char *ptr;
[dbcc83d]1491
[04ca20e]1492        ptr = strstr(cli->buf, "\r\n\r\n");
1493        if (!ptr)
1494                return 0;
[dbcc83d]1495
[04ca20e]1496        cli->msg_len = ptr - cli->buf + 4;
[dbcc83d]1497
[04ca20e]1498        ptr = strstr(cli->buf, "Content-Length: ");
1499        if (ptr) {
1500                sscanf(ptr, "Content-Length: %i[^\r\n]", &cli->content_length);
1501                if (cli->content_length < 0)
[e3af7ee]1502                        return -1;
[04ca20e]1503                cli->msg_len += cli->content_length;
[83b242c]1504        }
1505
[04ca20e]1506        return 1;
[83b242c]1507}
1508
[04ca20e]1509static void og_agent_reset_state(struct og_client *cli)
[54c7ca3]1510{
[04ca20e]1511        cli->state = OG_AGENT_RECEIVING_HEADER;
1512        cli->buf_len = 0;
1513        cli->content_length = 0;
1514        memset(cli->buf, 0, sizeof(cli->buf));
[54c7ca3]1515}
1516
[04ca20e]1517static void og_agent_deliver_pending_cmd(struct og_client *cli)
[54c7ca3]1518{
[04ca20e]1519        const struct og_cmd *cmd;
[54c7ca3]1520
[04ca20e]1521        cmd = og_cmd_find(inet_ntoa(cli->addr.sin_addr));
1522        if (!cmd)
1523                return;
[54c7ca3]1524
[04ca20e]1525        og_send_request(cmd->method, cmd->type, &cmd->params, cmd->json);
1526        cli->last_cmd_id = cmd->id;
[54c7ca3]1527
[04ca20e]1528        og_cmd_free(cmd);
[54c7ca3]1529}
1530
[04ca20e]1531static void og_agent_read_cb(struct ev_loop *loop, struct ev_io *io, int events)
[95e6520]1532{
[04ca20e]1533        struct og_client *cli;
1534        int ret;
[95e6520]1535
[04ca20e]1536        cli = container_of(io, struct og_client, io);
1537
1538        ret = og_client_recv(cli, events);
1539        if (ret <= 0)
1540                goto close;
[95e6520]1541
[04ca20e]1542        ev_timer_again(loop, &cli->timer);
[95e6520]1543
[04ca20e]1544        cli->buf_len += ret;
1545        if (cli->buf_len >= sizeof(cli->buf)) {
1546                syslog(LOG_ERR, "client request from %s:%hu is too long\n",
1547                       inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
1548                goto close;
[95e6520]1549        }
1550
[04ca20e]1551        switch (cli->state) {
1552        case OG_AGENT_RECEIVING_HEADER:
1553                ret = og_agent_state_recv_hdr_rest(cli);
1554                if (ret < 0)
1555                        goto close;
1556                if (!ret)
1557                        return;
[af30cc7]1558
1559                cli->state = OG_AGENT_RECEIVING_PAYLOAD;
1560                /* Fall through. */
1561        case OG_AGENT_RECEIVING_PAYLOAD:
1562                /* Still not enough data to process request. */
1563                if (cli->buf_len < cli->msg_len)
1564                        return;
1565
1566                cli->state = OG_AGENT_PROCESSING_RESPONSE;
1567                /* fall through. */
1568        case OG_AGENT_PROCESSING_RESPONSE:
1569                ret = og_agent_state_process_response(cli);
1570                if (ret < 0) {
1571                        syslog(LOG_ERR, "Failed to process HTTP request from %s:%hu\n",
1572                               inet_ntoa(cli->addr.sin_addr),
1573                               ntohs(cli->addr.sin_port));
1574                        goto close;
[b31e7dd]1575                } else if (ret == 0) {
1576                        og_agent_deliver_pending_cmd(cli);
[af30cc7]1577                }
[54c7ca3]1578
[af30cc7]1579                syslog(LOG_DEBUG, "leaving client %s:%hu in keepalive mode\n",
1580                       inet_ntoa(cli->addr.sin_addr),
1581                       ntohs(cli->addr.sin_port));
1582                og_agent_reset_state(cli);
1583                break;
1584        default:
1585                syslog(LOG_ERR, "unknown state, critical internal error\n");
1586                goto close;
1587        }
1588        return;
1589close:
1590        ev_timer_stop(loop, &cli->timer);
1591        og_client_release(loop, cli);
1592}
1593
1594static void og_client_timer_cb(struct ev_loop *loop, ev_timer *timer, int events)
1595{
1596        struct og_client *cli;
1597
1598        cli = container_of(timer, struct og_client, timer);
1599        if (cli->keepalive_idx >= 0) {
1600                ev_timer_again(loop, &cli->timer);
1601                return;
1602        }
1603        syslog(LOG_ERR, "timeout request for client %s:%hu\n",
1604               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
1605
1606        og_client_release(loop, cli);
1607}
1608
[87be2ce]1609static void og_agent_send_refresh(struct og_client *cli)
[af30cc7]1610{
1611        struct og_msg_params params;
1612        int err;
1613
1614        params.ips_array[0] = inet_ntoa(cli->addr.sin_addr);
1615        params.ips_array_len = 1;
1616
[87be2ce]1617        err = og_send_request(OG_METHOD_GET, OG_CMD_REFRESH, &params, NULL);
[af30cc7]1618        if (err < 0) {
[87be2ce]1619                syslog(LOG_ERR, "Can't send refresh to: %s\n",
[af30cc7]1620                       params.ips_array[0]);
1621        } else {
[87be2ce]1622                syslog(LOG_INFO, "Sent refresh to: %s\n",
[af30cc7]1623                       params.ips_array[0]);
1624        }
1625}
1626
[e81d230]1627static int socket_rest, socket_agent_rest;
[af30cc7]1628
1629static void og_server_accept_cb(struct ev_loop *loop, struct ev_io *io,
1630                                int events)
1631{
1632        struct sockaddr_in client_addr;
1633        socklen_t addrlen = sizeof(client_addr);
1634        struct og_client *cli;
1635        int client_sd;
1636
1637        if (events & EV_ERROR)
1638                return;
1639
1640        client_sd = accept(io->fd, (struct sockaddr *)&client_addr, &addrlen);
1641        if (client_sd < 0) {
1642                syslog(LOG_ERR, "cannot accept client connection\n");
1643                return;
1644        }
1645
1646        cli = (struct og_client *)calloc(1, sizeof(struct og_client));
1647        if (!cli) {
1648                close(client_sd);
1649                return;
1650        }
1651        memcpy(&cli->addr, &client_addr, sizeof(client_addr));
1652        if (io->fd == socket_agent_rest)
1653                cli->keepalive_idx = 0;
1654        else
1655                cli->keepalive_idx = -1;
1656
1657        if (io->fd == socket_rest)
1658                cli->rest = true;
1659        else if (io->fd == socket_agent_rest)
1660                cli->agent = true;
1661
1662        syslog(LOG_DEBUG, "connection from client %s:%hu\n",
1663               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
1664
1665        if (io->fd == socket_agent_rest)
1666                ev_io_init(&cli->io, og_agent_read_cb, client_sd, EV_READ);
1667        else
1668                ev_io_init(&cli->io, og_client_read_cb, client_sd, EV_READ);
1669
1670        ev_io_start(loop, &cli->io);
1671        if (io->fd == socket_agent_rest) {
1672                ev_timer_init(&cli->timer, og_client_timer_cb,
1673                              OG_AGENT_CLIENT_TIMEOUT, 0.);
1674        } else {
1675                ev_timer_init(&cli->timer, og_client_timer_cb,
1676                              OG_CLIENT_TIMEOUT, 0.);
1677        }
1678        ev_timer_start(loop, &cli->timer);
[04ca20e]1679        og_client_add(cli);
[af30cc7]1680
[87be2ce]1681        if (io->fd == socket_agent_rest) {
1682                og_agent_send_refresh(cli);
1683        }
[af30cc7]1684}
1685
1686static int og_socket_server_init(const char *port)
1687{
1688        struct sockaddr_in local;
1689        int sd, on = 1;
[e3e4e6f]1690
1691        sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1692        if (sd < 0) {
1693                syslog(LOG_ERR, "cannot create main socket\n");
1694                return -1;
1695        }
1696        setsockopt(sd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(int));
1697
1698        local.sin_addr.s_addr = htonl(INADDR_ANY);
1699        local.sin_family = AF_INET;
1700        local.sin_port = htons(atoi(port));
1701
1702        if (bind(sd, (struct sockaddr *) &local, sizeof(local)) < 0) {
[8b1bedd]1703                close(sd);
[e3e4e6f]1704                syslog(LOG_ERR, "cannot bind socket\n");
1705                return -1;
1706        }
1707
1708        listen(sd, 250);
1709
1710        return sd;
1711}
1712
[04ca20e]1713struct ev_loop *og_loop;
1714
[212280e]1715int main(int argc, char *argv[])
1716{
[e81d230]1717        struct ev_io ev_io_server_rest, ev_io_agent_rest;
[212280e]1718        int i;
[b9eb98b]1719
[83b242c]1720        og_loop = ev_default_loop(0);
1721
[9fc0037]1722        if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
1723                exit(EXIT_FAILURE);
1724
[57c8c50]1725        openlog("ogAdmServer", LOG_PID, LOG_DAEMON);
[ef6e3d2]1726
[b9eb98b]1727        /*--------------------------------------------------------------------------------------------------------
1728         Validación de parámetros de ejecución y lectura del fichero de configuración del servicio
1729         ---------------------------------------------------------------------------------------------------------*/
1730        if (!validacionParametros(argc, argv, 1)) // Valida parámetros de ejecución
1731                exit(EXIT_FAILURE);
1732
1733        if (!tomaConfiguracion(szPathFileCfg)) { // Toma parametros de configuracion
1734                exit(EXIT_FAILURE);
1735        }
1736
1737        /*--------------------------------------------------------------------------------------------------------
1738         // Inicializa array de información de los clientes
1739         ---------------------------------------------------------------------------------------------------------*/
1740        for (i = 0; i < MAXIMOS_CLIENTES; i++) {
1741                tbsockets[i].ip[0] = '\0';
[f09aca6]1742                tbsockets[i].cli = NULL;
[b9eb98b]1743        }
1744        /*--------------------------------------------------------------------------------------------------------
1745         Creación y configuración del socket del servicio
1746         ---------------------------------------------------------------------------------------------------------*/
[212280e]1747
[95e6520]1748        socket_rest = og_socket_server_init("8888");
1749        if (socket_rest < 0)
1750                exit(EXIT_FAILURE);
1751
1752        ev_io_init(&ev_io_server_rest, og_server_accept_cb, socket_rest, EV_READ);
[83b242c]1753        ev_io_start(og_loop, &ev_io_server_rest);
[95e6520]1754
[af30cc7]1755        socket_agent_rest = og_socket_server_init("8889");
1756        if (socket_agent_rest < 0)
1757                exit(EXIT_FAILURE);
1758
1759        ev_io_init(&ev_io_agent_rest, og_server_accept_cb, socket_agent_rest, EV_READ);
[83b242c]1760        ev_io_start(og_loop, &ev_io_agent_rest);
1761
1762        if (og_dbi_schedule_get() < 0)
1763                exit(EXIT_FAILURE);
1764
1765        og_schedule_next(og_loop);
[af30cc7]1766
[ef6e3d2]1767        syslog(LOG_INFO, "Waiting for connections\n");
1768
[212280e]1769        while (1)
[83b242c]1770                ev_loop(og_loop, 0);
[212280e]1771
[b9eb98b]1772        exit(EXIT_SUCCESS);
1773}
Note: See TracBrowser for help on using the repository browser.