source: admin/Sources/Services/ogAdmServer/sources/ogAdmServer.c @ d327da6

Last change on this file since d327da6 was d327da6, checked in by OpenGnSys Support Team <soporte-og@…>, 5 years ago

#942 Add support for scheduled tasks and commands

This field needs to be at least 31 bits long to store all days in a month.
Other fields are also set to 32 bits because unsigned int length can change
depending on the system.

We also need to support the three ways that the ogAdmAgent and the WebConsole?
have to create an schedule. At first, we only supported the easiest
method:

  • Hour, day, month and year -> 10:00, 28, february, 2020

This commit adds these two ways to create an schedule:

  • Hour, week day, month and year -> 10:00, Monday, february, 2020
  • Hour, week, month and year -> 10:00, first week, february, 2020
  • Property mode set to 100644
File size: 185.2 KB
Line 
1// *******************************************************************************************************
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
8// *******************************************************************************************************
9#include "ogAdmServer.h"
10#include "ogAdmLib.c"
11#include "dbi.h"
12#include "list.h"
13#include "schedule.h"
14#include <ev.h>
15#include <syslog.h>
16#include <sys/ioctl.h>
17#include <ifaddrs.h>
18#include <sys/types.h>
19#include <sys/stat.h>
20#include <fcntl.h>
21#include <jansson.h>
22#include <time.h>
23
24static char usuario[LONPRM]; // Usuario de acceso a la base de datos
25static char pasguor[LONPRM]; // Password del usuario
26static char datasource[LONPRM]; // Dirección IP del gestor de base de datos
27static char catalog[LONPRM]; // Nombre de la base de datos
28static char interface[LONPRM]; // Interface name
29static char auth_token[LONPRM]; // API token
30
31static struct og_dbi_config dbi_config = {
32        .user           = usuario,
33        .passwd         = pasguor,
34        .host           = datasource,
35        .database       = catalog,
36};
37
38//________________________________________________________________________________________________________
39//      Función: tomaConfiguracion
40//
41//      Descripción:
42//              Lee el fichero de configuración del servicio
43//      Parámetros:
44//              filecfg : Ruta completa al fichero de configuración
45//      Devuelve:
46//              true: Si el proceso es correcto
47//              false: En caso de ocurrir algún error
48//________________________________________________________________________________________________________
49static bool tomaConfiguracion(const char *filecfg)
50{
51        char buf[1024], *line;
52        char *key, *value;
53        FILE *fcfg;
54
55        if (filecfg == NULL || strlen(filecfg) == 0) {
56                syslog(LOG_ERR, "No configuration file has been specified\n");
57                return false;
58        }
59
60        fcfg = fopen(filecfg, "rt");
61        if (fcfg == NULL) {
62                syslog(LOG_ERR, "Cannot open configuration file `%s'\n",
63                       filecfg);
64                return false;
65        }
66
67        servidoradm[0] = '\0'; //inicializar variables globales
68
69        line = fgets(buf, sizeof(buf), fcfg);
70        while (line != NULL) {
71                const char *delim = "=";
72
73                line[strlen(line) - 1] = '\0';
74
75                key = strtok(line, delim);
76                value = strtok(NULL, delim);
77
78                if (!strcmp(StrToUpper(key), "SERVIDORADM"))
79                        snprintf(servidoradm, sizeof(servidoradm), "%s", value);
80                else if (!strcmp(StrToUpper(key), "PUERTO"))
81                        snprintf(puerto, sizeof(puerto), "%s", value);
82                else if (!strcmp(StrToUpper(key), "USUARIO"))
83                        snprintf(usuario, sizeof(usuario), "%s", value);
84                else if (!strcmp(StrToUpper(key), "PASSWORD"))
85                        snprintf(pasguor, sizeof(pasguor), "%s", value);
86                else if (!strcmp(StrToUpper(key), "DATASOURCE"))
87                        snprintf(datasource, sizeof(datasource), "%s", value);
88                else if (!strcmp(StrToUpper(key), "CATALOG"))
89                        snprintf(catalog, sizeof(catalog), "%s", value);
90                else if (!strcmp(StrToUpper(key), "INTERFACE"))
91                        snprintf(interface, sizeof(interface), "%s", value);
92                else if (!strcmp(StrToUpper(key), "APITOKEN"))
93                        snprintf(auth_token, sizeof(auth_token), "%s", value);
94
95                line = fgets(buf, sizeof(buf), fcfg);
96        }
97
98        fclose(fcfg);
99
100        if (!servidoradm[0]) {
101                syslog(LOG_ERR, "Missing SERVIDORADM in configuration file\n");
102                return false;
103        }
104        if (!puerto[0]) {
105                syslog(LOG_ERR, "Missing PUERTO in configuration file\n");
106                return false;
107        }
108        if (!usuario[0]) {
109                syslog(LOG_ERR, "Missing USUARIO in configuration file\n");
110                return false;
111        }
112        if (!pasguor[0]) {
113                syslog(LOG_ERR, "Missing PASSWORD in configuration file\n");
114                return false;
115        }
116        if (!datasource[0]) {
117                syslog(LOG_ERR, "Missing DATASOURCE in configuration file\n");
118                return false;
119        }
120        if (!catalog[0]) {
121                syslog(LOG_ERR, "Missing CATALOG in configuration file\n");
122                return false;
123        }
124        if (!interface[0])
125                syslog(LOG_ERR, "Missing INTERFACE in configuration file\n");
126
127        return true;
128}
129
130enum og_client_state {
131        OG_CLIENT_RECEIVING_HEADER      = 0,
132        OG_CLIENT_RECEIVING_PAYLOAD,
133        OG_CLIENT_PROCESSING_REQUEST,
134};
135
136#define OG_MSG_REQUEST_MAXLEN   65536
137#define OG_CMD_MAXLEN           64
138
139/* Shut down connection if there is no complete message after 10 seconds. */
140#define OG_CLIENT_TIMEOUT       10
141
142/* Agent client operation might take longer, shut down after 30 seconds. */
143#define OG_AGENT_CLIENT_TIMEOUT 30
144
145static LIST_HEAD(client_list);
146
147struct og_client {
148        struct list_head        list;
149        struct ev_io            io;
150        struct ev_timer         timer;
151        struct sockaddr_in      addr;
152        enum og_client_state    state;
153        char                    buf[OG_MSG_REQUEST_MAXLEN];
154        unsigned int            buf_len;
155        unsigned int            msg_len;
156        int                     keepalive_idx;
157        bool                    rest;
158        bool                    agent;
159        int                     content_length;
160        char                    auth_token[64];
161        const char              *status;
162        char                    last_cmd[OG_CMD_MAXLEN];
163};
164
165static inline int og_client_socket(const struct og_client *cli)
166{
167        return cli->io.fd;
168}
169
170// ________________________________________________________________________________________________________
171// Función: clienteDisponible
172//
173//      Descripción:
174//              Comprueba la disponibilidad del cliente para recibir comandos interactivos
175//      Parametros:
176//              - ip : La ip del cliente a buscar
177//              - idx: (Salida)  Indice que ocupa el cliente, de estar ya registrado
178//      Devuelve:
179//              true: Si el cliente está disponible
180//              false: En caso contrario
181// ________________________________________________________________________________________________________
182bool clienteDisponible(char *ip, int* idx)
183{
184        int estado;
185
186        if (clienteExistente(ip, idx)) {
187                estado = strcmp(tbsockets[*idx].estado, CLIENTE_OCUPADO); // Cliente ocupado
188                if (estado == 0)
189                        return false;
190
191                estado = strcmp(tbsockets[*idx].estado, CLIENTE_APAGADO); // Cliente apagado
192                if (estado == 0)
193                        return false;
194
195                estado = strcmp(tbsockets[*idx].estado, CLIENTE_INICIANDO); // Cliente en proceso de inclusión
196                if (estado == 0)
197                        return false;
198
199                return true; // En caso contrario el cliente está disponible
200        }
201        return false; // Cliente no está registrado en el sistema
202}
203// ________________________________________________________________________________________________________
204// Función: clienteExistente
205//
206//      Descripción:
207//              Comprueba si el cliente está registrado en la tabla de socket del sistema
208//      Parametros:
209//              - ip : La ip del cliente a buscar
210//              - idx:(Salida)  Indice que ocupa el cliente, de estar ya registrado
211//      Devuelve:
212//              true: Si el cliente está registrado
213//              false: En caso contrario
214// ________________________________________________________________________________________________________
215bool clienteExistente(char *ip, int* idx)
216{
217        int i;
218        for (i = 0; i < MAXIMOS_CLIENTES; i++) {
219                if (contieneIP(ip, tbsockets[i].ip)) { // Si existe la IP en la cadena
220                        *idx = i;
221                        return true;
222                }
223        }
224        return false;
225}
226// ________________________________________________________________________________________________________
227// Función: hayHueco
228//
229//      Descripción:
230//              Esta función devuelve true o false dependiendo de que haya hueco en la tabla de sockets para un nuevo cliente.
231//      Parametros:
232//              - idx:   Primer indice libre que se podrn utilizar
233//      Devuelve:
234//              true: Si el proceso es correcto
235//              false: En caso de ocurrir algún error
236// ________________________________________________________________________________________________________
237static bool hayHueco(int *idx)
238{
239        int i;
240
241        for (i = 0; i < MAXIMOS_CLIENTES; i++) {
242                if (strncmp(tbsockets[i].ip, "\0", 1) == 0) { // Hay un hueco
243                        *idx = i;
244                        return true;
245                }
246        }
247        return false;
248}
249// ________________________________________________________________________________________________________
250// Función: InclusionClienteWin
251//
252//      Descripción:
253//              Esta función incorpora el socket de un nuevo cliente Windows o Linux a la tabla de clientes
254//      Parámetros:
255//              - socket_c: Socket del cliente que envió el mensaje
256//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
257//      Devuelve:
258//              true: Si el proceso es correcto
259//              false: En caso de ocurrir algún error
260// ________________________________________________________________________________________________________
261static bool InclusionClienteWinLnx(TRAMA *ptrTrama, struct og_client *cli)
262{
263        int socket_c = og_client_socket(cli);
264        int res,idordenador,lon;
265        char nombreordenador[LONFIL];
266
267        res = procesoInclusionClienteWinLnx(socket_c, ptrTrama, &idordenador,
268                                            nombreordenador);
269
270        // Prepara la trama de respuesta
271
272        initParametros(ptrTrama,0);
273        ptrTrama->tipo=MSG_RESPUESTA;
274        lon = sprintf(ptrTrama->parametros, "nfn=RESPUESTA_InclusionClienteWinLnx\r");
275        lon += sprintf(ptrTrama->parametros + lon, "ido=%d\r", idordenador);
276        lon += sprintf(ptrTrama->parametros + lon, "npc=%s\r", nombreordenador);       
277        lon += sprintf(ptrTrama->parametros + lon, "res=%d\r", res);   
278
279        if (!mandaTrama(&socket_c, ptrTrama)) {
280                syslog(LOG_ERR, "failed to send response to %s:%hu reason=%s\n",
281                       inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port),
282                       strerror(errno));
283                return false;
284        }
285        return true;
286}
287// ________________________________________________________________________________________________________
288// Función: procesoInclusionClienteWinLnx
289//
290//      Descripción:
291//              Implementa el proceso de inclusión en el sistema del Cliente Windows o Linux
292//      Parámetros de entrada:
293//              - socket_c: Socket del cliente que envió el mensaje
294//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
295//      Parámetros de salida:
296//              - ido: Identificador del ordenador
297//              - nombreordenador: Nombre del ordenador
298//      Devuelve:
299//              Código del error producido en caso de ocurrir algún error, 0 si el proceso es correcto
300// ________________________________________________________________________________________________________
301bool procesoInclusionClienteWinLnx(int socket_c, TRAMA *ptrTrama, int *idordenador, char *nombreordenador)
302 {
303        struct og_dbi *dbi;
304        const char *msglog;
305        dbi_result result;
306        char *iph;
307
308        // Toma parámetros
309        iph = copiaParametro("iph",ptrTrama); // Toma ip
310
311        dbi = og_dbi_open(&dbi_config);
312        if (!dbi) {
313                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
314                       __func__, __LINE__);
315                goto err_dbi_open;
316        }
317
318        result = dbi_conn_queryf(dbi->conn,
319                        "SELECT idordenador,nombreordenador FROM ordenadores "
320                                " WHERE ordenadores.ip = '%s'", iph);
321        if (!result) {
322                dbi_conn_error(dbi->conn, &msglog);
323                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
324                       __func__, __LINE__, msglog);
325                goto err_query_fail;
326        }
327
328        if (!dbi_result_next_row(result)) {
329                syslog(LOG_ERR, "client does not exist in database (%s:%d)\n",
330                       __func__, __LINE__);
331                dbi_result_free(result);
332                goto err_query_fail;
333        }
334
335        syslog(LOG_DEBUG, "Client %s requesting inclusion\n", iph);
336
337        *idordenador = dbi_result_get_uint(result, "idordenador");
338        nombreordenador = (char *)dbi_result_get_string(result, "nombreordenador");
339
340        dbi_result_free(result);
341        og_dbi_close(dbi);
342
343        if (!registraCliente(iph)) { // Incluyendo al cliente en la tabla de sokets
344                liberaMemoria(iph);
345                syslog(LOG_ERR, "client table is full\n");
346                return false;
347        }
348        liberaMemoria(iph);
349        return true;
350
351err_query_fail:
352        og_dbi_close(dbi);
353err_dbi_open:
354        liberaMemoria(iph);
355        return false;
356}
357// ________________________________________________________________________________________________________
358// Función: InclusionCliente
359//
360//      Descripción:
361//              Esta función incorpora el socket de un nuevo cliente a la tabla de clientes y le devuelve alguna de sus propiedades:
362//              nombre, identificador, tamaño de la caché , etc ...
363//      Parámetros:
364//              - socket_c: Socket del cliente que envió el mensaje
365//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
366//      Devuelve:
367//              true: Si el proceso es correcto
368//              false: En caso de ocurrir algún error
369// ________________________________________________________________________________________________________
370static bool InclusionCliente(TRAMA *ptrTrama, struct og_client *cli)
371{
372        int socket_c = og_client_socket(cli);
373
374        if (!procesoInclusionCliente(cli, ptrTrama)) {
375                initParametros(ptrTrama,0);
376                strcpy(ptrTrama->parametros, "nfn=RESPUESTA_InclusionCliente\rres=0\r");
377                if (!mandaTrama(&socket_c, ptrTrama)) {
378                        syslog(LOG_ERR, "failed to send response to %s:%hu reason=%s\n",
379                               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port),
380                               strerror(errno));
381                        return false;
382                }
383        }
384        return true;
385}
386// ________________________________________________________________________________________________________
387// Función: procesoInclusionCliente
388//
389//      Descripción:
390//              Implementa el proceso de inclusión en el sistema del Cliente
391//      Parámetros:
392//              - socket_c: Socket del cliente que envió el mensaje
393//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
394//      Devuelve:
395//              true: Si el proceso es correcto
396//              false: En caso de ocurrir algún error
397// ________________________________________________________________________________________________________
398bool procesoInclusionCliente(struct og_client *cli, TRAMA *ptrTrama)
399{
400        int socket_c = og_client_socket(cli);
401        const char *msglog, *str;
402        struct og_dbi *dbi;
403        dbi_result result;
404
405        char *iph, *cfg;
406        char nombreordenador[LONFIL];
407        int lon, resul, idordenador, cache, idproautoexec, idaula, idcentro;
408
409        // Toma parámetros
410        iph = copiaParametro("iph",ptrTrama); // Toma ip
411        cfg = copiaParametro("cfg",ptrTrama); // Toma configuracion
412
413        dbi = og_dbi_open(&dbi_config);
414        if (!dbi) {
415                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
416                       __func__, __LINE__);
417                goto err_dbi_open;
418        }
419
420        // Recupera los datos del cliente
421        result = dbi_conn_queryf(dbi->conn,
422                        "SELECT ordenadores.*,aulas.idaula,centros.idcentro FROM ordenadores "
423                                " INNER JOIN aulas ON aulas.idaula=ordenadores.idaula"
424                                " INNER JOIN centros ON centros.idcentro=aulas.idcentro"
425                                " WHERE ordenadores.ip = '%s'", iph);
426
427        if (!result) {
428                dbi_conn_error(dbi->conn, &msglog);
429                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
430                       __func__, __LINE__, msglog);
431                goto err_query_fail;
432        }
433
434        if (!dbi_result_next_row(result)) {
435                syslog(LOG_ERR, "client does not exist in database (%s:%d)\n",
436                       __func__, __LINE__);
437                dbi_result_free(result);
438                goto err_query_fail;
439        }
440
441        syslog(LOG_DEBUG, "Client %s requesting inclusion\n", iph);
442
443        idordenador = dbi_result_get_uint(result, "idordenador");
444        str = (char *)dbi_result_get_string(result, "nombreordenador");
445        sprintf(nombreordenador, "%s", str);
446        cache = dbi_result_get_uint(result, "cache");
447        idproautoexec = dbi_result_get_uint(result, "idproautoexec");
448        idaula = dbi_result_get_uint(result, "idaula");
449        idcentro = dbi_result_get_uint(result, "idcentro");
450        dbi_result_free(result);
451
452        resul = actualizaConfiguracion(dbi, cfg, idordenador); // Actualiza la configuración del ordenador
453        liberaMemoria(cfg);
454        og_dbi_close(dbi);
455
456        if (!resul) {
457                liberaMemoria(iph);
458                syslog(LOG_ERR, "Cannot add client to database\n");
459                return false;
460        }
461
462        if (!registraCliente(iph)) { // Incluyendo al cliente en la tabla de sokets
463                liberaMemoria(iph);
464                syslog(LOG_ERR, "client table is full\n");
465                return false;
466        }
467
468        /*------------------------------------------------------------------------------------------------------------------------------
469         Prepara la trama de respuesta
470         -------------------------------------------------------------------------------------------------------------------------------*/
471        initParametros(ptrTrama,0);
472        ptrTrama->tipo=MSG_RESPUESTA;
473        lon = sprintf(ptrTrama->parametros, "nfn=RESPUESTA_InclusionCliente\r");
474        lon += sprintf(ptrTrama->parametros + lon, "ido=%d\r", idordenador);
475        lon += sprintf(ptrTrama->parametros + lon, "npc=%s\r", nombreordenador);
476        lon += sprintf(ptrTrama->parametros + lon, "che=%d\r", cache);
477        lon += sprintf(ptrTrama->parametros + lon, "exe=%d\r", idproautoexec);
478        lon += sprintf(ptrTrama->parametros + lon, "ida=%d\r", idaula);
479        lon += sprintf(ptrTrama->parametros + lon, "idc=%d\r", idcentro);
480        lon += sprintf(ptrTrama->parametros + lon, "res=%d\r", 1); // Confirmación proceso correcto
481
482        if (!mandaTrama(&socket_c, ptrTrama)) {
483                syslog(LOG_ERR, "failed to send response to %s:%hu reason=%s\n",
484                       inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port),
485                       strerror(errno));
486                return false;
487        }
488        liberaMemoria(iph);
489        return true;
490
491err_query_fail:
492        og_dbi_close(dbi);
493err_dbi_open:
494        liberaMemoria(iph);
495        liberaMemoria(cfg);
496        return false;
497}
498// ________________________________________________________________________________________________________
499// Función: actualizaConfiguracion
500//
501//      Descripción:
502//              Esta función actualiza la base de datos con la configuracion de particiones de un cliente
503//      Parámetros:
504//              - db: Objeto base de datos (ya operativo)
505//              - tbl: Objeto tabla
506//              - cfg: cadena con una Configuración
507//              - ido: Identificador del ordenador cliente
508//      Devuelve:
509//              true: Si el proceso es correcto
510//              false: En caso de ocurrir algún error
511//      Especificaciones:
512//              Los parametros de la configuración son:
513//                      par= Número de partición
514//                      cpt= Codigo o tipo de partición
515//                      sfi= Sistema de ficheros que está implementado en la partición
516//                      soi= Nombre del sistema de ficheros instalado en la partición
517//                      tam= Tamaño de la partición
518// ________________________________________________________________________________________________________
519bool actualizaConfiguracion(struct og_dbi *dbi, char *cfg, int ido)
520{
521        int lon, p, c,i, dato, swu, idsoi, idsfi,k;
522        char *ptrPar[MAXPAR], *ptrCfg[7], *ptrDual[2], tbPar[LONSTD];
523        char *ser, *disk, *par, *cpt, *sfi, *soi, *tam, *uso; // Parametros de configuración.
524        dbi_result result, result_update;
525        const char *msglog;
526
527        lon = 0;
528        p = splitCadena(ptrPar, cfg, '\n');
529        for (i = 0; i < p; i++) {
530                c = splitCadena(ptrCfg, ptrPar[i], '\t');
531
532                // Si la 1ª línea solo incluye el número de serie del equipo; actualizar BD.
533                if (i == 0 && c == 1) {
534                        splitCadena(ptrDual, ptrCfg[0], '=');
535                        ser = ptrDual[1];
536                        if (strlen(ser) > 0) {
537                                // Solo actualizar si número de serie no existía.
538                                result = dbi_conn_queryf(dbi->conn,
539                                                "UPDATE ordenadores SET numserie='%s'"
540                                                " WHERE idordenador=%d AND numserie IS NULL",
541                                                ser, ido);
542                                if (!result) {
543                                        dbi_conn_error(dbi->conn, &msglog);
544                                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
545                                               __func__, __LINE__, msglog);
546                                        return false;
547                                }
548                                dbi_result_free(result);
549                        }
550                        continue;
551                }
552
553                // Distribución de particionado.
554                disk = par = cpt = sfi = soi = tam = uso = NULL;
555
556                splitCadena(ptrDual, ptrCfg[0], '=');
557                disk = ptrDual[1]; // Número de disco
558
559                splitCadena(ptrDual, ptrCfg[1], '=');
560                par = ptrDual[1]; // Número de partición
561
562                k=splitCadena(ptrDual, ptrCfg[2], '=');
563                if(k==2){
564                        cpt = ptrDual[1]; // Código de partición
565                }else{
566                        cpt = (char*)"0";
567                }
568
569                k=splitCadena(ptrDual, ptrCfg[3], '=');
570                if(k==2){
571                        sfi = ptrDual[1]; // Sistema de ficheros
572                        /* Comprueba existencia del s0xistema de ficheros instalado */
573                        idsfi = checkDato(dbi, sfi, "sistemasficheros", "descripcion","idsistemafichero");
574                }
575                else
576                        idsfi=0;
577
578                k=splitCadena(ptrDual, ptrCfg[4], '=');
579                if(k==2){ // Sistema operativo detecdtado
580                        soi = ptrDual[1]; // Nombre del S.O. instalado
581                        /* Comprueba existencia del sistema operativo instalado */
582                        idsoi = checkDato(dbi, soi, "nombresos", "nombreso", "idnombreso");
583                }
584                else
585                        idsoi=0;
586
587                splitCadena(ptrDual, ptrCfg[5], '=');
588                tam = ptrDual[1]; // Tamaño de la partición
589
590                splitCadena(ptrDual, ptrCfg[6], '=');
591                uso = ptrDual[1]; // Porcentaje de uso del S.F.
592
593                lon += sprintf(tbPar + lon, "(%s, %s),", disk, par);
594
595                result = dbi_conn_queryf(dbi->conn,
596                                "SELECT numdisk, numpar, tamano, uso, idsistemafichero, idnombreso"
597                                "  FROM ordenadores_particiones"
598                                " WHERE idordenador=%d AND numdisk=%s AND numpar=%s",
599                                ido, disk, par);
600                if (!result) {
601                        dbi_conn_error(dbi->conn, &msglog);
602                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
603                               __func__, __LINE__, msglog);
604                        return false;
605                }
606                if (!dbi_result_next_row(result)) {
607                        result_update = dbi_conn_queryf(dbi->conn,
608                                        "INSERT INTO ordenadores_particiones(idordenador,numdisk,numpar,codpar,tamano,uso,idsistemafichero,idnombreso,idimagen)"
609                                        " VALUES(%d,%s,%s,0x%s,%s,%s,%d,%d,0)",
610                                        ido, disk, par, cpt, tam, uso, idsfi, idsoi);
611                        if (!result_update) {
612                                dbi_conn_error(dbi->conn, &msglog);
613                                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
614                                       __func__, __LINE__, msglog);
615                                return false;
616                        }
617                        dbi_result_free(result_update);
618
619                } else { // Existe el registro
620                        swu = true; // Se supone que algún dato ha cambiado
621
622                        dato = dbi_result_get_uint(result, "tamano");
623                        if (atoi(tam) == dato) {// Parámetro tamaño igual al almacenado
624                                dato = dbi_result_get_uint(result, "idsistemafichero");
625                                if (idsfi == dato) {// Parámetro sistema de fichero igual al almacenado
626                                        dato = dbi_result_get_uint(result, "idnombreso");
627                                        if (idsoi == dato) {// Parámetro sistema de fichero distinto al almacenado
628                                                swu = false; // Todos los parámetros de la partición son iguales, no se actualiza
629                                        }
630                                }
631                        }
632                        if (swu) { // Hay que actualizar los parámetros de la partición
633                                result_update = dbi_conn_queryf(dbi->conn,
634                                        "UPDATE ordenadores_particiones SET "
635                                        " codpar=0x%s,"
636                                        " tamano=%s,"
637                                        " uso=%s,"
638                                        " idsistemafichero=%d,"
639                                        " idnombreso=%d,"
640                                        " idimagen=0,"
641                                        " idperfilsoft=0,"
642                                        " fechadespliegue=NULL"
643                                        " WHERE idordenador=%d AND numdisk=%s AND numpar=%s",
644                                        cpt, tam, uso, idsfi, idsoi, ido, disk, par);
645                        } else {  // Actualizar porcentaje de uso.
646                                result_update = dbi_conn_queryf(dbi->conn,
647                                        "UPDATE ordenadores_particiones SET "
648                                        " codpar=0x%s,"
649                                        " uso=%s"
650                                        " WHERE idordenador=%d AND numdisk=%s AND numpar=%s",
651                                        cpt, uso, ido, disk, par);
652                        }
653                        if (!result_update) {
654                                dbi_conn_error(dbi->conn, &msglog);
655                                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
656                                       __func__, __LINE__, msglog);
657                                return false;
658                        }
659
660                        dbi_result_free(result_update);
661                }
662                dbi_result_free(result);
663        }
664        lon += sprintf(tbPar + lon, "(0,0)");
665        // Eliminar particiones almacenadas que ya no existen
666        result_update = dbi_conn_queryf(dbi->conn,
667                "DELETE FROM ordenadores_particiones WHERE idordenador=%d AND (numdisk, numpar) NOT IN (%s)",
668                        ido, tbPar);
669        if (!result_update) {
670                dbi_conn_error(dbi->conn, &msglog);
671                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
672                       __func__, __LINE__, msglog);
673                return false;
674        }
675        dbi_result_free(result_update);
676
677        return true;
678}
679// ________________________________________________________________________________________________________
680// Función: checkDato
681//
682//      Descripción:
683//               Esta función comprueba si existe un dato en una tabla y si no es así lo incluye. devuelve en
684//              cualquier caso el identificador del registro existenet o del insertado
685//      Parámetros:
686//              - db: Objeto base de datos (ya operativo)
687//              - tbl: Objeto tabla
688//              - dato: Dato
689//              - tabla: Nombre de la tabla
690//              - nomdato: Nombre del dato en la tabla
691//              - nomidentificador: Nombre del identificador en la tabla
692//      Devuelve:
693//              El identificador del registro existente o el del insertado
694//
695//      Especificaciones:
696//              En caso de producirse algún error se devuelve el valor 0
697// ________________________________________________________________________________________________________
698
699int checkDato(struct og_dbi *dbi, char *dato, const char *tabla,
700                     const char *nomdato, const char *nomidentificador)
701{
702        const char *msglog;
703        int identificador;
704        dbi_result result;
705
706        if (strlen(dato) == 0)
707                return (0); // EL dato no tiene valor
708        result = dbi_conn_queryf(dbi->conn,
709                        "SELECT %s FROM %s WHERE %s ='%s'", nomidentificador,
710                        tabla, nomdato, dato);
711
712        // Ejecuta consulta
713        if (!result) {
714                dbi_conn_error(dbi->conn, &msglog);
715                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
716                       __func__, __LINE__, msglog);
717                return (0);
718        }
719        if (!dbi_result_next_row(result)) { //  Software NO existente
720                dbi_result_free(result);
721
722                result = dbi_conn_queryf(dbi->conn,
723                                "INSERT INTO %s (%s) VALUES('%s')", tabla, nomdato, dato);
724                if (!result) {
725                        dbi_conn_error(dbi->conn, &msglog);
726                        og_info((char *)msglog);
727                        return (0);
728                }
729                // Recupera el identificador del software
730                identificador = dbi_conn_sequence_last(dbi->conn, NULL);
731        } else {
732                identificador = dbi_result_get_uint(result, nomidentificador);
733        }
734        dbi_result_free(result);
735
736        return (identificador);
737}
738// ________________________________________________________________________________________________________
739// Función: registraCliente
740//
741//      Descripción:
742//               Incluye al cliente en la tabla de sokets
743//      Parámetros:
744//              - iph: Dirección ip del cliente
745//      Devuelve:
746//              true: Si el proceso es correcto
747//              false: En caso de ocurrir algún error
748// ________________________________________________________________________________________________________
749bool registraCliente(char *iph)
750{
751        int idx;
752
753        if (!clienteExistente(iph, &idx)) { // Si no existe la IP ...
754                if (!hayHueco(&idx)) { // Busca hueco para el nuevo cliente
755                        return false; // No hay huecos
756                }
757        }
758        strcpy(tbsockets[idx].ip, iph); // Copia IP
759        strcpy(tbsockets[idx].estado, CLIENTE_INICIANDO); // Actualiza el estado del cliente
760        return true;
761}
762// ________________________________________________________________________________________________________
763// Función: AutoexecCliente
764//
765//      Descripción:
766//              Envía archivo de autoexec al cliente
767//      Parámetros:
768//              - socket_c: Socket del cliente que envió el mensaje
769//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
770//      Devuelve:
771//              true: Si el proceso es correcto
772//              false: En caso de ocurrir algún error
773// ________________________________________________________________________________________________________
774static bool AutoexecCliente(TRAMA *ptrTrama, struct og_client *cli)
775{
776        int socket_c = og_client_socket(cli);
777        int lon;
778        char *iph, *exe;
779        FILE *fileexe;
780        char fileautoexec[LONPRM];
781        char parametros[LONGITUD_PARAMETROS];
782        struct og_dbi *dbi;
783
784        iph = copiaParametro("iph",ptrTrama); // Toma dirección IP del cliente
785        exe = copiaParametro("exe",ptrTrama); // Toma identificador del procedimiento inicial
786
787        sprintf(fileautoexec, "/tmp/Sautoexec-%s", iph);
788        liberaMemoria(iph);
789        fileexe = fopen(fileautoexec, "wb"); // Abre fichero de script
790        if (fileexe == NULL) {
791                syslog(LOG_ERR, "cannot create temporary file\n");
792                return false;
793        }
794
795        dbi = og_dbi_open(&dbi_config);
796        if (!dbi) {
797                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
798                       __func__, __LINE__);
799                return false;
800        }
801        initParametros(ptrTrama,0);
802        if (recorreProcedimientos(dbi, parametros, fileexe, exe)) {
803                lon = sprintf(ptrTrama->parametros, "nfn=RESPUESTA_AutoexecCliente\r");
804                lon += sprintf(ptrTrama->parametros + lon, "nfl=%s\r", fileautoexec);
805                lon += sprintf(ptrTrama->parametros + lon, "res=1\r");
806        } else {
807                lon = sprintf(ptrTrama->parametros, "nfn=RESPUESTA_AutoexecCliente\r");
808                lon += sprintf(ptrTrama->parametros + lon, "res=0\r");
809        }
810
811        og_dbi_close(dbi);
812        fclose(fileexe);
813
814        if (!mandaTrama(&socket_c, ptrTrama)) {
815                liberaMemoria(exe);
816                syslog(LOG_ERR, "failed to send response to %s:%hu reason=%s\n",
817                       inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port),
818                       strerror(errno));
819                return false;
820        }
821        liberaMemoria(exe);
822        return true;
823}
824// ________________________________________________________________________________________________________
825// Función: recorreProcedimientos
826//
827//      Descripción:
828//              Crea un archivo con el código de un procedimiento separando cada comando  por un salto de linea
829//      Parámetros:
830//              Database db,char* parametros,FILE* fileexe,char* idp
831//      Devuelve:
832//              true: Si el proceso es correcto
833//              false: En caso de ocurrir algún error
834// ________________________________________________________________________________________________________
835bool recorreProcedimientos(struct og_dbi *dbi, char *parametros, FILE *fileexe, char *idp)
836{
837        char idprocedimiento[LONPRM];
838        int procedimientoid, lsize;
839        const char *msglog, *param;
840        dbi_result result;
841
842        result = dbi_conn_queryf(dbi->conn,
843                        "SELECT procedimientoid,parametros FROM procedimientos_acciones"
844                                " WHERE idprocedimiento=%s ORDER BY orden", idp);
845        if (!result) {
846                dbi_conn_error(dbi->conn, &msglog);
847                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
848                       __func__, __LINE__, msglog);
849                return false;
850        }
851        while (dbi_result_next_row(result)) {
852                procedimientoid = dbi_result_get_uint(result, "procedimientoid");
853                if (procedimientoid > 0) { // Procedimiento recursivo
854                        sprintf(idprocedimiento, "%d", procedimientoid);
855                        if (!recorreProcedimientos(dbi, parametros, fileexe, idprocedimiento)) {
856                                return false;
857                        }
858                } else {
859                        param = dbi_result_get_string(result, "parametros");
860                        sprintf(parametros, "%s@", param);
861                        lsize = strlen(parametros);
862                        fwrite(parametros, 1, lsize, fileexe); // Escribe el código a ejecutar
863                }
864        }
865        dbi_result_free(result);
866
867        return true;
868}
869
870struct og_task {
871        uint32_t        procedure_id;
872        uint32_t        type_scope;
873        uint32_t        scope;
874        const char      *filtered_scope;
875        const char      *params;
876};
877
878struct og_cmd {
879        struct list_head list;
880        uint32_t        client_id;
881        const char      *params;
882        const char      *ip;
883        const char      *mac;
884};
885
886static LIST_HEAD(cmd_list);
887
888static const struct og_cmd *og_cmd_find(char *client_ip)
889{
890        struct og_cmd *cmd, *next;
891
892        list_for_each_entry_safe(cmd, next, &cmd_list, list) {
893                if (strcmp(cmd->ip, client_ip))
894                        continue;
895
896                list_del(&cmd->list);
897                return cmd;
898        }
899
900        return NULL;
901}
902
903static void og_cmd_free(const struct og_cmd *cmd)
904{
905        free((void *)cmd->params);
906        free((void *)cmd->ip);
907        free((void *)cmd->mac);
908        free((void *)cmd);
909}
910
911static TRAMA *og_msg_alloc(char *data, unsigned int len);
912static void og_msg_free(TRAMA *ptrTrama);
913
914static int og_deliver_pending_command(const struct og_cmd *cmd, int *socket,
915                                      int idx)
916{
917        char buf[4096];
918        TRAMA *msg;
919        int len;
920
921        len = snprintf(buf, sizeof(buf), "%s\r", cmd->params);
922
923        msg = og_msg_alloc(buf, len);
924        if (!msg)
925                return false;
926
927        strcpy(tbsockets[idx].estado, CLIENTE_OCUPADO);
928        if (!mandaTrama(socket, msg)) {
929                syslog(LOG_ERR, "failed to send response to %s reason=%s\n",
930                                cmd->ip, strerror(errno));
931                return false;
932        }
933        og_msg_free(msg);
934        og_cmd_free(cmd);
935
936        return true;
937}
938
939// ________________________________________________________________________________________________________
940// Función: ComandosPendientes
941//
942//      Descripción:
943//              Esta función busca en la base de datos,comandos pendientes de ejecutar por un  ordenador  concreto
944//      Parámetros:
945//              - socket_c: Socket del cliente que envió el mensaje
946//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
947//      Devuelve:
948//              true: Si el proceso es correcto
949//              false: En caso de ocurrir algún error
950// ________________________________________________________________________________________________________
951static bool ComandosPendientes(TRAMA *ptrTrama, struct og_client *cli)
952{
953        int socket_c = og_client_socket(cli);
954        char *ido,*iph,pids[LONPRM];
955        const struct og_cmd *cmd;
956        int ids, idx;
957
958        iph = copiaParametro("iph",ptrTrama); // Toma dirección IP
959        ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
960
961        if (!clienteExistente(iph, &idx)) { // Busca índice del cliente
962                liberaMemoria(iph);
963                liberaMemoria(ido);
964                syslog(LOG_ERR, "client does not exist\n");
965                return false;
966        }
967
968        cmd = og_cmd_find(iph);
969        if (cmd) {
970                liberaMemoria(iph);
971                liberaMemoria(ido);
972                return og_deliver_pending_command(cmd, &socket_c, idx);
973        } else if (buscaComandos(ido, ptrTrama, &ids)) { // Existen comandos pendientes
974                ptrTrama->tipo = MSG_COMANDO;
975                sprintf(pids, "\rids=%d\r", ids);
976                strcat(ptrTrama->parametros, pids);
977                strcpy(tbsockets[idx].estado, CLIENTE_OCUPADO);
978        } else {
979                initParametros(ptrTrama,0);
980                strcpy(ptrTrama->parametros, "nfn=NoComandosPtes\r");
981        }
982        if (!mandaTrama(&socket_c, ptrTrama)) {
983                liberaMemoria(iph);
984                liberaMemoria(ido);
985                syslog(LOG_ERR, "failed to send response to %s:%hu reason=%s\n",
986                       inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port),
987                       strerror(errno));
988                return false;
989        }
990        liberaMemoria(iph);
991        liberaMemoria(ido);     
992        return true;
993}
994// ________________________________________________________________________________________________________
995// Función: buscaComandos
996//
997//      Descripción:
998//              Busca en la base de datos,comandos pendientes de ejecutar por el cliente
999//      Parámetros:
1000//              - ido: Identificador del ordenador
1001//              - cmd: Parámetros del comando (Salida)
1002//              - ids: Identificador de la sesion(Salida)
1003//      Devuelve:
1004//              true: Si el proceso es correcto
1005//              false: En caso de ocurrir algún error
1006// ________________________________________________________________________________________________________
1007bool buscaComandos(char *ido, TRAMA *ptrTrama, int *ids)
1008{
1009        const char *param, *msglog;
1010        struct og_dbi *dbi;
1011        dbi_result result;
1012        unsigned int lonprm;
1013
1014        dbi = og_dbi_open(&dbi_config);
1015        if (!dbi) {
1016                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
1017                       __func__, __LINE__);
1018                goto err_dbi_open;
1019        }
1020        result = dbi_conn_queryf(dbi->conn,
1021                        "SELECT sesion, parametros"\
1022                        " FROM acciones WHERE idordenador=%s AND estado='%d'"\
1023                        " ORDER BY idaccion", ido, ACCION_INICIADA);
1024        if (!result) {
1025                dbi_conn_error(dbi->conn, &msglog);
1026                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1027                       __func__, __LINE__, msglog);
1028                goto err_query_fail;
1029        }
1030        if (!dbi_result_next_row(result)) {
1031                dbi_result_free(result);
1032                og_dbi_close(dbi);
1033                return false; // No hay comandos pendientes
1034        }
1035
1036        *ids = dbi_result_get_uint(result, "sesion");
1037        param = dbi_result_get_string(result, "parametros");
1038        lonprm = strlen(param);
1039
1040        if(!initParametros(ptrTrama,lonprm + LONGITUD_PARAMETROS)){
1041                syslog(LOG_ERR, "%s:%d OOM\n", __FILE__, __LINE__);
1042                goto err_init_params;
1043        }
1044        sprintf(ptrTrama->parametros, "%s", param);
1045
1046        dbi_result_free(result);
1047        og_dbi_close(dbi);
1048
1049        return true; // Hay comandos pendientes, se toma el primero de la cola
1050
1051err_init_params:
1052        dbi_result_free(result);
1053err_query_fail:
1054        og_dbi_close(dbi);
1055err_dbi_open:
1056        return false;
1057}
1058// ________________________________________________________________________________________________________
1059// Función: DisponibilidadComandos
1060//
1061//      Descripción:
1062//              Esta función habilita a un cliente para recibir comandos desde la consola
1063//      Parámetros:
1064//              - socket_c: Socket del cliente que envió el mensaje
1065//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1066//      Devuelve:
1067//              true: Si el proceso es correcto
1068//              false: En caso de ocurrir algún error
1069// ________________________________________________________________________________________________________
1070//
1071static bool DisponibilidadComandos(TRAMA *ptrTrama, struct og_client *cli)
1072{
1073        char *iph, *tpc;
1074        int idx;
1075
1076        iph = copiaParametro("iph",ptrTrama); // Toma ip
1077        if (!clienteExistente(iph, &idx)) { // Busca índice del cliente
1078                liberaMemoria(iph);
1079                syslog(LOG_ERR, "client does not exist\n");
1080                return false;
1081        }
1082        tpc = copiaParametro("tpc",ptrTrama); // Tipo de cliente (Plataforma y S.O.)
1083        strcpy(tbsockets[idx].estado, tpc);
1084        cli->keepalive_idx = idx;
1085        liberaMemoria(iph);
1086        liberaMemoria(tpc);             
1087        return true;
1088}
1089// ________________________________________________________________________________________________________
1090// Función: respuestaEstandar
1091//
1092//      Descripción:
1093//              Esta función actualiza la base de datos con el resultado de la ejecución de un comando con seguimiento
1094//      Parámetros:
1095//              - res: resultado de la ejecución del comando
1096//              - der: Descripción del error si hubiese habido
1097//              - iph: Dirección IP
1098//              - ids: identificador de la sesión
1099//              - ido: Identificador del ordenador que notifica
1100//              - db: Objeto base de datos (operativo)
1101//              - tbl: Objeto tabla
1102//      Devuelve:
1103//              true: Si el proceso es correcto
1104//              false: En caso de ocurrir algún error
1105// ________________________________________________________________________________________________________
1106static bool respuestaEstandar(TRAMA *ptrTrama, char *iph, char *ido,
1107                              struct og_dbi *dbi)
1108{
1109        char *res, *ids, *der;
1110        char fechafin[LONPRM];
1111        const char *msglog;
1112        dbi_result result;
1113        struct tm* st;
1114        int idaccion;
1115
1116        ids = copiaParametro("ids",ptrTrama);
1117        res = copiaParametro("res",ptrTrama);
1118
1119        if (ids == NULL) {
1120                if (atoi(res) == ACCION_FALLIDA) {
1121                        liberaMemoria(res);
1122                        return false;
1123                }
1124                liberaMemoria(res);
1125                return true;
1126        }
1127
1128        if (atoi(ids) == 0) {
1129                liberaMemoria(ids);
1130                if (atoi(res) == ACCION_FALLIDA) {
1131                        liberaMemoria(res);
1132                        return false;
1133                }
1134                liberaMemoria(res);
1135                return true;
1136        }
1137
1138        result = dbi_conn_queryf(dbi->conn,
1139                        "SELECT * FROM acciones WHERE idordenador=%s"
1140                        " AND sesion=%s ORDER BY idaccion", ido,ids);
1141
1142        liberaMemoria(ids);
1143
1144        if (!result) {
1145                dbi_conn_error(dbi->conn, &msglog);
1146                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1147                       __func__, __LINE__, msglog);
1148                return false;
1149        }
1150        if (!dbi_result_next_row(result)) {
1151                syslog(LOG_ERR, "no actions available\n");
1152                dbi_result_free(result);
1153                return true;
1154        }
1155
1156        idaccion = dbi_result_get_uint(result, "idaccion");
1157        dbi_result_free(result);
1158
1159        st = tomaHora();
1160        sprintf(fechafin, "%d/%d/%d %d:%d:%d", st->tm_year + 1900, st->tm_mon + 1,
1161                        st->tm_mday, st->tm_hour, st->tm_min, st->tm_sec);
1162
1163        der = copiaParametro("der",ptrTrama); // Toma descripción del error (si hubiera habido)
1164
1165        result = dbi_conn_queryf(dbi->conn,
1166                        "UPDATE acciones"\
1167                        "   SET resultado='%s',estado='%d',fechahorafin='%s',descrinotificacion='%s'"\
1168                        " WHERE idordenador=%s AND idaccion=%d",
1169                        res, ACCION_FINALIZADA, fechafin, der, ido, idaccion);
1170        if (!result) {
1171                dbi_conn_error(dbi->conn, &msglog);
1172                liberaMemoria(res);
1173                liberaMemoria(der);
1174                og_info((char *)msglog);
1175                return false;
1176        }
1177        dbi_result_free(result);
1178
1179        liberaMemoria(der);
1180
1181        if (atoi(res) == ACCION_FALLIDA) {
1182                liberaMemoria(res);
1183                return false;
1184        }
1185
1186        liberaMemoria(res);
1187        return true;
1188}
1189
1190static bool og_send_cmd(char *ips_array[], int ips_array_len,
1191                        const char *state, TRAMA *ptrTrama)
1192{
1193        int i, idx;
1194
1195        for (i = 0; i < ips_array_len; i++) {
1196                if (clienteDisponible(ips_array[i], &idx)) { // Si el cliente puede recibir comandos
1197                        int sock = tbsockets[idx].cli ? tbsockets[idx].cli->io.fd : -1;
1198
1199                        strcpy(tbsockets[idx].estado, state); // Actualiza el estado del cliente
1200                        if (sock >= 0 && !mandaTrama(&sock, ptrTrama)) {
1201                                syslog(LOG_ERR, "failed to send response to %s:%s\n",
1202                                       ips_array[i], strerror(errno));
1203                        }
1204                }
1205        }
1206        return true;
1207}
1208
1209// ________________________________________________________________________________________________________
1210// Función: enviaComando
1211//
1212//      Descripción:
1213//              Envía un comando a los clientes
1214//      Parámetros:
1215//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1216//              - estado: Estado en el se deja al cliente mientras se ejecuta el comando
1217//      Devuelve:
1218//              true: Si el proceso es correcto
1219//              false: En caso de ocurrir algún error
1220// ________________________________________________________________________________________________________
1221bool enviaComando(TRAMA* ptrTrama, const char *estado)
1222{
1223        char *iph, *Ipes, *ptrIpes[MAXIMOS_CLIENTES];
1224        int lon;
1225
1226        iph = copiaParametro("iph",ptrTrama); // Toma dirección/es IP
1227        lon = strlen(iph); // Calcula longitud de la cadena de direccion/es IPE/S
1228        Ipes = (char*) reservaMemoria(lon + 1);
1229        if (Ipes == NULL) {
1230                syslog(LOG_ERR, "%s:%d OOM\n", __FILE__, __LINE__);
1231                return false;
1232        }
1233       
1234        strcpy(Ipes, iph); // Copia cadena de IPES
1235        liberaMemoria(iph);
1236
1237        lon = splitCadena(ptrIpes, Ipes, ';');
1238        FINCADaINTRO(ptrTrama);
1239
1240        if (!og_send_cmd(ptrIpes, lon, estado, ptrTrama))
1241                return false;
1242
1243        liberaMemoria(Ipes);
1244        return true;
1245}
1246//______________________________________________________________________________________________________
1247// Función: respuestaConsola
1248//
1249//      Descripción:
1250//              Envia una respuesta a la consola sobre el resultado de la ejecución de un comando
1251//      Parámetros:
1252//              - socket_c: (Salida) Socket utilizado para el envío
1253//              - res: Resultado del envío del comando
1254//      Devuelve:
1255//              true: Si el proceso es correcto
1256//              false: En caso de ocurrir algún error
1257// ________________________________________________________________________________________________________
1258bool respuestaConsola(int socket_c, TRAMA *ptrTrama, int res)
1259{
1260        initParametros(ptrTrama,0);
1261        sprintf(ptrTrama->parametros, "res=%d\r", res);
1262        if (!mandaTrama(&socket_c, ptrTrama)) {
1263                syslog(LOG_ERR, "%s:%d failed to send response: %s\n",
1264                       __func__, __LINE__, strerror(errno));
1265                return false;
1266        }
1267        return true;
1268}
1269// ________________________________________________________________________________________________________
1270// Función: Levanta
1271//
1272//      Descripción:
1273//              Enciende ordenadores a través de la red cuyas macs se pasan como parámetro
1274//      Parámetros:
1275//              - iph: Cadena de direcciones ip separadas por ";"
1276//              - mac: Cadena de direcciones mac separadas por ";"
1277//              - mar: Método de arranque (1=Broadcast, 2=Unicast)
1278//      Devuelve:
1279//              true: Si el proceso es correcto
1280//              false: En caso de ocurrir algún error
1281// ________________________________________________________________________________________________________
1282
1283bool Levanta(char *ptrIP[], char *ptrMacs[], int lon, char *mar)
1284{
1285        unsigned int on = 1;
1286        struct sockaddr_in local;
1287        int i, res;
1288        int s;
1289
1290        /* Creación de socket para envío de magig packet */
1291        s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1292        if (s < 0) {
1293                syslog(LOG_ERR, "cannot create socket for magic packet\n");
1294                return false;
1295        }
1296        res = setsockopt(s, SOL_SOCKET, SO_BROADCAST, (unsigned int *) &on,
1297                         sizeof(on));
1298        if (res < 0) {
1299                syslog(LOG_ERR, "cannot set broadcast socket\n");
1300                return false;
1301        }
1302        memset(&local, 0, sizeof(local));
1303        local.sin_family = AF_INET;
1304        local.sin_port = htons(PUERTO_WAKEUP);
1305        local.sin_addr.s_addr = htonl(INADDR_ANY);
1306
1307        for (i = 0; i < lon; i++) {
1308                if (!WakeUp(s, ptrIP[i], ptrMacs[i], mar)) {
1309                        syslog(LOG_ERR, "problem sending magic packet\n");
1310                        close(s);
1311                        return false;
1312                }
1313        }
1314        close(s);
1315        return true;
1316}
1317
1318#define OG_WOL_SEQUENCE         6
1319#define OG_WOL_MACADDR_LEN      6
1320#define OG_WOL_REPEAT           16
1321
1322struct wol_msg {
1323        char secuencia_FF[OG_WOL_SEQUENCE];
1324        char macbin[OG_WOL_REPEAT][OG_WOL_MACADDR_LEN];
1325};
1326
1327static bool wake_up_broadcast(int sd, struct sockaddr_in *client,
1328                              const struct wol_msg *msg)
1329{
1330        struct sockaddr_in *broadcast_addr;
1331        struct ifaddrs *ifaddr, *ifa;
1332        int ret;
1333
1334        if (getifaddrs(&ifaddr) < 0) {
1335                syslog(LOG_ERR, "cannot get list of addresses\n");
1336                return false;
1337        }
1338
1339        client->sin_addr.s_addr = htonl(INADDR_BROADCAST);
1340
1341        for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
1342                if (ifa->ifa_addr == NULL ||
1343                    ifa->ifa_addr->sa_family != AF_INET ||
1344                    strcmp(ifa->ifa_name, interface) != 0)
1345                        continue;
1346
1347                broadcast_addr =
1348                        (struct sockaddr_in *)ifa->ifa_ifu.ifu_broadaddr;
1349                client->sin_addr.s_addr = broadcast_addr->sin_addr.s_addr;
1350                break;
1351        }
1352        freeifaddrs(ifaddr);
1353
1354        ret = sendto(sd, msg, sizeof(*msg), 0,
1355                     (struct sockaddr *)client, sizeof(*client));
1356        if (ret < 0) {
1357                syslog(LOG_ERR, "failed to send broadcast wol\n");
1358                return false;
1359        }
1360
1361        return true;
1362}
1363
1364static bool wake_up_unicast(int sd, struct sockaddr_in *client,
1365                            const struct wol_msg *msg,
1366                            const struct in_addr *addr)
1367{
1368        int ret;
1369
1370        client->sin_addr.s_addr = addr->s_addr;
1371
1372        ret = sendto(sd, msg, sizeof(*msg), 0,
1373                     (struct sockaddr *)client, sizeof(*client));
1374        if (ret < 0) {
1375                syslog(LOG_ERR, "failed to send unicast wol\n");
1376                return false;
1377        }
1378
1379        return true;
1380}
1381
1382enum wol_delivery_type {
1383        OG_WOL_BROADCAST = 1,
1384        OG_WOL_UNICAST = 2
1385};
1386
1387//_____________________________________________________________________________________________________________
1388// Función: WakeUp
1389//
1390//       Descripción:
1391//              Enciende el ordenador cuya MAC se pasa como parámetro
1392//      Parámetros:
1393//              - s : Socket para enviar trama magic packet
1394//              - iph : Cadena con la dirección ip
1395//              - mac : Cadena con la dirección mac en formato XXXXXXXXXXXX
1396//              - mar: Método de arranque (1=Broadcast, 2=Unicast)
1397//      Devuelve:
1398//              true: Si el proceso es correcto
1399//              false: En caso de ocurrir algún error
1400//_____________________________________________________________________________________________________________
1401//
1402bool WakeUp(int s, char* iph, char *mac, char *mar)
1403{
1404        unsigned int macaddr[OG_WOL_MACADDR_LEN];
1405        char HDaddress_bin[OG_WOL_MACADDR_LEN];
1406        struct sockaddr_in WakeUpCliente;
1407        struct wol_msg Trama_WakeUp;
1408        struct in_addr addr;
1409        bool ret;
1410        int i;
1411
1412        for (i = 0; i < 6; i++) // Primera secuencia de la trama Wake Up (0xFFFFFFFFFFFF)
1413                Trama_WakeUp.secuencia_FF[i] = 0xFF;
1414
1415        sscanf(mac, "%02x%02x%02x%02x%02x%02x",
1416               &macaddr[0], &macaddr[1], &macaddr[2],
1417               &macaddr[3], &macaddr[4], &macaddr[5]);
1418
1419        for (i = 0; i < 6; i++)
1420                HDaddress_bin[i] = (uint8_t)macaddr[i];
1421
1422        for (i = 0; i < 16; i++) // Segunda secuencia de la trama Wake Up , repetir 16 veces su la MAC
1423                memcpy(&Trama_WakeUp.macbin[i][0], &HDaddress_bin, 6);
1424
1425        /* Creación de socket del cliente que recibe la trama magic packet */
1426        WakeUpCliente.sin_family = AF_INET;
1427        WakeUpCliente.sin_port = htons((short) PUERTO_WAKEUP);
1428
1429        switch (atoi(mar)) {
1430        case OG_WOL_BROADCAST:
1431                ret = wake_up_broadcast(s, &WakeUpCliente, &Trama_WakeUp);
1432                break;
1433        case OG_WOL_UNICAST:
1434                if (inet_aton(iph, &addr) < 0) {
1435                        syslog(LOG_ERR, "bad IP address for unicast wol\n");
1436                        ret = false;
1437                        break;
1438                }
1439                ret = wake_up_unicast(s, &WakeUpCliente, &Trama_WakeUp, &addr);
1440                break;
1441        default:
1442                syslog(LOG_ERR, "unknown wol type\n");
1443                ret = false;
1444                break;
1445        }
1446        return ret;
1447}
1448// ________________________________________________________________________________________________________
1449// Función: RESPUESTA_Arrancar
1450//
1451//      Descripción:
1452//              Respuesta del cliente al comando Arrancar
1453//      Parámetros:
1454//              - socket_c: Socket del cliente que envió el mensaje
1455//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1456//      Devuelve:
1457//              true: Si el proceso es correcto
1458//              false: En caso de ocurrir algún error
1459// ________________________________________________________________________________________________________
1460static bool RESPUESTA_Arrancar(TRAMA* ptrTrama, struct og_client *cli)
1461{
1462        struct og_dbi *dbi;
1463        char *iph, *ido;
1464        char *tpc;
1465        int i;
1466
1467        dbi = og_dbi_open(&dbi_config);
1468        if (!dbi) {
1469                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
1470                       __func__, __LINE__);
1471                return false;
1472        }
1473
1474        iph = copiaParametro("iph",ptrTrama); // Toma dirección ip
1475        ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
1476
1477        if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) {
1478                liberaMemoria(iph);
1479                liberaMemoria(ido);
1480                syslog(LOG_ERR, "failed to register notification\n");
1481                og_dbi_close(dbi);
1482                return false;
1483        }
1484
1485        tpc = copiaParametro("tpc",ptrTrama); // Tipo de cliente (Plataforma y S.O.)
1486        if (clienteExistente(iph, &i)) // Actualiza estado
1487                strcpy(tbsockets[i].estado, tpc);
1488
1489        liberaMemoria(iph);
1490        liberaMemoria(ido);
1491        liberaMemoria(tpc);
1492        og_dbi_close(dbi);
1493
1494        return true;
1495}
1496// ________________________________________________________________________________________________________
1497// Función: RESPUESTA_Apagar
1498//
1499//      Descripción:
1500//              Respuesta del cliente al comando Apagar
1501//      Parámetros:
1502//              - socket_c: Socket del cliente que envió el mensaje
1503//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1504//      Devuelve:
1505//              true: Si el proceso es correcto
1506//              false: En caso de ocurrir algún error
1507// ________________________________________________________________________________________________________
1508static bool RESPUESTA_Apagar(TRAMA* ptrTrama, struct og_client *cli)
1509{
1510        struct og_dbi *dbi;
1511        char *iph, *ido;
1512        int i;
1513
1514        dbi = og_dbi_open(&dbi_config);
1515        if (!dbi) {
1516                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
1517                       __func__, __LINE__);
1518                return false;
1519        }
1520
1521        iph = copiaParametro("iph",ptrTrama); // Toma dirección ip
1522        ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
1523
1524        if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) {
1525                liberaMemoria(iph);
1526                liberaMemoria(ido);
1527                syslog(LOG_ERR, "failed to register notification\n");
1528                og_dbi_close(dbi);
1529                return false; // Error al registrar notificacion
1530        }
1531
1532        if (clienteExistente(iph, &i)) // Actualiza estado
1533                strcpy(tbsockets[i].estado, CLIENTE_APAGADO);
1534
1535        liberaMemoria(iph);
1536        liberaMemoria(ido);
1537        og_dbi_close(dbi);
1538
1539        return true;
1540}
1541// ________________________________________________________________________________________________________
1542// Función: RESPUESTA_CrearImagen
1543//
1544//      Descripción:
1545//              Respuesta del cliente al comando CrearImagen
1546//      Parámetros:
1547//              - socket_c: Socket del cliente que envió el mensaje
1548//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1549//      Devuelve:
1550//              true: Si el proceso es correcto
1551//              false: En caso de ocurrir algún error
1552// ________________________________________________________________________________________________________
1553static bool RESPUESTA_CrearImagen(TRAMA* ptrTrama, struct og_client *cli)
1554{
1555        char *iph, *dsk, *par, *cpt, *ipr, *ido;
1556        struct og_dbi *dbi;
1557        char *idi;
1558        bool res;
1559
1560        dbi = og_dbi_open(&dbi_config);
1561        if (!dbi) {
1562                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
1563                       __func__, __LINE__);
1564                return false;
1565        }
1566
1567        iph = copiaParametro("iph",ptrTrama); // Toma dirección ip
1568        ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
1569
1570        if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) {
1571                liberaMemoria(iph);
1572                liberaMemoria(ido);
1573                syslog(LOG_ERR, "failed to register notification\n");
1574                og_dbi_close(dbi);
1575                return false; // Error al registrar notificacion
1576        }
1577
1578        // Acciones posteriores
1579        idi = copiaParametro("idi",ptrTrama);
1580        dsk = copiaParametro("dsk",ptrTrama);
1581        par = copiaParametro("par",ptrTrama);
1582        cpt = copiaParametro("cpt",ptrTrama);
1583        ipr = copiaParametro("ipr",ptrTrama);
1584
1585        res=actualizaCreacionImagen(dbi, idi, dsk, par, cpt, ipr, ido);
1586
1587        liberaMemoria(idi);
1588        liberaMemoria(par);
1589        liberaMemoria(cpt);
1590        liberaMemoria(ipr);
1591        og_dbi_close(dbi);
1592
1593        if (!res)
1594                syslog(LOG_ERR, "Problem processing update\n");
1595
1596        return res;
1597}
1598// ________________________________________________________________________________________________________
1599// Función: actualizaCreacionImagen
1600//
1601//      Descripción:
1602//              Esta función actualiza la base de datos con el resultado de la creación de una imagen
1603//      Parámetros:
1604//              - db: Objeto base de datos (ya operativo)
1605//              - tbl: Objeto tabla
1606//              - idi: Identificador de la imagen
1607//              - dsk: Disco de donde se creó
1608//              - par: Partición de donde se creó
1609//              - cpt: Código de partición
1610//              - ipr: Ip del repositorio
1611//              - ido: Identificador del ordenador modelo
1612//      Devuelve:
1613//              true: Si el proceso es correcto
1614//              false: En caso de ocurrir algún error
1615// ________________________________________________________________________________________________________
1616bool actualizaCreacionImagen(struct og_dbi *dbi, char *idi, char *dsk,
1617                             char *par, char *cpt, char *ipr, char *ido)
1618{
1619        const char *msglog;
1620        dbi_result result;
1621        int idr,ifs;
1622
1623        /* Toma identificador del repositorio correspondiente al ordenador modelo */
1624        result = dbi_conn_queryf(dbi->conn,
1625                        "SELECT repositorios.idrepositorio"
1626                        "  FROM repositorios"
1627                        "  LEFT JOIN ordenadores USING (idrepositorio)"
1628                        " WHERE repositorios.ip='%s' AND ordenadores.idordenador=%s", ipr, ido);
1629
1630        if (!result) {
1631                dbi_conn_error(dbi->conn, &msglog);
1632                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1633                       __func__, __LINE__, msglog);
1634                return false;
1635        }
1636        if (!dbi_result_next_row(result)) {
1637                syslog(LOG_ERR,
1638                       "repository does not exist in database (%s:%d)\n",
1639                       __func__, __LINE__);
1640                dbi_result_free(result);
1641                return false;
1642        }
1643        idr = dbi_result_get_uint(result, "idrepositorio");
1644        dbi_result_free(result);
1645
1646        /* Toma identificador del perfilsoftware */
1647        result = dbi_conn_queryf(dbi->conn,
1648                        "SELECT idperfilsoft"
1649                        "  FROM ordenadores_particiones"
1650                        " WHERE idordenador=%s AND numdisk=%s AND numpar=%s", ido, dsk, par);
1651
1652        if (!result) {
1653                dbi_conn_error(dbi->conn, &msglog);
1654                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1655                       __func__, __LINE__, msglog);
1656                return false;
1657        }
1658        if (!dbi_result_next_row(result)) {
1659                syslog(LOG_ERR,
1660                       "software profile does not exist in database (%s:%d)\n",
1661                       __func__, __LINE__);
1662                dbi_result_free(result);
1663                return false;
1664        }
1665        ifs = dbi_result_get_uint(result, "idperfilsoft");
1666        dbi_result_free(result);
1667
1668        /* Actualizar los datos de la imagen */
1669        result = dbi_conn_queryf(dbi->conn,
1670                "UPDATE imagenes"
1671                "   SET idordenador=%s, numdisk=%s, numpar=%s, codpar=%s,"
1672                "       idperfilsoft=%d, idrepositorio=%d,"
1673                "       fechacreacion=NOW(), revision=revision+1"
1674                " WHERE idimagen=%s", ido, dsk, par, cpt, ifs, idr, idi);
1675
1676        if (!result) {
1677                dbi_conn_error(dbi->conn, &msglog);
1678                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1679                       __func__, __LINE__, msglog);
1680                return false;
1681        }
1682        dbi_result_free(result);
1683
1684        /* Actualizar los datos en el cliente */
1685        result = dbi_conn_queryf(dbi->conn,
1686                "UPDATE ordenadores_particiones"
1687                "   SET idimagen=%s, revision=(SELECT revision FROM imagenes WHERE idimagen=%s),"
1688                "       fechadespliegue=NOW()"
1689                " WHERE idordenador=%s AND numdisk=%s AND numpar=%s",
1690                idi, idi, ido, dsk, par);
1691        if (!result) {
1692                dbi_conn_error(dbi->conn, &msglog);
1693                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1694                       __func__, __LINE__, msglog);
1695                return false;
1696        }
1697        dbi_result_free(result);
1698
1699        return true;
1700}
1701// ________________________________________________________________________________________________________
1702// Función: RESPUESTA_CrearImagenBasica
1703//
1704//      Descripción:
1705//              Respuesta del cliente al comando CrearImagenBasica
1706//      Parámetros:
1707//              - socket_c: Socket del cliente que envió el mensaje
1708//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1709//      Devuelve:
1710//              true: Si el proceso es correcto
1711//              false: En caso de ocurrir algún error
1712// ________________________________________________________________________________________________________
1713static bool RESPUESTA_CrearImagenBasica(TRAMA* ptrTrama, struct og_client *cli)
1714{
1715        // La misma respuesta que la creación de imagen monolítica
1716        return RESPUESTA_CrearImagen(ptrTrama, cli);
1717}
1718// ________________________________________________________________________________________________________
1719// Función: RESPUESTA_CrearSoftIncremental
1720//
1721//      Descripción:
1722//              Respuesta del cliente al comando crearImagenDiferencial
1723//      Parámetros:
1724//              - socket_c: Socket del cliente que envió el mensaje
1725//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1726//      Devuelve:
1727//              true: Si el proceso es correcto
1728//              false: En caso de ocurrir algún error
1729// ________________________________________________________________________________________________________
1730static bool RESPUESTA_CrearSoftIncremental(TRAMA* ptrTrama, struct og_client *cli)
1731{
1732        char *iph,*par,*ido,*idf;
1733        int ifs;
1734        const char *msglog;
1735        struct og_dbi *dbi;
1736        dbi_result result;
1737
1738        dbi = og_dbi_open(&dbi_config);
1739        if (!dbi) {
1740                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
1741                       __func__, __LINE__);
1742                return false;
1743        }
1744
1745        iph = copiaParametro("iph",ptrTrama); // Toma dirección ip
1746        ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
1747
1748        if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) {
1749                og_dbi_close(dbi);
1750                liberaMemoria(iph);
1751                liberaMemoria(ido);
1752                syslog(LOG_ERR, "failed to register notification\n");
1753                return false;
1754        }
1755
1756        par = copiaParametro("par",ptrTrama);
1757
1758        /* Toma identificador del perfilsoftware creado por el inventario de software */
1759        result = dbi_conn_queryf(dbi->conn,
1760                                 "SELECT idperfilsoft FROM ordenadores_particiones WHERE idordenador=%s AND numpar=%s",
1761                                 ido, par);
1762        liberaMemoria(iph);
1763        liberaMemoria(ido);     
1764        liberaMemoria(par);     
1765
1766        if (!result) {
1767                dbi_conn_error(dbi->conn, &msglog);
1768                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1769                       __func__, __LINE__, msglog);
1770                og_dbi_close(dbi);
1771                return false;
1772        }
1773        if (!dbi_result_next_row(result)) {
1774                syslog(LOG_ERR,
1775                       "software profile does not exist in database (%s:%d)\n",
1776                       __func__, __LINE__);
1777                dbi_result_free(result);
1778                og_dbi_close(dbi);
1779                return false;
1780        }
1781        ifs = dbi_result_get_uint(result, "idperfilsoft");
1782        dbi_result_free(result);
1783
1784        /* Actualizar los datos de la imagen */
1785        idf = copiaParametro("idf", ptrTrama);
1786        result = dbi_conn_queryf(dbi->conn,
1787                                 "UPDATE imagenes SET idperfilsoft=%d WHERE idimagen=%s",
1788                                 ifs, idf);
1789        liberaMemoria(idf);     
1790
1791        if (!result) {
1792                dbi_conn_error(dbi->conn, &msglog);
1793                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1794                       __func__, __LINE__, msglog);
1795                og_dbi_close(dbi);
1796                return false;
1797        }
1798        dbi_result_free(result);
1799
1800        og_dbi_close(dbi);
1801
1802        return true;
1803}
1804// ________________________________________________________________________________________________________
1805// Función: RESPUESTA_RestaurarImagen
1806//
1807//      Descripción:
1808//              Respuesta del cliente al comando RestaurarImagen
1809//      Parámetros:
1810//              - socket_c: Socket del cliente que envió el mensaje
1811//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1812//      Devuelve:
1813//              true: Si el proceso es correcto
1814//              false: En caso de ocurrir algún error
1815// ________________________________________________________________________________________________________
1816//
1817static bool RESPUESTA_RestaurarImagen(TRAMA* ptrTrama, struct og_client *cli)
1818{
1819        bool res;
1820        char *iph, *ido, *idi, *dsk, *par, *ifs, *cfg;
1821        struct og_dbi *dbi;
1822
1823        dbi = og_dbi_open(&dbi_config);
1824        if (!dbi) {
1825                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
1826                       __func__, __LINE__);
1827                return false;
1828        }
1829
1830        iph = copiaParametro("iph",ptrTrama); // Toma dirección ip
1831        ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
1832
1833        if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) {
1834                og_dbi_close(dbi);
1835                liberaMemoria(iph);
1836                liberaMemoria(ido);
1837                syslog(LOG_ERR, "failed to register notification\n");
1838                return false;
1839        }
1840
1841        // Acciones posteriores
1842        idi = copiaParametro("idi",ptrTrama); // Toma identificador de la imagen
1843        dsk = copiaParametro("dsk",ptrTrama); // Número de disco
1844        par = copiaParametro("par",ptrTrama); // Número de partición
1845        ifs = copiaParametro("ifs",ptrTrama); // Identificador del perfil software contenido
1846        cfg = copiaParametro("cfg",ptrTrama); // Configuración de discos
1847        if(cfg){
1848                actualizaConfiguracion(dbi, cfg, atoi(ido)); // Actualiza la configuración del ordenador
1849                liberaMemoria(cfg);     
1850        }
1851        res=actualizaRestauracionImagen(dbi, idi, dsk, par, ido, ifs);
1852       
1853        liberaMemoria(iph);
1854        liberaMemoria(ido);
1855        liberaMemoria(idi);
1856        liberaMemoria(par);
1857        liberaMemoria(ifs);
1858        og_dbi_close(dbi);
1859
1860        if(!res)
1861                syslog(LOG_ERR, "Problem after restoring image\n");
1862
1863        return res;
1864}
1865// ________________________________________________________________________________________________________
1866//
1867// Función: RESPUESTA_RestaurarImagenBasica
1868//
1869//      Descripción:
1870//              Respuesta del cliente al comando RestaurarImagen
1871//      Parámetros:
1872//              - socket_c: Socket del cliente que envió el mensaje
1873//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1874//      Devuelve:
1875//              true: Si el proceso es correcto
1876//              false: En caso de ocurrir algún error
1877// ________________________________________________________________________________________________________
1878//
1879static bool RESPUESTA_RestaurarImagenBasica(TRAMA* ptrTrama, struct og_client *cli)
1880{
1881        return RESPUESTA_RestaurarImagen(ptrTrama, cli);
1882}
1883// ________________________________________________________________________________________________________
1884// Función: RESPUESTA_RestaurarSoftIncremental
1885//
1886//      Descripción:
1887//              Respuesta del cliente al comando RestaurarSoftIncremental
1888//      Parámetros:
1889//              - socket_c: Socket del cliente que envió el mensaje
1890//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1891//      Devuelve:
1892//              true: Si el proceso es correcto
1893//              false: En caso de ocurrir algún error
1894// ________________________________________________________________________________________________________
1895static bool RESPUESTA_RestaurarSoftIncremental(TRAMA* ptrTrama, struct og_client *cli)
1896{
1897        return RESPUESTA_RestaurarImagen(ptrTrama, cli);
1898}
1899// ________________________________________________________________________________________________________
1900// Función: actualizaRestauracionImagen
1901//
1902//      Descripción:
1903//              Esta función actualiza la base de datos con el resultado de la restauración de una imagen
1904//      Parámetros:
1905//              - db: Objeto base de datos (ya operativo)
1906//              - tbl: Objeto tabla
1907//              - idi: Identificador de la imagen
1908//              - dsk: Disco de donde se restauró
1909//              - par: Partición de donde se restauró
1910//              - ido: Identificador del cliente donde se restauró
1911//              - ifs: Identificador del perfil software contenido      en la imagen
1912//      Devuelve:
1913//              true: Si el proceso es correcto
1914//              false: En caso de ocurrir algún error
1915// ________________________________________________________________________________________________________
1916bool actualizaRestauracionImagen(struct og_dbi *dbi, char *idi,
1917                                 char *dsk, char *par, char *ido, char *ifs)
1918{
1919        const char *msglog;
1920        dbi_result result;
1921
1922        /* Actualizar los datos de la imagen */
1923        result = dbi_conn_queryf(dbi->conn,
1924                        "UPDATE ordenadores_particiones"
1925                        "   SET idimagen=%s, idperfilsoft=%s, fechadespliegue=NOW(),"
1926                        "       revision=(SELECT revision FROM imagenes WHERE idimagen=%s),"
1927                        "       idnombreso=IFNULL((SELECT idnombreso FROM perfilessoft WHERE idperfilsoft=%s),0)"
1928                        " WHERE idordenador=%s AND numdisk=%s AND numpar=%s", idi, ifs, idi, ifs, ido, dsk, par);
1929
1930        if (!result) {
1931                dbi_conn_error(dbi->conn, &msglog);
1932                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1933                       __func__, __LINE__, msglog);
1934                return false;
1935        }
1936        dbi_result_free(result);
1937
1938        return true;
1939}
1940// ________________________________________________________________________________________________________
1941// Función: RESPUESTA_EjecutarScript
1942//
1943//      Descripción:
1944//              Respuesta del cliente al comando EjecutarScript
1945//      Parámetros:
1946//              - socket_c: Socket del cliente que envió el mensaje
1947//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1948//      Devuelve:
1949//              true: Si el proceso es correcto
1950//              false: En caso de ocurrir algún error
1951// ________________________________________________________________________________________________________
1952static bool RESPUESTA_EjecutarScript(TRAMA* ptrTrama, struct og_client *cli)
1953{
1954        char *iph, *ido,*cfg;
1955        struct og_dbi *dbi;
1956        bool res = true;
1957
1958        dbi = og_dbi_open(&dbi_config);
1959        if (!dbi) {
1960                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
1961                       __func__, __LINE__);
1962                return false;
1963        }
1964
1965        iph = copiaParametro("iph",ptrTrama); // Toma dirección ip
1966        ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
1967
1968        if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) {
1969                og_dbi_close(dbi);
1970                liberaMemoria(iph);
1971                liberaMemoria(ido);
1972                syslog(LOG_ERR, "failed to register notification\n");
1973                return false;
1974        }
1975       
1976        cfg = copiaParametro("cfg",ptrTrama); // Toma configuración de particiones
1977        if(cfg){
1978                res = actualizaConfiguracion(dbi, cfg, atoi(ido)); // Actualiza la configuración del ordenador
1979                liberaMemoria(cfg);     
1980        }
1981
1982        liberaMemoria(iph);
1983        liberaMemoria(ido);
1984        og_dbi_close(dbi);
1985
1986        if (!res)
1987                syslog(LOG_ERR, "Problem updating client configuration\n");
1988
1989        return res;
1990}
1991// ________________________________________________________________________________________________________
1992// Función: RESPUESTA_InventarioHardware
1993//
1994//      Descripción:
1995//              Respuesta del cliente al comando InventarioHardware
1996//      Parámetros:
1997//              - socket_c: Socket del cliente que envió el mensaje
1998//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1999//      Devuelve:
2000//              true: Si el proceso es correcto
2001//              false: En caso de ocurrir algún error
2002// ________________________________________________________________________________________________________
2003static bool RESPUESTA_InventarioHardware(TRAMA* ptrTrama, struct og_client *cli)
2004{
2005        bool res;
2006        char *iph, *ido, *idc, *npc, *hrd, *buffer;
2007        struct og_dbi *dbi;
2008
2009        dbi = og_dbi_open(&dbi_config);
2010        if (!dbi) {
2011                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
2012                       __func__, __LINE__);
2013                return false;
2014        }
2015
2016        iph = copiaParametro("iph",ptrTrama); // Toma dirección ip del cliente
2017        ido = copiaParametro("ido",ptrTrama); // Toma identificador del cliente
2018
2019        if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) {
2020                og_dbi_close(dbi);
2021                liberaMemoria(iph);
2022                liberaMemoria(ido);
2023                syslog(LOG_ERR, "failed to register notification\n");
2024                return false;
2025        }
2026        // Lee archivo de inventario enviado anteriormente
2027        hrd = copiaParametro("hrd",ptrTrama);
2028        buffer = rTrim(leeArchivo(hrd));
2029       
2030        npc = copiaParametro("npc",ptrTrama);
2031        idc = copiaParametro("idc",ptrTrama); // Toma identificador del Centro
2032       
2033        if (buffer)
2034                res=actualizaHardware(dbi, buffer, ido, npc, idc);
2035        else
2036                res = false;
2037
2038        liberaMemoria(iph);
2039        liberaMemoria(ido);                     
2040        liberaMemoria(npc);                     
2041        liberaMemoria(idc);             
2042        liberaMemoria(buffer);         
2043        og_dbi_close(dbi);
2044
2045        if (!res)
2046                syslog(LOG_ERR, "Problem updating client configuration\n");
2047
2048        return res;
2049}
2050// ________________________________________________________________________________________________________
2051// Función: actualizaHardware
2052//
2053//              Descripción:
2054//                      Actualiza la base de datos con la configuracion hardware del cliente
2055//              Parámetros:
2056//                      - db: Objeto base de datos (ya operativo)
2057//                      - tbl: Objeto tabla
2058//                      - hrd: cadena con el inventario hardware
2059//                      - ido: Identificador del ordenador
2060//                      - npc: Nombre del ordenador
2061//                      - idc: Identificador del centro o Unidad organizativa
2062// ________________________________________________________________________________________________________
2063//
2064bool actualizaHardware(struct og_dbi *dbi, char *hrd, char *ido, char *npc,
2065                       char *idc)
2066{
2067        const char *msglog;
2068        int idtipohardware, idperfilhard;
2069        int lon, i, j, aux;
2070        bool retval;
2071        char *whard;
2072        int tbidhardware[MAXHARDWARE];
2073        char *tbHardware[MAXHARDWARE],*dualHardware[2], strInt[LONINT], *idhardwares;
2074        dbi_result result;
2075
2076        /* Toma Centro (Unidad Organizativa) */
2077        result = dbi_conn_queryf(dbi->conn,
2078                                 "SELECT idperfilhard FROM ordenadores WHERE idordenador=%s",
2079                                 ido);
2080        if (!result) {
2081                dbi_conn_error(dbi->conn, &msglog);
2082                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2083                       __func__, __LINE__, msglog);
2084                return false;
2085        }
2086        if (!dbi_result_next_row(result)) {
2087                syslog(LOG_ERR, "client does not exist in database (%s:%d)\n",
2088                       __func__, __LINE__);
2089                dbi_result_free(result);
2090                return false;
2091        }
2092        idperfilhard = dbi_result_get_uint(result, "idperfilhard");
2093        dbi_result_free(result);
2094
2095        whard=escaparCadena(hrd); // Codificar comillas simples
2096        if(!whard)
2097                return false;
2098        /* Recorre componentes hardware*/
2099        lon = splitCadena(tbHardware, whard, '\n');
2100        if (lon > MAXHARDWARE)
2101                lon = MAXHARDWARE; // Limita el número de componentes hardware
2102        /*
2103         for (i=0;i<lon;i++){
2104         sprintf(msglog,"Linea de inventario: %s",tbHardware[i]);
2105         RegistraLog(msglog,false);
2106         }
2107         */
2108        for (i = 0; i < lon; i++) {
2109                splitCadena(dualHardware, rTrim(tbHardware[i]), '=');
2110                //sprintf(msglog,"nemonico: %s",dualHardware[0]);
2111                //RegistraLog(msglog,false);
2112                //sprintf(msglog,"valor: %s",dualHardware[1]);
2113                //RegistraLog(msglog,false);
2114                result = dbi_conn_queryf(dbi->conn,
2115                                         "SELECT idtipohardware,descripcion FROM tipohardwares WHERE nemonico='%s'",
2116                                         dualHardware[0]);
2117                if (!result) {
2118                        dbi_conn_error(dbi->conn, &msglog);
2119                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2120                               __func__, __LINE__, msglog);
2121                        return false;
2122                }
2123                if (!dbi_result_next_row(result)) { //  Tipo de Hardware NO existente
2124                        dbi_result_free(result);
2125                        return false;
2126                } else { //  Tipo de Hardware Existe
2127                        idtipohardware = dbi_result_get_uint(result, "idtipohardware");
2128                        dbi_result_free(result);
2129
2130                        result = dbi_conn_queryf(dbi->conn,
2131                                                 "SELECT idhardware FROM hardwares WHERE idtipohardware=%d AND descripcion='%s'",
2132                                                 idtipohardware, dualHardware[1]);
2133
2134                        if (!result) {
2135                                dbi_conn_error(dbi->conn, &msglog);
2136                                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2137                                       __func__, __LINE__, msglog);
2138                                return false;
2139                        }
2140
2141                        if (!dbi_result_next_row(result)) { //  Hardware NO existente
2142                                dbi_result_free(result);
2143                                result = dbi_conn_queryf(dbi->conn,
2144                                                        "INSERT hardwares (idtipohardware,descripcion,idcentro,grupoid) "
2145                                                        " VALUES(%d,'%s',%s,0)", idtipohardware,
2146                                                dualHardware[1], idc);
2147                                if (!result) {
2148                                        dbi_conn_error(dbi->conn, &msglog);
2149                                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2150                                               __func__, __LINE__, msglog);
2151                                        return false;
2152                                }
2153
2154                                // Recupera el identificador del hardware
2155                                tbidhardware[i] = dbi_conn_sequence_last(dbi->conn, NULL);
2156                        } else {
2157                                tbidhardware[i] = dbi_result_get_uint(result, "idhardware");
2158                        }
2159                        dbi_result_free(result);
2160                }
2161        }
2162        // Ordena tabla de identificadores para cosultar si existe un pefil con esas especificaciones
2163
2164        for (i = 0; i < lon - 1; i++) {
2165                for (j = i + 1; j < lon; j++) {
2166                        if (tbidhardware[i] > tbidhardware[j]) {
2167                                aux = tbidhardware[i];
2168                                tbidhardware[i] = tbidhardware[j];
2169                                tbidhardware[j] = aux;
2170                        }
2171                }
2172        }
2173        /* Crea cadena de identificadores de componentes hardware separados por coma */
2174        sprintf(strInt, "%d", tbidhardware[lon - 1]); // Pasa a cadena el último identificador que es de mayor longitud
2175        aux = strlen(strInt); // Calcula longitud de cadena para reservar espacio a todos los perfiles
2176        idhardwares = reservaMemoria(sizeof(aux) * lon + lon);
2177        if (idhardwares == NULL) {
2178                syslog(LOG_ERR, "%s:%d OOM\n", __FILE__, __LINE__);
2179                return false;
2180        }
2181        aux = sprintf(idhardwares, "%d", tbidhardware[0]);
2182        for (i = 1; i < lon; i++)
2183                aux += sprintf(idhardwares + aux, ",%d", tbidhardware[i]);
2184
2185        if (!cuestionPerfilHardware(dbi, idc, ido, idperfilhard, idhardwares,
2186                        npc, tbidhardware, lon)) {
2187                syslog(LOG_ERR, "Problem updating client hardware\n");
2188                retval=false;
2189        }
2190        else {
2191                retval=true;
2192        }
2193        liberaMemoria(whard);
2194        liberaMemoria(idhardwares);
2195        return (retval);
2196}
2197// ________________________________________________________________________________________________________
2198// Función: cuestionPerfilHardware
2199//
2200//              Descripción:
2201//                      Comprueba existencia de perfil hardware y actualización de éste para el ordenador
2202//              Parámetros:
2203//                      - db: Objeto base de datos (ya operativo)
2204//                      - tbl: Objeto tabla
2205//                      - idc: Identificador de la Unidad organizativa donde se encuentra el cliente
2206//                      - ido: Identificador del ordenador
2207//                      - tbidhardware: Identificador del tipo de hardware
2208//                      - con: Número de componentes detectados para configurar un el perfil hardware
2209//                      - npc: Nombre del cliente
2210// ________________________________________________________________________________________________________
2211bool cuestionPerfilHardware(struct og_dbi *dbi, char *idc, char *ido,
2212                int idperfilhardware, char *idhardwares, char *npc, int *tbidhardware,
2213                int lon)
2214{
2215        const char *msglog;
2216        dbi_result result;
2217        int i;
2218        int nwidperfilhard;
2219
2220        // Busca perfil hard del ordenador que contenga todos los componentes hardware encontrados
2221        result = dbi_conn_queryf(dbi->conn,
2222                "SELECT idperfilhard FROM"
2223                " (SELECT perfileshard_hardwares.idperfilhard as idperfilhard,"
2224                "       group_concat(cast(perfileshard_hardwares.idhardware AS char( 11) )"
2225                "       ORDER BY perfileshard_hardwares.idhardware SEPARATOR ',' ) AS idhardwares"
2226                " FROM  perfileshard_hardwares"
2227                " GROUP BY perfileshard_hardwares.idperfilhard) AS temp"
2228                " WHERE idhardwares LIKE '%s'", idhardwares);
2229
2230        if (!result) {
2231                dbi_conn_error(dbi->conn, &msglog);
2232                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2233                       __func__, __LINE__, msglog);
2234                return false;
2235        }
2236        if (!dbi_result_next_row(result)) {
2237                // No existe un perfil hardware con esos componentes de componentes hardware, lo crea
2238                dbi_result_free(result);
2239                result = dbi_conn_queryf(dbi->conn,
2240                                "INSERT perfileshard  (descripcion,idcentro,grupoid)"
2241                                " VALUES('Perfil hardware (%s) ',%s,0)", npc, idc);
2242                if (!result) {
2243                        dbi_conn_error(dbi->conn, &msglog);
2244                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2245                               __func__, __LINE__, msglog);
2246                        return false;
2247                }
2248                dbi_result_free(result);
2249
2250                // Recupera el identificador del nuevo perfil hardware
2251                nwidperfilhard = dbi_conn_sequence_last(dbi->conn, NULL);
2252
2253                // Crea la relación entre perfiles y componenetes hardware
2254                for (i = 0; i < lon; i++) {
2255                        result = dbi_conn_queryf(dbi->conn,
2256                                        "INSERT perfileshard_hardwares  (idperfilhard,idhardware)"
2257                                                " VALUES(%d,%d)", nwidperfilhard, tbidhardware[i]);
2258                        if (!result) {
2259                                dbi_conn_error(dbi->conn, &msglog);
2260                                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2261                                       __func__, __LINE__, msglog);
2262                                return false;
2263                        }
2264                        dbi_result_free(result);
2265                }
2266        } else { // Existe un perfil con todos esos componentes
2267                nwidperfilhard = dbi_result_get_uint(result, "idperfilhard");
2268                dbi_result_free(result);
2269        }
2270        if (idperfilhardware != nwidperfilhard) { // No coinciden los perfiles
2271                // Actualiza el identificador del perfil hardware del ordenador
2272                result = dbi_conn_queryf(dbi->conn,
2273                        "UPDATE ordenadores SET idperfilhard=%d"
2274                        " WHERE idordenador=%s", nwidperfilhard, ido);
2275                if (!result) {
2276                        dbi_conn_error(dbi->conn, &msglog);
2277                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2278                               __func__, __LINE__, msglog);
2279                        return false;
2280                }
2281                dbi_result_free(result);
2282        }
2283        /* Eliminar Relación de hardwares con Perfiles hardware que quedan húerfanos */
2284        result = dbi_conn_queryf(dbi->conn,
2285                "DELETE FROM perfileshard_hardwares WHERE idperfilhard IN "
2286                " (SELECT idperfilhard FROM perfileshard WHERE idperfilhard NOT IN"
2287                " (SELECT DISTINCT idperfilhard from ordenadores))");
2288        if (!result) {
2289                dbi_conn_error(dbi->conn, &msglog);
2290                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2291                       __func__, __LINE__, msglog);
2292                return false;
2293        }
2294        dbi_result_free(result);
2295
2296        /* Eliminar Perfiles hardware que quedan húerfanos */
2297        result = dbi_conn_queryf(dbi->conn,
2298                        "DELETE FROM perfileshard WHERE idperfilhard NOT IN"
2299                        " (SELECT DISTINCT idperfilhard FROM ordenadores)");
2300        if (!result) {
2301                dbi_conn_error(dbi->conn, &msglog);
2302                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2303                       __func__, __LINE__, msglog);
2304                return false;
2305        }
2306        dbi_result_free(result);
2307
2308        /* Eliminar Relación de hardwares con Perfiles hardware que quedan húerfanos */
2309        result = dbi_conn_queryf(dbi->conn,
2310                        "DELETE FROM perfileshard_hardwares WHERE idperfilhard NOT IN"
2311                        " (SELECT idperfilhard FROM perfileshard)");
2312        if (!result) {
2313                dbi_conn_error(dbi->conn, &msglog);
2314                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2315                       __func__, __LINE__, msglog);
2316                return false;
2317        }
2318        dbi_result_free(result);
2319
2320        return true;
2321}
2322// ________________________________________________________________________________________________________
2323// Función: RESPUESTA_InventarioSoftware
2324//
2325//      Descripción:
2326//              Respuesta del cliente al comando InventarioSoftware
2327//      Parámetros:
2328//              - socket_c: Socket del cliente que envió el mensaje
2329//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
2330//      Devuelve:
2331//              true: Si el proceso es correcto
2332//              false: En caso de ocurrir algún error
2333// ________________________________________________________________________________________________________
2334static bool RESPUESTA_InventarioSoftware(TRAMA* ptrTrama, struct og_client *cli)
2335{
2336        bool res;
2337        char *iph, *ido, *npc, *idc, *par, *sft, *buffer;
2338        struct og_dbi *dbi;
2339
2340        dbi = og_dbi_open(&dbi_config);
2341        if (!dbi) {
2342                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
2343                       __func__, __LINE__);
2344                return false;
2345        }
2346
2347        iph = copiaParametro("iph",ptrTrama); // Toma dirección ip
2348        ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
2349
2350        if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) {
2351                og_dbi_close(dbi);
2352                liberaMemoria(iph);
2353                liberaMemoria(ido);
2354                syslog(LOG_ERR, "failed to register notification\n");
2355                return false;
2356        }
2357
2358        npc = copiaParametro("npc",ptrTrama);
2359        idc = copiaParametro("idc",ptrTrama); // Toma identificador del Centro 
2360        par = copiaParametro("par",ptrTrama);
2361        sft = copiaParametro("sft",ptrTrama);
2362
2363        buffer = rTrim(leeArchivo(sft));
2364        if (buffer)
2365                res=actualizaSoftware(dbi, buffer, par, ido, npc, idc);
2366        else
2367                res = false;
2368
2369        liberaMemoria(iph);
2370        liberaMemoria(ido);     
2371        liberaMemoria(npc);     
2372        liberaMemoria(idc);     
2373        liberaMemoria(par);     
2374        liberaMemoria(sft);     
2375        og_dbi_close(dbi);
2376
2377        if (!res)
2378                syslog(LOG_ERR, "cannot update software\n");
2379
2380        return res;
2381}
2382// ________________________________________________________________________________________________________
2383// Función: actualizaSoftware
2384//
2385//      Descripción:
2386//              Actualiza la base de datos con la configuración software del cliente
2387//      Parámetros:
2388//              - db: Objeto base de datos (ya operativo)
2389//              - tbl: Objeto tabla
2390//              - sft: cadena con el inventario software
2391//              - par: Número de la partición
2392//              - ido: Identificador del ordenador del cliente en la tabla
2393//              - npc: Nombre del ordenador
2394//              - idc: Identificador del centro o Unidad organizativa
2395//      Devuelve:
2396//              true: Si el proceso es correcto
2397//              false: En caso de ocurrir algún error
2398//
2399//      Versión 1.1.0: Se incluye el sistema operativo. Autora: Irina Gómez - ETSII Universidad Sevilla
2400// ________________________________________________________________________________________________________
2401bool actualizaSoftware(struct og_dbi *dbi, char *sft, char *par,char *ido,
2402                       char *npc, char *idc)
2403{
2404        int i, j, lon, aux, idperfilsoft, idnombreso;
2405        bool retval;
2406        char *wsft;
2407        int tbidsoftware[MAXSOFTWARE];
2408        char *tbSoftware[MAXSOFTWARE], strInt[LONINT], *idsoftwares;
2409        const char *msglog;
2410        dbi_result result;
2411
2412        /* Toma Centro (Unidad Organizativa) y perfil software */
2413        result = dbi_conn_queryf(dbi->conn,
2414                "SELECT idperfilsoft,numpar"
2415                " FROM ordenadores_particiones"
2416                " WHERE idordenador=%s", ido);
2417        if (!result) {
2418                dbi_conn_error(dbi->conn, &msglog);
2419                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2420                       __func__, __LINE__, msglog);
2421                return false;
2422        }
2423        idperfilsoft = 0; // Por defecto se supone que el ordenador no tiene aún detectado el perfil software
2424        while (dbi_result_next_row(result)) {
2425                aux = dbi_result_get_uint(result, "numpar");
2426                if (aux == atoi(par)) { // Se encuentra la partición
2427                        idperfilsoft = dbi_result_get_uint(result, "idperfilsoft");
2428                        break;
2429                }
2430        }
2431        dbi_result_free(result);
2432        wsft=escaparCadena(sft); // Codificar comillas simples
2433        if(!wsft)
2434                return false;
2435
2436        /* Recorre componentes software*/
2437        lon = splitCadena(tbSoftware, wsft, '\n');
2438
2439        if (lon == 0)
2440                return true; // No hay lineas que procesar
2441        if (lon > MAXSOFTWARE)
2442                lon = MAXSOFTWARE; // Limita el número de componentes software
2443
2444        idnombreso = 0;
2445        for (i = 0; i < lon; i++) {
2446                // Primera línea es el sistema operativo: se obtiene identificador
2447                if (i == 0) {
2448                        idnombreso = checkDato(dbi, rTrim(tbSoftware[i]), "nombresos", "nombreso", "idnombreso");
2449                        continue;
2450                }
2451
2452                result = dbi_conn_queryf(dbi->conn,
2453                                "SELECT idsoftware FROM softwares WHERE descripcion ='%s'",
2454                                rTrim(tbSoftware[i]));
2455                if (!result) {
2456                        dbi_conn_error(dbi->conn, &msglog);
2457                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2458                               __func__, __LINE__, msglog);
2459                        return false;
2460                }
2461
2462                if (!dbi_result_next_row(result)) {
2463                        dbi_result_free(result);
2464                        result = dbi_conn_queryf(dbi->conn,
2465                                                "INSERT INTO softwares (idtiposoftware,descripcion,idcentro,grupoid)"
2466                                                " VALUES(2,'%s',%s,0)", tbSoftware[i], idc);
2467                        if (!result) { // Error al insertar
2468                                dbi_conn_error(dbi->conn, &msglog);
2469                                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2470                                       __func__, __LINE__, msglog);
2471                                return false;
2472                        }
2473
2474                        // Recupera el identificador del software
2475                        tbidsoftware[i] = dbi_conn_sequence_last(dbi->conn, NULL);
2476                } else {
2477                        tbidsoftware[i] = dbi_result_get_uint(result, "idsoftware");
2478                }
2479                dbi_result_free(result);
2480        }
2481
2482        // Ordena tabla de identificadores para cosultar si existe un pefil con esas especificaciones
2483
2484        for (i = 0; i < lon - 1; i++) {
2485                for (j = i + 1; j < lon; j++) {
2486                        if (tbidsoftware[i] > tbidsoftware[j]) {
2487                                aux = tbidsoftware[i];
2488                                tbidsoftware[i] = tbidsoftware[j];
2489                                tbidsoftware[j] = aux;
2490                        }
2491                }
2492        }
2493        /* Crea cadena de identificadores de componentes software separados por coma */
2494        sprintf(strInt, "%d", tbidsoftware[lon - 1]); // Pasa a cadena el último identificador que es de mayor longitud
2495        aux = strlen(strInt); // Calcula longitud de cadena para reservar espacio a todos los perfiles
2496        idsoftwares = reservaMemoria((sizeof(aux)+1) * lon + lon);
2497        if (idsoftwares == NULL) {
2498                syslog(LOG_ERR, "%s:%d OOM\n", __FILE__, __LINE__);
2499                return false;
2500        }
2501        aux = sprintf(idsoftwares, "%d", tbidsoftware[0]);
2502        for (i = 1; i < lon; i++)
2503                aux += sprintf(idsoftwares + aux, ",%d", tbidsoftware[i]);
2504
2505        // Comprueba existencia de perfil software y actualización de éste para el ordenador
2506        if (!cuestionPerfilSoftware(dbi, idc, ido, idperfilsoft, idnombreso, idsoftwares,
2507                        npc, par, tbidsoftware, lon)) {
2508                syslog(LOG_ERR, "cannot update software\n");
2509                og_info((char *)msglog);
2510                retval=false;
2511        }
2512        else {
2513                retval=true;
2514        }
2515        liberaMemoria(wsft);
2516        liberaMemoria(idsoftwares);
2517        return (retval);
2518}
2519// ________________________________________________________________________________________________________
2520// Función: CuestionPerfilSoftware
2521//
2522//      Parámetros:
2523//              - db: Objeto base de datos (ya operativo)
2524//              - tbl: Objeto tabla
2525//              - idcentro: Identificador del centro en la tabla
2526//              - ido: Identificador del ordenador del cliente en la tabla
2527//              - idnombreso: Identificador del sistema operativo
2528//              - idsoftwares: Cadena con los identificadores de componentes software separados por comas
2529//              - npc: Nombre del ordenador del cliente
2530//              - particion: Número de la partición
2531//              - tbidsoftware: Array con los identificadores de componentes software
2532//              - lon: Número de componentes
2533//      Devuelve:
2534//              true: Si el proceso es correcto
2535//              false: En caso de ocurrir algún error
2536//
2537//      Versión 1.1.0: Se incluye el sistema operativo. Autora: Irina Gómez - ETSII Universidad Sevilla
2538//_________________________________________________________________________________________________________
2539bool cuestionPerfilSoftware(struct og_dbi *dbi, char *idc, char *ido,
2540                            int idperfilsoftware, int idnombreso,
2541                            char *idsoftwares, char *npc, char *par,
2542                            int *tbidsoftware, int lon)
2543{
2544        int i, nwidperfilsoft;
2545        const char *msglog;
2546        dbi_result result;
2547
2548        // Busca perfil soft del ordenador que contenga todos los componentes software encontrados
2549        result = dbi_conn_queryf(dbi->conn,
2550                "SELECT idperfilsoft FROM"
2551                " (SELECT perfilessoft_softwares.idperfilsoft as idperfilsoft,"
2552                "       group_concat(cast(perfilessoft_softwares.idsoftware AS char( 11) )"
2553                "       ORDER BY perfilessoft_softwares.idsoftware SEPARATOR ',' ) AS idsoftwares"
2554                " FROM  perfilessoft_softwares"
2555                " GROUP BY perfilessoft_softwares.idperfilsoft) AS temp"
2556                " WHERE idsoftwares LIKE '%s'", idsoftwares);
2557
2558        if (!result) {
2559                dbi_conn_error(dbi->conn, &msglog);
2560                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2561                       __func__, __LINE__, msglog);
2562                return false;
2563        }
2564        if (!dbi_result_next_row(result)) { // No existe un perfil software con esos componentes de componentes software, lo crea
2565                dbi_result_free(result);
2566                result = dbi_conn_queryf(dbi->conn,
2567                                "INSERT perfilessoft  (descripcion, idcentro, grupoid, idnombreso)"
2568                                " VALUES('Perfil Software (%s, Part:%s) ',%s,0,%i)", npc, par, idc,idnombreso);
2569                if (!result) {
2570                        dbi_conn_error(dbi->conn, &msglog);
2571                        og_info((char *)msglog);
2572                        return false;
2573                }
2574
2575                dbi_result_free(result);
2576                // Recupera el identificador del nuevo perfil software
2577                nwidperfilsoft = dbi_conn_sequence_last(dbi->conn, NULL);
2578
2579                // Crea la relación entre perfiles y componenetes software
2580                for (i = 0; i < lon; i++) {
2581                        result = dbi_conn_queryf(dbi->conn,
2582                                                "INSERT perfilessoft_softwares (idperfilsoft,idsoftware)"
2583                                                " VALUES(%d,%d)", nwidperfilsoft, tbidsoftware[i]);
2584                        if (!result) {
2585                                dbi_conn_error(dbi->conn, &msglog);
2586                                og_info((char *)msglog);
2587                                return false;
2588                        }
2589                        dbi_result_free(result);
2590                }
2591        } else { // Existe un perfil con todos esos componentes
2592                nwidperfilsoft = dbi_result_get_uint(result, "idperfilsoft");
2593                dbi_result_free(result);
2594        }
2595
2596        if (idperfilsoftware != nwidperfilsoft) { // No coinciden los perfiles
2597                // Actualiza el identificador del perfil software del ordenador
2598                result = dbi_conn_queryf(dbi->conn,
2599                                "UPDATE ordenadores_particiones SET idperfilsoft=%d,idimagen=0"
2600                                " WHERE idordenador=%s AND numpar=%s", nwidperfilsoft, ido, par);
2601                if (!result) { // Error al insertar
2602                        dbi_conn_error(dbi->conn, &msglog);
2603                        og_info((char *)msglog);
2604                        return false;
2605                }
2606                dbi_result_free(result);
2607        }
2608
2609        /* DEPURACIÓN DE PERFILES SOFTWARE */
2610
2611         /* Eliminar Relación de softwares con Perfiles software que quedan húerfanos */
2612        result = dbi_conn_queryf(dbi->conn,
2613                "DELETE FROM perfilessoft_softwares WHERE idperfilsoft IN "\
2614                " (SELECT idperfilsoft FROM perfilessoft WHERE idperfilsoft NOT IN"\
2615                " (SELECT DISTINCT idperfilsoft from ordenadores_particiones) AND idperfilsoft NOT IN"\
2616                " (SELECT DISTINCT idperfilsoft from imagenes))");
2617        if (!result) {
2618                dbi_conn_error(dbi->conn, &msglog);
2619                og_info((char *)msglog);
2620                return false;
2621        }
2622        dbi_result_free(result),
2623        /* Eliminar Perfiles software que quedan húerfanos */
2624        result = dbi_conn_queryf(dbi->conn,
2625                "DELETE FROM perfilessoft WHERE idperfilsoft NOT IN"
2626                " (SELECT DISTINCT idperfilsoft from ordenadores_particiones)"\
2627                " AND  idperfilsoft NOT IN"\
2628                " (SELECT DISTINCT idperfilsoft from imagenes)");
2629        if (!result) {
2630                dbi_conn_error(dbi->conn, &msglog);
2631                og_info((char *)msglog);
2632                return false;
2633        }
2634        dbi_result_free(result),
2635
2636        /* Eliminar Relación de softwares con Perfiles software que quedan húerfanos */
2637        result = dbi_conn_queryf(dbi->conn,
2638                        "DELETE FROM perfilessoft_softwares WHERE idperfilsoft NOT IN"
2639                        " (SELECT idperfilsoft from perfilessoft)");
2640        if (!result) {
2641                dbi_conn_error(dbi->conn, &msglog);
2642                og_info((char *)msglog);
2643                return false;
2644        }
2645        dbi_result_free(result);
2646
2647        return true;
2648}
2649// ________________________________________________________________________________________________________
2650// Función: enviaArchivo
2651//
2652//      Descripción:
2653//              Envia un archivo por la red, por bloques
2654//      Parámetros:
2655//              - socket_c: Socket del cliente que envió el mensaje
2656//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
2657//      Devuelve:
2658//              true: Si el proceso es correcto
2659//              false: En caso de ocurrir algún error
2660// ________________________________________________________________________________________________________
2661static bool enviaArchivo(TRAMA *ptrTrama, struct og_client *cli)
2662{
2663        int socket_c = og_client_socket(cli);
2664        char *nfl;
2665
2666        // Toma parámetros
2667        nfl = copiaParametro("nfl",ptrTrama); // Toma nombre completo del archivo
2668        if (!sendArchivo(&socket_c, nfl)) {
2669                liberaMemoria(nfl);
2670                syslog(LOG_ERR, "Problem sending file\n");
2671                return false;
2672        }
2673        liberaMemoria(nfl);
2674        return true;
2675}
2676// ________________________________________________________________________________________________________
2677// Función: enviaArchivo
2678//
2679//      Descripción:
2680//              Envia un archivo por la red, por bloques
2681//      Parámetros:
2682//              - socket_c: Socket del cliente que envió el mensaje
2683//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
2684//      Devuelve:
2685//              true: Si el proceso es correcto
2686//              false: En caso de ocurrir algún error
2687// ________________________________________________________________________________________________________
2688static bool recibeArchivo(TRAMA *ptrTrama, struct og_client *cli)
2689{
2690        int socket_c = og_client_socket(cli);
2691        char *nfl;
2692
2693        // Toma parámetros
2694        nfl = copiaParametro("nfl",ptrTrama); // Toma nombre completo del archivo
2695        ptrTrama->tipo = MSG_NOTIFICACION;
2696        enviaFlag(&socket_c, ptrTrama);
2697        if (!recArchivo(&socket_c, nfl)) {
2698                liberaMemoria(nfl);
2699                syslog(LOG_ERR, "Problem receiving file\n");
2700                return false;
2701        }
2702        liberaMemoria(nfl);
2703        return true;
2704}
2705// ________________________________________________________________________________________________________
2706// Función: envioProgramacion
2707//
2708//      Descripción:
2709//              Envia un comando de actualización a todos los ordenadores que han sido programados con
2710//              alguna acción para que entren en el bucle de comandos pendientes y las ejecuten
2711//      Parámetros:
2712//              - socket_c: Socket del cliente que envió el mensaje
2713//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
2714//      Devuelve:
2715//              true: Si el proceso es correcto
2716//              false: En caso de ocurrir algún error
2717// ________________________________________________________________________________________________________
2718static bool envioProgramacion(TRAMA *ptrTrama, struct og_client *cli)
2719{
2720        char *ptrIP[MAXIMOS_CLIENTES],*ptrMacs[MAXIMOS_CLIENTES];
2721        char *idp, *iph, *mac;
2722        int idx,idcomando,lon;
2723        const char *msglog;
2724        struct og_dbi *dbi;
2725        dbi_result result;
2726
2727        dbi = og_dbi_open(&dbi_config);
2728        if (!dbi) {
2729                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
2730                       __func__, __LINE__);
2731                return false;
2732        }
2733
2734        idp = copiaParametro("idp",ptrTrama); // Toma identificador de la programación de la tabla acciones
2735
2736        result = dbi_conn_queryf(dbi->conn,
2737                        "SELECT ordenadores.ip,ordenadores.mac,acciones.idcomando FROM acciones "\
2738                        " INNER JOIN ordenadores ON ordenadores.ip=acciones.ip"\
2739                        " WHERE acciones.idprogramacion=%s",idp);
2740
2741        liberaMemoria(idp);
2742
2743        if (!result) {
2744                dbi_conn_error(dbi->conn, &msglog);
2745                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2746                       __func__, __LINE__, msglog);
2747                og_dbi_close(dbi);
2748                return false;
2749        }
2750
2751        /* Prepara la trama de actualizacion */
2752
2753        initParametros(ptrTrama,0);
2754        ptrTrama->tipo=MSG_COMANDO;
2755        sprintf(ptrTrama->parametros, "nfn=Actualizar\r");
2756
2757        while (dbi_result_next_row(result)) {
2758                iph = (char *)dbi_result_get_string(result, "ip");
2759                idcomando = dbi_result_get_uint(result, "idcomando");
2760
2761                if (idcomando == 1){ // Arrancar
2762                        mac = (char *)dbi_result_get_string(result, "mac");
2763                        lon = splitCadena(ptrIP, iph, ';');
2764                        lon = splitCadena(ptrMacs, mac, ';');
2765
2766                        // Se manda por broadcast y por unicast
2767                        if (!Levanta(ptrIP, ptrMacs, lon, (char*)"1")) {
2768                                dbi_result_free(result);
2769                                og_dbi_close(dbi);
2770                                return false;
2771                        }
2772
2773                        if (!Levanta(ptrIP, ptrMacs, lon, (char*)"2")) {
2774                                dbi_result_free(result);
2775                                og_dbi_close(dbi);
2776                                return false;
2777                        }
2778
2779                }
2780                if (clienteDisponible(iph, &idx)) { // Si el cliente puede recibir comandos
2781                        int sock = tbsockets[idx].cli ? tbsockets[idx].cli->io.fd : -1;
2782
2783                        strcpy(tbsockets[idx].estado, CLIENTE_OCUPADO); // Actualiza el estado del cliente
2784                        if (sock >= 0 && !mandaTrama(&sock, ptrTrama)) {
2785                                syslog(LOG_ERR, "failed to send response: %s\n",
2786                                       strerror(errno));
2787                        }
2788                        //close(tbsockets[idx].sock); // Cierra el socket del cliente hasta nueva disponibilidad
2789                }
2790        }
2791        dbi_result_free(result);
2792        og_dbi_close(dbi);
2793
2794        return true; // No existen registros
2795}
2796
2797// This object stores function handler for messages
2798static struct {
2799        const char *nf; // Nombre de la función
2800        bool (*fcn)(TRAMA *, struct og_client *cli);
2801} tbfuncionesServer[] = {
2802        { "InclusionCliente",                   InclusionCliente,       },
2803        { "InclusionClienteWinLnx",             InclusionClienteWinLnx, },
2804        { "AutoexecCliente",                    AutoexecCliente,        },
2805        { "ComandosPendientes",                 ComandosPendientes,     },
2806        { "DisponibilidadComandos",             DisponibilidadComandos, },
2807        { "RESPUESTA_Arrancar",                 RESPUESTA_Arrancar,     },
2808        { "RESPUESTA_Apagar",                   RESPUESTA_Apagar,       },
2809        { "RESPUESTA_Reiniciar",                RESPUESTA_Apagar,       },
2810        { "RESPUESTA_IniciarSesion",            RESPUESTA_Apagar, },
2811        { "RESPUESTA_CrearImagen",              RESPUESTA_CrearImagen,  },
2812        { "RESPUESTA_CrearImagenBasica",        RESPUESTA_CrearImagenBasica, },
2813        { "RESPUESTA_CrearSoftIncremental",     RESPUESTA_CrearSoftIncremental, },
2814        { "RESPUESTA_RestaurarImagen",          RESPUESTA_RestaurarImagen },
2815        { "RESPUESTA_RestaurarImagenBasica",    RESPUESTA_RestaurarImagenBasica, },
2816        { "RESPUESTA_RestaurarSoftIncremental", RESPUESTA_RestaurarSoftIncremental, },
2817        { "RESPUESTA_Configurar",               RESPUESTA_EjecutarScript, },
2818        { "RESPUESTA_EjecutarScript",           RESPUESTA_EjecutarScript, },
2819        { "RESPUESTA_InventarioHardware",       RESPUESTA_InventarioHardware, },
2820        { "RESPUESTA_InventarioSoftware",       RESPUESTA_InventarioSoftware, },
2821        { "enviaArchivo",                       enviaArchivo,           },
2822        { "recibeArchivo",                      recibeArchivo,          },
2823        { "envioProgramacion",                  envioProgramacion,      },
2824        { NULL,                                 NULL,                   },
2825};
2826
2827// ________________________________________________________________________________________________________
2828// Función: gestionaTrama
2829//
2830//              Descripción:
2831//                      Procesa las tramas recibidas .
2832//              Parametros:
2833//                      - s : Socket usado para comunicaciones
2834//      Devuelve:
2835//              true: Si el proceso es correcto
2836//              false: En caso de ocurrir algún error
2837// ________________________________________________________________________________________________________
2838static void gestionaTrama(TRAMA *ptrTrama, struct og_client *cli)
2839{
2840        int i, res;
2841        char *nfn;
2842
2843        if (ptrTrama){
2844                INTROaFINCAD(ptrTrama);
2845                nfn = copiaParametro("nfn",ptrTrama); // Toma nombre de la función
2846
2847                for (i = 0; tbfuncionesServer[i].fcn; i++) {
2848                        if (!strncmp(tbfuncionesServer[i].nf, nfn,
2849                                     strlen(tbfuncionesServer[i].nf))) {
2850                                res = tbfuncionesServer[i].fcn(ptrTrama, cli);
2851                                if (!res) {
2852                                        syslog(LOG_ERR, "Failed handling of %s for client %s:%hu\n",
2853                                               tbfuncionesServer[i].nf,
2854                                               inet_ntoa(cli->addr.sin_addr),
2855                                               ntohs(cli->addr.sin_port));
2856                                } else {
2857                                        syslog(LOG_DEBUG, "Successful handling of %s for client %s:%hu\n",
2858                                               tbfuncionesServer[i].nf,
2859                                               inet_ntoa(cli->addr.sin_addr),
2860                                               ntohs(cli->addr.sin_port));
2861                                }
2862                                break;
2863                        }
2864                }
2865                if (!tbfuncionesServer[i].fcn)
2866                        syslog(LOG_ERR, "unknown request %s from client %s:%hu\n",
2867                               nfn, inet_ntoa(cli->addr.sin_addr),
2868                               ntohs(cli->addr.sin_port));
2869
2870                liberaMemoria(nfn);
2871        }
2872}
2873
2874static void og_client_release(struct ev_loop *loop, struct og_client *cli)
2875{
2876        if (cli->keepalive_idx >= 0) {
2877                syslog(LOG_DEBUG, "closing keepalive connection for %s:%hu in slot %d\n",
2878                       inet_ntoa(cli->addr.sin_addr),
2879                       ntohs(cli->addr.sin_port), cli->keepalive_idx);
2880                tbsockets[cli->keepalive_idx].cli = NULL;
2881        }
2882
2883        list_del(&cli->list);
2884        ev_io_stop(loop, &cli->io);
2885        close(cli->io.fd);
2886        free(cli);
2887}
2888
2889static void og_client_keepalive(struct ev_loop *loop, struct og_client *cli)
2890{
2891        struct og_client *old_cli;
2892
2893        old_cli = tbsockets[cli->keepalive_idx].cli;
2894        if (old_cli && old_cli != cli) {
2895                syslog(LOG_DEBUG, "closing old keepalive connection for %s:%hu\n",
2896                       inet_ntoa(old_cli->addr.sin_addr),
2897                       ntohs(old_cli->addr.sin_port));
2898
2899                og_client_release(loop, old_cli);
2900        }
2901        tbsockets[cli->keepalive_idx].cli = cli;
2902}
2903
2904static void og_client_reset_state(struct og_client *cli)
2905{
2906        cli->state = OG_CLIENT_RECEIVING_HEADER;
2907        cli->buf_len = 0;
2908}
2909
2910static int og_client_state_recv_hdr(struct og_client *cli)
2911{
2912        char hdrlen[LONHEXPRM];
2913
2914        /* Still too short to validate protocol fingerprint and message
2915         * length.
2916         */
2917        if (cli->buf_len < 15 + LONHEXPRM)
2918                return 0;
2919
2920        if (strncmp(cli->buf, "@JMMLCAMDJ_MCDJ", 15)) {
2921                syslog(LOG_ERR, "bad fingerprint from client %s:%hu, closing\n",
2922                       inet_ntoa(cli->addr.sin_addr),
2923                       ntohs(cli->addr.sin_port));
2924                return -1;
2925        }
2926
2927        memcpy(hdrlen, &cli->buf[LONGITUD_CABECERATRAMA], LONHEXPRM);
2928        cli->msg_len = strtol(hdrlen, NULL, 16);
2929
2930        /* Header announces more that we can fit into buffer. */
2931        if (cli->msg_len >= sizeof(cli->buf)) {
2932                syslog(LOG_ERR, "too large message %u bytes from %s:%hu\n",
2933                       cli->msg_len, inet_ntoa(cli->addr.sin_addr),
2934                       ntohs(cli->addr.sin_port));
2935                return -1;
2936        }
2937
2938        return 1;
2939}
2940
2941static TRAMA *og_msg_alloc(char *data, unsigned int len)
2942{
2943        TRAMA *ptrTrama;
2944
2945        ptrTrama = (TRAMA *)reservaMemoria(sizeof(TRAMA));
2946        if (!ptrTrama) {
2947                syslog(LOG_ERR, "OOM\n");
2948                return NULL;
2949        }
2950
2951        initParametros(ptrTrama, len);
2952        memcpy(ptrTrama, "@JMMLCAMDJ_MCDJ", LONGITUD_CABECERATRAMA);
2953        memcpy(ptrTrama->parametros, data, len);
2954        ptrTrama->lonprm = len;
2955
2956        return ptrTrama;
2957}
2958
2959static void og_msg_free(TRAMA *ptrTrama)
2960{
2961        liberaMemoria(ptrTrama->parametros);
2962        liberaMemoria(ptrTrama);
2963}
2964
2965static int og_client_state_process_payload(struct og_client *cli)
2966{
2967        TRAMA *ptrTrama;
2968        char *data;
2969        int len;
2970
2971        len = cli->msg_len - (LONGITUD_CABECERATRAMA + LONHEXPRM);
2972        data = &cli->buf[LONGITUD_CABECERATRAMA + LONHEXPRM];
2973
2974        ptrTrama = og_msg_alloc(data, len);
2975        if (!ptrTrama)
2976                return -1;
2977
2978        gestionaTrama(ptrTrama, cli);
2979
2980        og_msg_free(ptrTrama);
2981
2982        return 1;
2983}
2984
2985#define OG_CLIENTS_MAX  4096
2986#define OG_PARTITION_MAX 4
2987
2988struct og_partition {
2989        const char      *disk;
2990        const char      *number;
2991        const char      *code;
2992        const char      *size;
2993        const char      *filesystem;
2994        const char      *format;
2995        const char      *os;
2996        const char      *used_size;
2997};
2998
2999struct og_sync_params {
3000        const char      *sync;
3001        const char      *diff;
3002        const char      *remove;
3003        const char      *compress;
3004        const char      *cleanup;
3005        const char      *cache;
3006        const char      *cleanup_cache;
3007        const char      *remove_dst;
3008        const char      *diff_id;
3009        const char      *diff_name;
3010        const char      *path;
3011        const char      *method;
3012};
3013
3014struct og_msg_params {
3015        const char      *ips_array[OG_CLIENTS_MAX];
3016        const char      *mac_array[OG_CLIENTS_MAX];
3017        unsigned int    ips_array_len;
3018        const char      *wol_type;
3019        char            run_cmd[4096];
3020        const char      *disk;
3021        const char      *partition;
3022        const char      *repository;
3023        const char      *name;
3024        const char      *id;
3025        const char      *code;
3026        const char      *type;
3027        const char      *profile;
3028        const char      *cache;
3029        const char      *cache_size;
3030        bool            echo;
3031        struct og_partition     partition_setup[OG_PARTITION_MAX];
3032        struct og_sync_params sync_setup;
3033        struct og_schedule_time time;
3034        const char      *task_id;
3035        uint64_t        flags;
3036};
3037
3038#define OG_COMPUTER_NAME_MAXLEN 100
3039
3040struct og_computer {
3041        unsigned int    id;
3042        unsigned int    center;
3043        unsigned int    room;
3044        char            name[OG_COMPUTER_NAME_MAXLEN + 1];
3045};
3046
3047#define OG_REST_PARAM_ADDR                      (1UL << 0)
3048#define OG_REST_PARAM_MAC                       (1UL << 1)
3049#define OG_REST_PARAM_WOL_TYPE                  (1UL << 2)
3050#define OG_REST_PARAM_RUN_CMD                   (1UL << 3)
3051#define OG_REST_PARAM_DISK                      (1UL << 4)
3052#define OG_REST_PARAM_PARTITION                 (1UL << 5)
3053#define OG_REST_PARAM_REPO                      (1UL << 6)
3054#define OG_REST_PARAM_NAME                      (1UL << 7)
3055#define OG_REST_PARAM_ID                        (1UL << 8)
3056#define OG_REST_PARAM_CODE                      (1UL << 9)
3057#define OG_REST_PARAM_TYPE                      (1UL << 10)
3058#define OG_REST_PARAM_PROFILE                   (1UL << 11)
3059#define OG_REST_PARAM_CACHE                     (1UL << 12)
3060#define OG_REST_PARAM_CACHE_SIZE                (1UL << 13)
3061#define OG_REST_PARAM_PART_0                    (1UL << 14)
3062#define OG_REST_PARAM_PART_1                    (1UL << 15)
3063#define OG_REST_PARAM_PART_2                    (1UL << 16)
3064#define OG_REST_PARAM_PART_3                    (1UL << 17)
3065#define OG_REST_PARAM_SYNC_SYNC                 (1UL << 18)
3066#define OG_REST_PARAM_SYNC_DIFF                 (1UL << 19)
3067#define OG_REST_PARAM_SYNC_REMOVE               (1UL << 20)
3068#define OG_REST_PARAM_SYNC_COMPRESS             (1UL << 21)
3069#define OG_REST_PARAM_SYNC_CLEANUP              (1UL << 22)
3070#define OG_REST_PARAM_SYNC_CACHE                (1UL << 23)
3071#define OG_REST_PARAM_SYNC_CLEANUP_CACHE        (1UL << 24)
3072#define OG_REST_PARAM_SYNC_REMOVE_DST           (1UL << 25)
3073#define OG_REST_PARAM_SYNC_DIFF_ID              (1UL << 26)
3074#define OG_REST_PARAM_SYNC_DIFF_NAME            (1UL << 27)
3075#define OG_REST_PARAM_SYNC_PATH                 (1UL << 28)
3076#define OG_REST_PARAM_SYNC_METHOD               (1UL << 29)
3077#define OG_REST_PARAM_ECHO                      (1UL << 30)
3078#define OG_REST_PARAM_TASK                      (1UL << 31)
3079#define OG_REST_PARAM_TIME_YEARS                (1UL << 32)
3080#define OG_REST_PARAM_TIME_MONTHS               (1UL << 33)
3081#define OG_REST_PARAM_TIME_DAYS                 (1UL << 34)
3082#define OG_REST_PARAM_TIME_HOURS                (1UL << 35)
3083#define OG_REST_PARAM_TIME_AM_PM                (1UL << 36)
3084#define OG_REST_PARAM_TIME_MINUTES              (1UL << 37)
3085
3086enum og_rest_method {
3087        OG_METHOD_GET   = 0,
3088        OG_METHOD_POST,
3089};
3090
3091static struct og_client *og_client_find(const char *ip)
3092{
3093        struct og_client *client;
3094        struct in_addr addr;
3095        int res;
3096
3097        res = inet_aton(ip, &addr);
3098        if (!res) {
3099                syslog(LOG_ERR, "Invalid IP string: %s\n", ip);
3100                return NULL;
3101        }
3102
3103        list_for_each_entry(client, &client_list, list) {
3104                if (client->addr.sin_addr.s_addr == addr.s_addr && client->agent) {
3105                        return client;
3106                }
3107        }
3108
3109        return NULL;
3110}
3111
3112static int og_send_request(const char *cmd,
3113                           const enum og_rest_method method,
3114                           const struct og_msg_params *params,
3115                           const json_t *data)
3116{
3117        const char *content_type = "Content-Type: application/json";
3118        char content [OG_MSG_REQUEST_MAXLEN - 700] = {};
3119        char buf[OG_MSG_REQUEST_MAXLEN] = {};
3120        unsigned int content_length;
3121        char method_str[5] = {};
3122        struct og_client *cli;
3123        unsigned int i;
3124        int client_sd;
3125
3126        if (method == OG_METHOD_GET)
3127                snprintf(method_str, 5, "GET");
3128        else if (method == OG_METHOD_POST)
3129                snprintf(method_str, 5, "POST");
3130        else
3131                return -1;
3132
3133        if (!data)
3134                content_length = 0;
3135        else
3136                content_length = json_dumpb(data, content,
3137                                            OG_MSG_REQUEST_MAXLEN - 700,
3138                                            JSON_COMPACT);
3139
3140        snprintf(buf, OG_MSG_REQUEST_MAXLEN,
3141                 "%s /%s HTTP/1.1\r\nContent-Length: %d\r\n%s\r\n\r\n%s",
3142                 method_str, cmd, content_length, content_type, content);
3143
3144        for (i = 0; i < params->ips_array_len; i++) {
3145                cli = og_client_find(params->ips_array[i]);
3146                if (!cli)
3147                        continue;
3148
3149                client_sd = cli->io.fd;
3150                if (client_sd < 0) {
3151                        syslog(LOG_INFO, "Client %s not conected\n",
3152                               params->ips_array[i]);
3153                        continue;
3154                }
3155
3156                if (send(client_sd, buf, strlen(buf), 0) < 0)
3157                        continue;
3158
3159                strncpy(cli->last_cmd, cmd, OG_CMD_MAXLEN);
3160        }
3161
3162        return 0;
3163}
3164
3165static bool og_msg_params_validate(const struct og_msg_params *params,
3166                                   const uint64_t flags)
3167{
3168        return (params->flags & flags) == flags;
3169}
3170
3171static int og_json_parse_clients(json_t *element, struct og_msg_params *params)
3172{
3173        unsigned int i;
3174        json_t *k;
3175
3176        if (json_typeof(element) != JSON_ARRAY)
3177                return -1;
3178
3179        for (i = 0; i < json_array_size(element); i++) {
3180                k = json_array_get(element, i);
3181                if (json_typeof(k) != JSON_STRING)
3182                        return -1;
3183
3184                params->ips_array[params->ips_array_len++] =
3185                        json_string_value(k);
3186
3187                params->flags |= OG_REST_PARAM_ADDR;
3188        }
3189
3190        return 0;
3191}
3192
3193static int og_json_parse_string(json_t *element, const char **str)
3194{
3195        if (json_typeof(element) != JSON_STRING)
3196                return -1;
3197
3198        *str = json_string_value(element);
3199        return 0;
3200}
3201
3202static int og_json_parse_uint(json_t *element, uint32_t *integer)
3203{
3204        if (json_typeof(element) != JSON_INTEGER)
3205                return -1;
3206
3207        *integer = json_integer_value(element);
3208        return 0;
3209}
3210
3211static int og_json_parse_bool(json_t *element, bool *value)
3212{
3213        if (json_typeof(element) == JSON_TRUE)
3214                *value = true;
3215        else if (json_typeof(element) == JSON_FALSE)
3216                *value = false;
3217        else
3218                return -1;
3219
3220        return 0;
3221}
3222
3223static int og_json_parse_sync_params(json_t *element,
3224                                     struct og_msg_params *params)
3225{
3226        const char *key;
3227        json_t *value;
3228        int err = 0;
3229
3230        json_object_foreach(element, key, value) {
3231                if (!strcmp(key, "sync")) {
3232                        err = og_json_parse_string(value, &params->sync_setup.sync);
3233                        params->flags |= OG_REST_PARAM_SYNC_SYNC;
3234                } else if (!strcmp(key, "diff")) {
3235                        err = og_json_parse_string(value, &params->sync_setup.diff);
3236                        params->flags |= OG_REST_PARAM_SYNC_DIFF;
3237                } else if (!strcmp(key, "remove")) {
3238                        err = og_json_parse_string(value, &params->sync_setup.remove);
3239                        params->flags |= OG_REST_PARAM_SYNC_REMOVE;
3240                } else if (!strcmp(key, "compress")) {
3241                        err = og_json_parse_string(value, &params->sync_setup.compress);
3242                        params->flags |= OG_REST_PARAM_SYNC_COMPRESS;
3243                } else if (!strcmp(key, "cleanup")) {
3244                        err = og_json_parse_string(value, &params->sync_setup.cleanup);
3245                        params->flags |= OG_REST_PARAM_SYNC_CLEANUP;
3246                } else if (!strcmp(key, "cache")) {
3247                        err = og_json_parse_string(value, &params->sync_setup.cache);
3248                        params->flags |= OG_REST_PARAM_SYNC_CACHE;
3249                } else if (!strcmp(key, "cleanup_cache")) {
3250                        err = og_json_parse_string(value, &params->sync_setup.cleanup_cache);
3251                        params->flags |= OG_REST_PARAM_SYNC_CLEANUP_CACHE;
3252                } else if (!strcmp(key, "remove_dst")) {
3253                        err = og_json_parse_string(value, &params->sync_setup.remove_dst);
3254                        params->flags |= OG_REST_PARAM_SYNC_REMOVE_DST;
3255                } else if (!strcmp(key, "diff_id")) {
3256                        err = og_json_parse_string(value, &params->sync_setup.diff_id);
3257                        params->flags |= OG_REST_PARAM_SYNC_DIFF_ID;
3258                } else if (!strcmp(key, "diff_name")) {
3259                        err = og_json_parse_string(value, &params->sync_setup.diff_name);
3260                        params->flags |= OG_REST_PARAM_SYNC_DIFF_NAME;
3261                } else if (!strcmp(key, "path")) {
3262                        err = og_json_parse_string(value, &params->sync_setup.path);
3263                        params->flags |= OG_REST_PARAM_SYNC_PATH;
3264                } else if (!strcmp(key, "method")) {
3265                        err = og_json_parse_string(value, &params->sync_setup.method);
3266                        params->flags |= OG_REST_PARAM_SYNC_METHOD;
3267                }
3268
3269                if (err != 0)
3270                        return err;
3271        }
3272        return err;
3273}
3274
3275#define OG_PARAM_PART_NUMBER                    (1UL << 0)
3276#define OG_PARAM_PART_CODE                      (1UL << 1)
3277#define OG_PARAM_PART_FILESYSTEM                (1UL << 2)
3278#define OG_PARAM_PART_SIZE                      (1UL << 3)
3279#define OG_PARAM_PART_FORMAT                    (1UL << 4)
3280#define OG_PARAM_PART_DISK                      (1UL << 5)
3281#define OG_PARAM_PART_OS                        (1UL << 6)
3282#define OG_PARAM_PART_USED_SIZE                 (1UL << 7)
3283
3284static int og_json_parse_partition(json_t *element,
3285                                   struct og_partition *part,
3286                                   uint64_t required_flags)
3287{
3288        uint64_t flags = 0UL;
3289        const char *key;
3290        json_t *value;
3291        int err = 0;
3292
3293        json_object_foreach(element, key, value) {
3294                if (!strcmp(key, "partition")) {
3295                        err = og_json_parse_string(value, &part->number);
3296                        flags |= OG_PARAM_PART_NUMBER;
3297                } else if (!strcmp(key, "code")) {
3298                        err = og_json_parse_string(value, &part->code);
3299                        flags |= OG_PARAM_PART_CODE;
3300                } else if (!strcmp(key, "filesystem")) {
3301                        err = og_json_parse_string(value, &part->filesystem);
3302                        flags |= OG_PARAM_PART_FILESYSTEM;
3303                } else if (!strcmp(key, "size")) {
3304                        err = og_json_parse_string(value, &part->size);
3305                        flags |= OG_PARAM_PART_SIZE;
3306                } else if (!strcmp(key, "format")) {
3307                        err = og_json_parse_string(value, &part->format);
3308                        flags |= OG_PARAM_PART_FORMAT;
3309                } else if (!strcmp(key, "disk")) {
3310                        err = og_json_parse_string(value, &part->disk);
3311                        flags |= OG_PARAM_PART_DISK;
3312                } else if (!strcmp(key, "os")) {
3313                        err = og_json_parse_string(value, &part->os);
3314                        flags |= OG_PARAM_PART_OS;
3315                } else if (!strcmp(key, "used_size")) {
3316                        err = og_json_parse_string(value, &part->used_size);
3317                        flags |= OG_PARAM_PART_USED_SIZE;
3318                }
3319
3320                if (err < 0)
3321                        return err;
3322        }
3323
3324        if (flags != required_flags)
3325                return -1;
3326
3327        return err;
3328}
3329
3330static int og_json_parse_partition_setup(json_t *element,
3331                                         struct og_msg_params *params)
3332{
3333        unsigned int i;
3334        json_t *k;
3335
3336        if (json_typeof(element) != JSON_ARRAY)
3337                return -1;
3338
3339        for (i = 0; i < json_array_size(element) && i < OG_PARTITION_MAX; ++i) {
3340                k = json_array_get(element, i);
3341
3342                if (json_typeof(k) != JSON_OBJECT)
3343                        return -1;
3344
3345                if (og_json_parse_partition(k, &params->partition_setup[i],
3346                                            OG_PARAM_PART_NUMBER |
3347                                            OG_PARAM_PART_CODE |
3348                                            OG_PARAM_PART_FILESYSTEM |
3349                                            OG_PARAM_PART_SIZE |
3350                                            OG_PARAM_PART_FORMAT) < 0)
3351                        return -1;
3352
3353                params->flags |= (OG_REST_PARAM_PART_0 << i);
3354        }
3355        return 0;
3356}
3357
3358static int og_json_parse_time_params(json_t *element,
3359                                     struct og_msg_params *params)
3360{
3361        const char *key;
3362        json_t *value;
3363        int err = 0;
3364
3365        json_object_foreach(element, key, value) {
3366                if (!strcmp(key, "years")) {
3367                        err = og_json_parse_uint(value, &params->time.years);
3368                        params->flags |= OG_REST_PARAM_TIME_YEARS;
3369                } else if (!strcmp(key, "months")) {
3370                        err = og_json_parse_uint(value, &params->time.months);
3371                        params->flags |= OG_REST_PARAM_TIME_MONTHS;
3372                } else if (!strcmp(key, "days")) {
3373                        err = og_json_parse_uint(value, &params->time.days);
3374                        params->flags |= OG_REST_PARAM_TIME_DAYS;
3375                } else if (!strcmp(key, "hours")) {
3376                        err = og_json_parse_uint(value, &params->time.hours);
3377                        params->flags |= OG_REST_PARAM_TIME_HOURS;
3378                } else if (!strcmp(key, "am_pm")) {
3379                        err = og_json_parse_uint(value, &params->time.am_pm);
3380                        params->flags |= OG_REST_PARAM_TIME_AM_PM;
3381                } else if (!strcmp(key, "minutes")) {
3382                        err = og_json_parse_uint(value, &params->time.minutes);
3383                        params->flags |= OG_REST_PARAM_TIME_MINUTES;
3384                }
3385                if (err != 0)
3386                        return err;
3387        }
3388
3389        return err;
3390}
3391
3392static int og_cmd_post_clients(json_t *element, struct og_msg_params *params)
3393{
3394        const char *key;
3395        json_t *value;
3396        int err = 0;
3397
3398        if (json_typeof(element) != JSON_OBJECT)
3399                return -1;
3400
3401        json_object_foreach(element, key, value) {
3402                if (!strcmp(key, "clients"))
3403                        err = og_json_parse_clients(value, params);
3404
3405                if (err < 0)
3406                        break;
3407        }
3408
3409        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
3410                return -1;
3411
3412        return og_send_request("probe", OG_METHOD_POST, params, NULL);
3413}
3414
3415struct og_buffer {
3416        char    *data;
3417        int     len;
3418};
3419
3420static int og_json_dump_clients(const char *buffer, size_t size, void *data)
3421{
3422        struct og_buffer *og_buffer = (struct og_buffer *)data;
3423
3424        memcpy(og_buffer->data + og_buffer->len, buffer, size);
3425        og_buffer->len += size;
3426
3427        return 0;
3428}
3429
3430static int og_cmd_get_clients(json_t *element, struct og_msg_params *params,
3431                              char *buffer_reply)
3432{
3433        json_t *root, *array, *addr, *state, *object;
3434        struct og_client *client;
3435        struct og_buffer og_buffer = {
3436                .data   = buffer_reply,
3437        };
3438
3439        array = json_array();
3440        if (!array)
3441                return -1;
3442
3443        list_for_each_entry(client, &client_list, list) {
3444                if (!client->agent)
3445                        continue;
3446
3447                object = json_object();
3448                if (!object) {
3449                        json_decref(array);
3450                        return -1;
3451                }
3452                addr = json_string(inet_ntoa(client->addr.sin_addr));
3453                if (!addr) {
3454                        json_decref(object);
3455                        json_decref(array);
3456                        return -1;
3457                }
3458                json_object_set_new(object, "addr", addr);
3459                state = json_string(client->status);
3460                if (!state) {
3461                        json_decref(object);
3462                        json_decref(array);
3463                        return -1;
3464                }
3465                json_object_set_new(object, "state", state);
3466                json_array_append_new(array, object);
3467        }
3468        root = json_pack("{s:o}", "clients", array);
3469        if (!root) {
3470                json_decref(array);
3471                return -1;
3472        }
3473
3474        json_dump_callback(root, og_json_dump_clients, &og_buffer, 0);
3475        json_decref(root);
3476
3477        return 0;
3478}
3479
3480static int og_json_parse_target(json_t *element, struct og_msg_params *params)
3481{
3482        const char *key;
3483        json_t *value;
3484
3485        if (json_typeof(element) != JSON_OBJECT) {
3486                return -1;
3487        }
3488
3489        json_object_foreach(element, key, value) {
3490                if (!strcmp(key, "addr")) {
3491                        if (json_typeof(value) != JSON_STRING)
3492                                return -1;
3493
3494                        params->ips_array[params->ips_array_len] =
3495                                json_string_value(value);
3496
3497                        params->flags |= OG_REST_PARAM_ADDR;
3498                } else if (!strcmp(key, "mac")) {
3499                        if (json_typeof(value) != JSON_STRING)
3500                                return -1;
3501
3502                        params->mac_array[params->ips_array_len] =
3503                                json_string_value(value);
3504
3505                        params->flags |= OG_REST_PARAM_MAC;
3506                }
3507        }
3508
3509        return 0;
3510}
3511
3512static int og_json_parse_targets(json_t *element, struct og_msg_params *params)
3513{
3514        unsigned int i;
3515        json_t *k;
3516        int err;
3517
3518        if (json_typeof(element) != JSON_ARRAY)
3519                return -1;
3520
3521        for (i = 0; i < json_array_size(element); i++) {
3522                k = json_array_get(element, i);
3523
3524                if (json_typeof(k) != JSON_OBJECT)
3525                        return -1;
3526
3527                err = og_json_parse_target(k, params);
3528                if (err < 0)
3529                        return err;
3530
3531                params->ips_array_len++;
3532        }
3533        return 0;
3534}
3535
3536static int og_json_parse_type(json_t *element, struct og_msg_params *params)
3537{
3538        const char *type;
3539
3540        if (json_typeof(element) != JSON_STRING)
3541                return -1;
3542
3543        params->wol_type = json_string_value(element);
3544
3545        type = json_string_value(element);
3546        if (!strcmp(type, "unicast"))
3547                params->wol_type = "2";
3548        else if (!strcmp(type, "broadcast"))
3549                params->wol_type = "1";
3550
3551        params->flags |= OG_REST_PARAM_WOL_TYPE;
3552
3553        return 0;
3554}
3555
3556static int og_cmd_wol(json_t *element, struct og_msg_params *params)
3557{
3558        const char *key;
3559        json_t *value;
3560        int err = 0;
3561
3562        if (json_typeof(element) != JSON_OBJECT)
3563                return -1;
3564
3565        json_object_foreach(element, key, value) {
3566                if (!strcmp(key, "clients")) {
3567                        err = og_json_parse_targets(value, params);
3568                } else if (!strcmp(key, "type")) {
3569                        err = og_json_parse_type(value, params);
3570                }
3571
3572                if (err < 0)
3573                        break;
3574        }
3575
3576        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
3577                                            OG_REST_PARAM_MAC |
3578                                            OG_REST_PARAM_WOL_TYPE))
3579                return -1;
3580
3581        if (!Levanta((char **)params->ips_array, (char **)params->mac_array,
3582                     params->ips_array_len, (char *)params->wol_type))
3583                return -1;
3584
3585        return 0;
3586}
3587
3588static int og_json_parse_run(json_t *element, struct og_msg_params *params)
3589{
3590        if (json_typeof(element) != JSON_STRING)
3591                return -1;
3592
3593        snprintf(params->run_cmd, sizeof(params->run_cmd), "%s",
3594                 json_string_value(element));
3595
3596        params->flags |= OG_REST_PARAM_RUN_CMD;
3597
3598        return 0;
3599}
3600
3601static int og_cmd_run_post(json_t *element, struct og_msg_params *params)
3602{
3603        json_t *value, *clients;
3604        const char *key;
3605        unsigned int i;
3606        int err = 0;
3607
3608        if (json_typeof(element) != JSON_OBJECT)
3609                return -1;
3610
3611        json_object_foreach(element, key, value) {
3612                if (!strcmp(key, "clients"))
3613                        err = og_json_parse_clients(value, params);
3614                else if (!strcmp(key, "run"))
3615                        err = og_json_parse_run(value, params);
3616                else if (!strcmp(key, "echo")) {
3617                        err = og_json_parse_bool(value, &params->echo);
3618                        params->flags |= OG_REST_PARAM_ECHO;
3619                }
3620
3621                if (err < 0)
3622                        break;
3623        }
3624
3625        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
3626                                            OG_REST_PARAM_RUN_CMD |
3627                                            OG_REST_PARAM_ECHO))
3628                return -1;
3629
3630        clients = json_copy(element);
3631        json_object_del(clients, "clients");
3632
3633        err = og_send_request("shell/run", OG_METHOD_POST, params, clients);
3634        if (err < 0)
3635                return err;
3636
3637        for (i = 0; i < params->ips_array_len; i++) {
3638                char filename[4096];
3639                FILE *f;
3640
3641                sprintf(filename, "/tmp/_Seconsola_%s", params->ips_array[i]);
3642                f = fopen(filename, "wt");
3643                fclose(f);
3644        }
3645
3646        return 0;
3647}
3648
3649static int og_cmd_run_get(json_t *element, struct og_msg_params *params,
3650                          char *buffer_reply)
3651{
3652        struct og_buffer og_buffer = {
3653                .data   = buffer_reply,
3654        };
3655        json_t *root, *value, *array;
3656        const char *key;
3657        unsigned int i;
3658        int err = 0;
3659
3660        if (json_typeof(element) != JSON_OBJECT)
3661                return -1;
3662
3663        json_object_foreach(element, key, value) {
3664                if (!strcmp(key, "clients"))
3665                        err = og_json_parse_clients(value, params);
3666
3667                if (err < 0)
3668                        return err;
3669        }
3670
3671        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
3672                return -1;
3673
3674        array = json_array();
3675        if (!array)
3676                return -1;
3677
3678        for (i = 0; i < params->ips_array_len; i++) {
3679                json_t *object, *output, *addr;
3680                char data[4096] = {};
3681                char filename[4096];
3682                int fd, numbytes;
3683
3684                sprintf(filename, "/tmp/_Seconsola_%s", params->ips_array[i]);
3685
3686                fd = open(filename, O_RDONLY);
3687                if (!fd)
3688                        return -1;
3689
3690                numbytes = read(fd, data, sizeof(data));
3691                if (numbytes < 0) {
3692                        close(fd);
3693                        return -1;
3694                }
3695                data[sizeof(data) - 1] = '\0';
3696                close(fd);
3697
3698                object = json_object();
3699                if (!object) {
3700                        json_decref(array);
3701                        return -1;
3702                }
3703                addr = json_string(params->ips_array[i]);
3704                if (!addr) {
3705                        json_decref(object);
3706                        json_decref(array);
3707                        return -1;
3708                }
3709                json_object_set_new(object, "addr", addr);
3710
3711                output = json_string(data);
3712                if (!output) {
3713                        json_decref(object);
3714                        json_decref(array);
3715                        return -1;
3716                }
3717                json_object_set_new(object, "output", output);
3718
3719                json_array_append_new(array, object);
3720        }
3721
3722        root = json_pack("{s:o}", "clients", array);
3723        if (!root)
3724                return -1;
3725
3726        json_dump_callback(root, og_json_dump_clients, &og_buffer, 0);
3727        json_decref(root);
3728
3729        return 0;
3730}
3731
3732static int og_cmd_session(json_t *element, struct og_msg_params *params)
3733{
3734        json_t *clients, *value;
3735        const char *key;
3736        int err = 0;
3737
3738        if (json_typeof(element) != JSON_OBJECT)
3739                return -1;
3740
3741        json_object_foreach(element, key, value) {
3742                if (!strcmp(key, "clients")) {
3743                        err = og_json_parse_clients(value, params);
3744                } else if (!strcmp(key, "disk")) {
3745                        err = og_json_parse_string(value, &params->disk);
3746                        params->flags |= OG_REST_PARAM_DISK;
3747                } else if (!strcmp(key, "partition")) {
3748                        err = og_json_parse_string(value, &params->partition);
3749                        params->flags |= OG_REST_PARAM_PARTITION;
3750                }
3751
3752                if (err < 0)
3753                        return err;
3754        }
3755
3756        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
3757                                            OG_REST_PARAM_DISK |
3758                                            OG_REST_PARAM_PARTITION))
3759                return -1;
3760
3761        clients = json_copy(element);
3762        json_object_del(clients, "clients");
3763
3764        return og_send_request("session", OG_METHOD_POST, params, clients);
3765}
3766
3767static int og_cmd_poweroff(json_t *element, struct og_msg_params *params)
3768{
3769        const char *key;
3770        json_t *value;
3771        int err = 0;
3772
3773        if (json_typeof(element) != JSON_OBJECT)
3774                return -1;
3775
3776        json_object_foreach(element, key, value) {
3777                if (!strcmp(key, "clients"))
3778                        err = og_json_parse_clients(value, params);
3779
3780                if (err < 0)
3781                        break;
3782        }
3783
3784        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
3785                return -1;
3786
3787        return og_send_request("poweroff", OG_METHOD_POST, params, NULL);
3788}
3789
3790static int og_cmd_refresh(json_t *element, struct og_msg_params *params)
3791{
3792        const char *key;
3793        json_t *value;
3794        int err = 0;
3795
3796        if (json_typeof(element) != JSON_OBJECT)
3797                return -1;
3798
3799        json_object_foreach(element, key, value) {
3800                if (!strcmp(key, "clients"))
3801                        err = og_json_parse_clients(value, params);
3802
3803                if (err < 0)
3804                        break;
3805        }
3806
3807        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
3808                return -1;
3809
3810        return og_send_request("refresh", OG_METHOD_GET, params, NULL);
3811}
3812
3813static int og_cmd_reboot(json_t *element, struct og_msg_params *params)
3814{
3815        const char *key;
3816        json_t *value;
3817        int err = 0;
3818
3819        if (json_typeof(element) != JSON_OBJECT)
3820                return -1;
3821
3822        json_object_foreach(element, key, value) {
3823                if (!strcmp(key, "clients"))
3824                        err = og_json_parse_clients(value, params);
3825
3826                if (err < 0)
3827                        break;
3828        }
3829
3830        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
3831                return -1;
3832
3833        return og_send_request("reboot", OG_METHOD_POST, params, NULL);
3834}
3835
3836static int og_cmd_stop(json_t *element, struct og_msg_params *params)
3837{
3838        const char *key;
3839        json_t *value;
3840        int err = 0;
3841
3842        if (json_typeof(element) != JSON_OBJECT)
3843                return -1;
3844
3845        json_object_foreach(element, key, value) {
3846                if (!strcmp(key, "clients"))
3847                        err = og_json_parse_clients(value, params);
3848
3849                if (err < 0)
3850                        break;
3851        }
3852
3853        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
3854                return -1;
3855
3856        return og_send_request("stop", OG_METHOD_POST, params, NULL);
3857}
3858
3859static int og_cmd_hardware(json_t *element, struct og_msg_params *params)
3860{
3861        const char *key;
3862        json_t *value;
3863        int err = 0;
3864
3865        if (json_typeof(element) != JSON_OBJECT)
3866                return -1;
3867
3868        json_object_foreach(element, key, value) {
3869                if (!strcmp(key, "clients"))
3870                        err = og_json_parse_clients(value, params);
3871
3872                if (err < 0)
3873                        break;
3874        }
3875
3876        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
3877                return -1;
3878
3879        return og_send_request("hardware", OG_METHOD_GET, params, NULL);
3880}
3881
3882static int og_cmd_software(json_t *element, struct og_msg_params *params)
3883{
3884        json_t *clients, *value;
3885        const char *key;
3886        int err = 0;
3887
3888        if (json_typeof(element) != JSON_OBJECT)
3889                return -1;
3890
3891        json_object_foreach(element, key, value) {
3892                if (!strcmp(key, "clients"))
3893                        err = og_json_parse_clients(value, params);
3894                else if (!strcmp(key, "disk")) {
3895                        err = og_json_parse_string(value, &params->disk);
3896                        params->flags |= OG_REST_PARAM_DISK;
3897                }
3898                else if (!strcmp(key, "partition")) {
3899                        err = og_json_parse_string(value, &params->partition);
3900                        params->flags |= OG_REST_PARAM_PARTITION;
3901                }
3902
3903                if (err < 0)
3904                        break;
3905        }
3906
3907        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
3908                                            OG_REST_PARAM_DISK |
3909                                            OG_REST_PARAM_PARTITION))
3910                return -1;
3911
3912        clients = json_copy(element);
3913        json_object_del(clients, "clients");
3914
3915        return og_send_request("software", OG_METHOD_POST, params, clients);
3916}
3917
3918static int og_cmd_create_image(json_t *element, struct og_msg_params *params)
3919{
3920        json_t *value, *clients;
3921        const char *key;
3922        int err = 0;
3923
3924        if (json_typeof(element) != JSON_OBJECT)
3925                return -1;
3926
3927        json_object_foreach(element, key, value) {
3928                if (!strcmp(key, "disk")) {
3929                        err = og_json_parse_string(value, &params->disk);
3930                        params->flags |= OG_REST_PARAM_DISK;
3931                } else if (!strcmp(key, "partition")) {
3932                        err = og_json_parse_string(value, &params->partition);
3933                        params->flags |= OG_REST_PARAM_PARTITION;
3934                } else if (!strcmp(key, "name")) {
3935                        err = og_json_parse_string(value, &params->name);
3936                        params->flags |= OG_REST_PARAM_NAME;
3937                } else if (!strcmp(key, "repository")) {
3938                        err = og_json_parse_string(value, &params->repository);
3939                        params->flags |= OG_REST_PARAM_REPO;
3940                } else if (!strcmp(key, "clients")) {
3941                        err = og_json_parse_clients(value, params);
3942                } else if (!strcmp(key, "id")) {
3943                        err = og_json_parse_string(value, &params->id);
3944                        params->flags |= OG_REST_PARAM_ID;
3945                } else if (!strcmp(key, "code")) {
3946                        err = og_json_parse_string(value, &params->code);
3947                        params->flags |= OG_REST_PARAM_CODE;
3948                }
3949
3950                if (err < 0)
3951                        break;
3952        }
3953
3954        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
3955                                            OG_REST_PARAM_DISK |
3956                                            OG_REST_PARAM_PARTITION |
3957                                            OG_REST_PARAM_CODE |
3958                                            OG_REST_PARAM_ID |
3959                                            OG_REST_PARAM_NAME |
3960                                            OG_REST_PARAM_REPO))
3961                return -1;
3962
3963        clients = json_copy(element);
3964        json_object_del(clients, "clients");
3965
3966        return og_send_request("image/create", OG_METHOD_POST, params, clients);
3967}
3968
3969static int og_cmd_restore_image(json_t *element, struct og_msg_params *params)
3970{
3971        json_t *clients, *value;
3972        const char *key;
3973        int err = 0;
3974
3975        if (json_typeof(element) != JSON_OBJECT)
3976                return -1;
3977
3978        json_object_foreach(element, key, value) {
3979                if (!strcmp(key, "disk")) {
3980                        err = og_json_parse_string(value, &params->disk);
3981                        params->flags |= OG_REST_PARAM_DISK;
3982                } else if (!strcmp(key, "partition")) {
3983                        err = og_json_parse_string(value, &params->partition);
3984                        params->flags |= OG_REST_PARAM_PARTITION;
3985                } else if (!strcmp(key, "name")) {
3986                        err = og_json_parse_string(value, &params->name);
3987                        params->flags |= OG_REST_PARAM_NAME;
3988                } else if (!strcmp(key, "repository")) {
3989                        err = og_json_parse_string(value, &params->repository);
3990                        params->flags |= OG_REST_PARAM_REPO;
3991                } else if (!strcmp(key, "clients")) {
3992                        err = og_json_parse_clients(value, params);
3993                } else if (!strcmp(key, "type")) {
3994                        err = og_json_parse_string(value, &params->type);
3995                        params->flags |= OG_REST_PARAM_TYPE;
3996                } else if (!strcmp(key, "profile")) {
3997                        err = og_json_parse_string(value, &params->profile);
3998                        params->flags |= OG_REST_PARAM_PROFILE;
3999                } else if (!strcmp(key, "id")) {
4000                        err = og_json_parse_string(value, &params->id);
4001                        params->flags |= OG_REST_PARAM_ID;
4002                }
4003
4004                if (err < 0)
4005                        break;
4006        }
4007
4008        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
4009                                            OG_REST_PARAM_DISK |
4010                                            OG_REST_PARAM_PARTITION |
4011                                            OG_REST_PARAM_NAME |
4012                                            OG_REST_PARAM_REPO |
4013                                            OG_REST_PARAM_TYPE |
4014                                            OG_REST_PARAM_PROFILE |
4015                                            OG_REST_PARAM_ID))
4016                return -1;
4017
4018        clients = json_copy(element);
4019        json_object_del(clients, "clients");
4020
4021        return og_send_request("image/restore", OG_METHOD_POST, params, clients);
4022}
4023
4024static int og_cmd_setup(json_t *element, struct og_msg_params *params)
4025{
4026        json_t *value, *clients;
4027        const char *key;
4028        int err = 0;
4029
4030        if (json_typeof(element) != JSON_OBJECT)
4031                return -1;
4032
4033        json_object_foreach(element, key, value) {
4034                if (!strcmp(key, "clients")) {
4035                        err = og_json_parse_clients(value, params);
4036                } else if (!strcmp(key, "disk")) {
4037                        err = og_json_parse_string(value, &params->disk);
4038                        params->flags |= OG_REST_PARAM_DISK;
4039                } else if (!strcmp(key, "cache")) {
4040                        err = og_json_parse_string(value, &params->cache);
4041                        params->flags |= OG_REST_PARAM_CACHE;
4042                } else if (!strcmp(key, "cache_size")) {
4043                        err = og_json_parse_string(value, &params->cache_size);
4044                        params->flags |= OG_REST_PARAM_CACHE_SIZE;
4045                } else if (!strcmp(key, "partition_setup")) {
4046                        err = og_json_parse_partition_setup(value, params);
4047                }
4048
4049                if (err < 0)
4050                        break;
4051        }
4052
4053        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
4054                                            OG_REST_PARAM_DISK |
4055                                            OG_REST_PARAM_CACHE |
4056                                            OG_REST_PARAM_CACHE_SIZE |
4057                                            OG_REST_PARAM_PART_0 |
4058                                            OG_REST_PARAM_PART_1 |
4059                                            OG_REST_PARAM_PART_2 |
4060                                            OG_REST_PARAM_PART_3))
4061                return -1;
4062
4063        clients = json_copy(element);
4064        json_object_del(clients, "clients");
4065
4066        return og_send_request("setup", OG_METHOD_POST, params, clients);
4067}
4068
4069static int og_cmd_run_schedule(json_t *element, struct og_msg_params *params)
4070{
4071        const char *key;
4072        json_t *value;
4073        int err = 0;
4074
4075        json_object_foreach(element, key, value) {
4076                if (!strcmp(key, "clients"))
4077                        err = og_json_parse_clients(value, params);
4078
4079                if (err < 0)
4080                        break;
4081        }
4082
4083        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
4084                return -1;
4085
4086        return og_send_request("run/schedule", OG_METHOD_GET, params, NULL);
4087}
4088
4089static int og_cmd_create_basic_image(json_t *element, struct og_msg_params *params)
4090{
4091        char buf[4096] = {};
4092        int err = 0, len;
4093        const char *key;
4094        json_t *value;
4095        TRAMA *msg;
4096
4097        if (json_typeof(element) != JSON_OBJECT)
4098                return -1;
4099
4100        json_object_foreach(element, key, value) {
4101                if (!strcmp(key, "clients")) {
4102                        err = og_json_parse_clients(value, params);
4103                } else if (!strcmp(key, "disk")) {
4104                        err = og_json_parse_string(value, &params->disk);
4105                        params->flags |= OG_REST_PARAM_DISK;
4106                } else if (!strcmp(key, "partition")) {
4107                        err = og_json_parse_string(value, &params->partition);
4108                        params->flags |= OG_REST_PARAM_PARTITION;
4109                } else if (!strcmp(key, "code")) {
4110                        err = og_json_parse_string(value, &params->code);
4111                        params->flags |= OG_REST_PARAM_CODE;
4112                } else if (!strcmp(key, "id")) {
4113                        err = og_json_parse_string(value, &params->id);
4114                        params->flags |= OG_REST_PARAM_ID;
4115                } else if (!strcmp(key, "name")) {
4116                        err = og_json_parse_string(value, &params->name);
4117                        params->flags |= OG_REST_PARAM_NAME;
4118                } else if (!strcmp(key, "repository")) {
4119                        err = og_json_parse_string(value, &params->repository);
4120                        params->flags |= OG_REST_PARAM_REPO;
4121                } else if (!strcmp(key, "sync_params")) {
4122                        err = og_json_parse_sync_params(value, params);
4123                }
4124
4125                if (err < 0)
4126                        break;
4127        }
4128
4129        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
4130                                            OG_REST_PARAM_DISK |
4131                                            OG_REST_PARAM_PARTITION |
4132                                            OG_REST_PARAM_CODE |
4133                                            OG_REST_PARAM_ID |
4134                                            OG_REST_PARAM_NAME |
4135                                            OG_REST_PARAM_REPO |
4136                                            OG_REST_PARAM_SYNC_SYNC |
4137                                            OG_REST_PARAM_SYNC_DIFF |
4138                                            OG_REST_PARAM_SYNC_REMOVE |
4139                                            OG_REST_PARAM_SYNC_COMPRESS |
4140                                            OG_REST_PARAM_SYNC_CLEANUP |
4141                                            OG_REST_PARAM_SYNC_CACHE |
4142                                            OG_REST_PARAM_SYNC_CLEANUP_CACHE |
4143                                            OG_REST_PARAM_SYNC_REMOVE_DST))
4144                return -1;
4145
4146        len = snprintf(buf, sizeof(buf),
4147                       "nfn=CrearImagenBasica\rdsk=%s\rpar=%s\rcpt=%s\ridi=%s\r"
4148                       "nci=%s\ripr=%s\rrti=\rmsy=%s\rwhl=%s\reli=%s\rcmp=%s\rbpi=%s\r"
4149                       "cpc=%s\rbpc=%s\rnba=%s\r",
4150                       params->disk, params->partition, params->code, params->id,
4151                       params->name, params->repository, params->sync_setup.sync,
4152                       params->sync_setup.diff, params->sync_setup.remove,
4153                       params->sync_setup.compress, params->sync_setup.cleanup,
4154                       params->sync_setup.cache, params->sync_setup.cleanup_cache,
4155                       params->sync_setup.remove_dst);
4156
4157        msg = og_msg_alloc(buf, len);
4158        if (!msg)
4159                return -1;
4160
4161        og_send_cmd((char **)params->ips_array, params->ips_array_len,
4162                    CLIENTE_OCUPADO, msg);
4163
4164        og_msg_free(msg);
4165
4166        return 0;
4167}
4168
4169static int og_cmd_create_incremental_image(json_t *element, struct og_msg_params *params)
4170{
4171        char buf[4096] = {};
4172        int err = 0, len;
4173        const char *key;
4174        json_t *value;
4175        TRAMA *msg;
4176
4177        if (json_typeof(element) != JSON_OBJECT)
4178                return -1;
4179
4180        json_object_foreach(element, key, value) {
4181                if (!strcmp(key, "clients"))
4182                        err = og_json_parse_clients(value, params);
4183                else if (!strcmp(key, "disk")) {
4184                        err = og_json_parse_string(value, &params->disk);
4185                        params->flags |= OG_REST_PARAM_DISK;
4186                } else if (!strcmp(key, "partition")) {
4187                        err = og_json_parse_string(value, &params->partition);
4188                        params->flags |= OG_REST_PARAM_PARTITION;
4189                } else if (!strcmp(key, "id")) {
4190                        err = og_json_parse_string(value, &params->id);
4191                        params->flags |= OG_REST_PARAM_ID;
4192                } else if (!strcmp(key, "name")) {
4193                        err = og_json_parse_string(value, &params->name);
4194                        params->flags |= OG_REST_PARAM_NAME;
4195                } else if (!strcmp(key, "repository")) {
4196                        err = og_json_parse_string(value, &params->repository);
4197                        params->flags |= OG_REST_PARAM_REPO;
4198                } else if (!strcmp(key, "sync_params")) {
4199                        err = og_json_parse_sync_params(value, params);
4200                }
4201
4202                if (err < 0)
4203                        break;
4204        }
4205
4206        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
4207                                            OG_REST_PARAM_DISK |
4208                                            OG_REST_PARAM_PARTITION |
4209                                            OG_REST_PARAM_ID |
4210                                            OG_REST_PARAM_NAME |
4211                                            OG_REST_PARAM_REPO |
4212                                            OG_REST_PARAM_SYNC_SYNC |
4213                                            OG_REST_PARAM_SYNC_PATH |
4214                                            OG_REST_PARAM_SYNC_DIFF |
4215                                            OG_REST_PARAM_SYNC_DIFF_ID |
4216                                            OG_REST_PARAM_SYNC_DIFF_NAME |
4217                                            OG_REST_PARAM_SYNC_REMOVE |
4218                                            OG_REST_PARAM_SYNC_COMPRESS |
4219                                            OG_REST_PARAM_SYNC_CLEANUP |
4220                                            OG_REST_PARAM_SYNC_CACHE |
4221                                            OG_REST_PARAM_SYNC_CLEANUP_CACHE |
4222                                            OG_REST_PARAM_SYNC_REMOVE_DST))
4223                return -1;
4224
4225        len = snprintf(buf, sizeof(buf),
4226                       "nfn=CrearSoftIncremental\rdsk=%s\rpar=%s\ridi=%s\rnci=%s\r"
4227                       "rti=%s\ripr=%s\ridf=%s\rncf=%s\rmsy=%s\rwhl=%s\reli=%s\rcmp=%s\r"
4228                       "bpi=%s\rcpc=%s\rbpc=%s\rnba=%s\r",
4229                       params->disk, params->partition, params->id, params->name,
4230                       params->sync_setup.path, params->repository, params->sync_setup.diff_id,
4231                       params->sync_setup.diff_name, params->sync_setup.sync,
4232                       params->sync_setup.diff, params->sync_setup.remove_dst,
4233                       params->sync_setup.compress, params->sync_setup.cleanup,
4234                       params->sync_setup.cache, params->sync_setup.cleanup_cache,
4235                       params->sync_setup.remove_dst);
4236
4237        msg = og_msg_alloc(buf, len);
4238        if (!msg)
4239                return -1;
4240
4241        og_send_cmd((char **)params->ips_array, params->ips_array_len,
4242                    CLIENTE_OCUPADO, msg);
4243
4244        og_msg_free(msg);
4245
4246        return 0;
4247}
4248
4249static int og_cmd_restore_basic_image(json_t *element, struct og_msg_params *params)
4250{
4251        char buf[4096] = {};
4252        int err = 0, len;
4253        const char *key;
4254        json_t *value;
4255        TRAMA *msg;
4256
4257        if (json_typeof(element) != JSON_OBJECT)
4258                return -1;
4259
4260        json_object_foreach(element, key, value) {
4261                if (!strcmp(key, "clients")) {
4262                        err = og_json_parse_clients(value, params);
4263                } else if (!strcmp(key, "disk")) {
4264                        err = og_json_parse_string(value, &params->disk);
4265                        params->flags |= OG_REST_PARAM_DISK;
4266                } else if (!strcmp(key, "partition")) {
4267                        err = og_json_parse_string(value, &params->partition);
4268                        params->flags |= OG_REST_PARAM_PARTITION;
4269                } else if (!strcmp(key, "id")) {
4270                        err = og_json_parse_string(value, &params->id);
4271                        params->flags |= OG_REST_PARAM_ID;
4272                } else if (!strcmp(key, "name")) {
4273                        err = og_json_parse_string(value, &params->name);
4274                        params->flags |= OG_REST_PARAM_NAME;
4275                } else if (!strcmp(key, "repository")) {
4276                        err = og_json_parse_string(value, &params->repository);
4277                        params->flags |= OG_REST_PARAM_REPO;
4278                } else if (!strcmp(key, "profile")) {
4279                        err = og_json_parse_string(value, &params->profile);
4280                        params->flags |= OG_REST_PARAM_PROFILE;
4281                } else if (!strcmp(key, "type")) {
4282                        err = og_json_parse_string(value, &params->type);
4283                        params->flags |= OG_REST_PARAM_TYPE;
4284                } else if (!strcmp(key, "sync_params")) {
4285                        err = og_json_parse_sync_params(value, params);
4286                }
4287
4288                if (err < 0)
4289                        break;
4290        }
4291
4292        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
4293                                            OG_REST_PARAM_DISK |
4294                                            OG_REST_PARAM_PARTITION |
4295                                            OG_REST_PARAM_ID |
4296                                            OG_REST_PARAM_NAME |
4297                                            OG_REST_PARAM_REPO |
4298                                            OG_REST_PARAM_PROFILE |
4299                                            OG_REST_PARAM_TYPE |
4300                                            OG_REST_PARAM_SYNC_PATH |
4301                                            OG_REST_PARAM_SYNC_METHOD |
4302                                            OG_REST_PARAM_SYNC_SYNC |
4303                                            OG_REST_PARAM_SYNC_DIFF |
4304                                            OG_REST_PARAM_SYNC_REMOVE |
4305                                            OG_REST_PARAM_SYNC_COMPRESS |
4306                                            OG_REST_PARAM_SYNC_CLEANUP |
4307                                            OG_REST_PARAM_SYNC_CACHE |
4308                                            OG_REST_PARAM_SYNC_CLEANUP_CACHE |
4309                                            OG_REST_PARAM_SYNC_REMOVE_DST))
4310                return -1;
4311
4312        len = snprintf(buf, sizeof(buf),
4313                       "nfn=RestaurarImagenBasica\rdsk=%s\rpar=%s\ridi=%s\rnci=%s\r"
4314                           "ipr=%s\rifs=%s\rrti=%s\rmet=%s\rmsy=%s\rtpt=%s\rwhl=%s\r"
4315                           "eli=%s\rcmp=%s\rbpi=%s\rcpc=%s\rbpc=%s\rnba=%s\r",
4316                       params->disk, params->partition, params->id, params->name,
4317                           params->repository, params->profile, params->sync_setup.path,
4318                           params->sync_setup.method, params->sync_setup.sync, params->type,
4319                           params->sync_setup.diff, params->sync_setup.remove,
4320                       params->sync_setup.compress, params->sync_setup.cleanup,
4321                       params->sync_setup.cache, params->sync_setup.cleanup_cache,
4322                       params->sync_setup.remove_dst);
4323
4324        msg = og_msg_alloc(buf, len);
4325        if (!msg)
4326                return -1;
4327
4328        og_send_cmd((char **)params->ips_array, params->ips_array_len,
4329                    CLIENTE_OCUPADO, msg);
4330
4331        og_msg_free(msg);
4332
4333        return 0;
4334}
4335
4336static int og_cmd_restore_incremental_image(json_t *element, struct og_msg_params *params)
4337{
4338        char buf[4096] = {};
4339        int err = 0, len;
4340        const char *key;
4341        json_t *value;
4342        TRAMA *msg;
4343
4344        if (json_typeof(element) != JSON_OBJECT)
4345                return -1;
4346
4347        json_object_foreach(element, key, value) {
4348                if (!strcmp(key, "clients")) {
4349                        err = og_json_parse_clients(value, params);
4350                } else if (!strcmp(key, "disk")) {
4351                        err = og_json_parse_string(value, &params->disk);
4352                        params->flags |= OG_REST_PARAM_DISK;
4353                } else if (!strcmp(key, "partition")) {
4354                        err = og_json_parse_string(value, &params->partition);
4355                        params->flags |= OG_REST_PARAM_PARTITION;
4356                } else if (!strcmp(key, "id")) {
4357                        err = og_json_parse_string(value, &params->id);
4358                        params->flags |= OG_REST_PARAM_ID;
4359                } else if (!strcmp(key, "name")) {
4360                        err = og_json_parse_string(value, &params->name);
4361                        params->flags |= OG_REST_PARAM_NAME;
4362                } else if (!strcmp(key, "repository")) {
4363                        err = og_json_parse_string(value, &params->repository);
4364                        params->flags |= OG_REST_PARAM_REPO;
4365                } else if (!strcmp(key, "profile")) {
4366                        err = og_json_parse_string(value, &params->profile);
4367                        params->flags |= OG_REST_PARAM_PROFILE;
4368                } else if (!strcmp(key, "type")) {
4369                        err = og_json_parse_string(value, &params->type);
4370                        params->flags |= OG_REST_PARAM_TYPE;
4371                } else if (!strcmp(key, "sync_params")) {
4372                        err = og_json_parse_sync_params(value, params);
4373                }
4374
4375                if (err < 0)
4376                        break;
4377        }
4378
4379        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
4380                                            OG_REST_PARAM_DISK |
4381                                            OG_REST_PARAM_PARTITION |
4382                                            OG_REST_PARAM_ID |
4383                                            OG_REST_PARAM_NAME |
4384                                            OG_REST_PARAM_REPO |
4385                                            OG_REST_PARAM_PROFILE |
4386                                            OG_REST_PARAM_TYPE |
4387                                            OG_REST_PARAM_SYNC_DIFF_ID |
4388                                            OG_REST_PARAM_SYNC_DIFF_NAME |
4389                                            OG_REST_PARAM_SYNC_PATH |
4390                                            OG_REST_PARAM_SYNC_METHOD |
4391                                            OG_REST_PARAM_SYNC_SYNC |
4392                                            OG_REST_PARAM_SYNC_DIFF |
4393                                            OG_REST_PARAM_SYNC_REMOVE |
4394                                            OG_REST_PARAM_SYNC_COMPRESS |
4395                                            OG_REST_PARAM_SYNC_CLEANUP |
4396                                            OG_REST_PARAM_SYNC_CACHE |
4397                                            OG_REST_PARAM_SYNC_CLEANUP_CACHE |
4398                                            OG_REST_PARAM_SYNC_REMOVE_DST))
4399                return -1;
4400
4401        len = snprintf(buf, sizeof(buf),
4402                       "nfn=RestaurarSoftIncremental\rdsk=%s\rpar=%s\ridi=%s\rnci=%s\r"
4403                           "ipr=%s\rifs=%s\ridf=%s\rncf=%s\rrti=%s\rmet=%s\rmsy=%s\r"
4404                           "tpt=%s\rwhl=%s\reli=%s\rcmp=%s\rbpi=%s\rcpc=%s\rbpc=%s\r"
4405                           "nba=%s\r",
4406                       params->disk, params->partition, params->id, params->name,
4407                           params->repository, params->profile, params->sync_setup.diff_id,
4408                           params->sync_setup.diff_name, params->sync_setup.path,
4409                           params->sync_setup.method, params->sync_setup.sync, params->type,
4410                           params->sync_setup.diff, params->sync_setup.remove,
4411                       params->sync_setup.compress, params->sync_setup.cleanup,
4412                       params->sync_setup.cache, params->sync_setup.cleanup_cache,
4413                       params->sync_setup.remove_dst);
4414
4415        msg = og_msg_alloc(buf, len);
4416        if (!msg)
4417                return -1;
4418
4419        og_send_cmd((char **)params->ips_array, params->ips_array_len,
4420                    CLIENTE_OCUPADO, msg);
4421
4422        og_msg_free(msg);
4423
4424        return 0;
4425}
4426
4427static int og_queue_task_command(struct og_dbi *dbi, const struct og_task *task,
4428                                 char *query)
4429{
4430        struct og_cmd *cmd;
4431        const char *msglog;
4432        dbi_result result;
4433
4434        result = dbi_conn_queryf(dbi->conn, query);
4435        if (!result) {
4436                dbi_conn_error(dbi->conn, &msglog);
4437                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
4438                       __func__, __LINE__, msglog);
4439                return -1;
4440        }
4441
4442        while (dbi_result_next_row(result)) {
4443                cmd = (struct og_cmd *)calloc(1, sizeof(struct og_cmd));
4444                if (!cmd) {
4445                        dbi_result_free(result);
4446                        return -1;
4447                }
4448
4449                cmd->client_id  = dbi_result_get_uint(result, "idordenador");
4450                cmd->params     = task->params;
4451
4452                cmd->ip         = strdup(dbi_result_get_string(result, "ip"));
4453                cmd->mac        = strdup(dbi_result_get_string(result, "mac"));
4454
4455                list_add_tail(&cmd->list, &cmd_list);
4456
4457        }
4458
4459        dbi_result_free(result);
4460
4461        return 0;
4462}
4463
4464static int og_queue_task_group_clients(struct og_dbi *dbi, struct og_task *task,
4465                                       char *query)
4466{
4467
4468        const char *msglog;
4469        dbi_result result;
4470
4471        result = dbi_conn_queryf(dbi->conn, query);
4472        if (!result) {
4473                dbi_conn_error(dbi->conn, &msglog);
4474                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
4475                       __func__, __LINE__, msglog);
4476                return -1;
4477        }
4478
4479        while (dbi_result_next_row(result)) {
4480                uint32_t group_id = dbi_result_get_uint(result, "idgrupo");
4481
4482                sprintf(query, "SELECT idgrupo FROM gruposordenadores "
4483                                "WHERE grupoid=%d", group_id);
4484                if (og_queue_task_group_clients(dbi, task, query)) {
4485                        dbi_result_free(result);
4486                        return -1;
4487                }
4488
4489                sprintf(query,"SELECT ip, mac, idordenador FROM ordenadores "
4490                              "WHERE grupoid=%d", group_id);
4491                if (og_queue_task_command(dbi, task, query)) {
4492                        dbi_result_free(result);
4493                        return -1;
4494                }
4495
4496        }
4497
4498        dbi_result_free(result);
4499
4500        return 0;
4501}
4502
4503static int og_queue_task_classrooms(struct og_dbi *dbi, struct og_task *task,
4504                                    char *query)
4505{
4506
4507        const char *msglog;
4508        dbi_result result;
4509
4510        result = dbi_conn_queryf(dbi->conn, query);
4511        if (!result) {
4512                dbi_conn_error(dbi->conn, &msglog);
4513                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
4514                       __func__, __LINE__, msglog);
4515                return -1;
4516        }
4517
4518        while (dbi_result_next_row(result)) {
4519                uint32_t classroom_id = dbi_result_get_uint(result, "idaula");
4520
4521                sprintf(query, "SELECT idgrupo FROM gruposordenadores "
4522                                "WHERE idaula=%d AND grupoid=0", classroom_id);
4523                if (og_queue_task_group_clients(dbi, task, query)) {
4524                        dbi_result_free(result);
4525                        return -1;
4526                }
4527
4528                sprintf(query,"SELECT ip, mac, idordenador FROM ordenadores "
4529                                "WHERE idaula=%d AND grupoid=0", classroom_id);
4530                if (og_queue_task_command(dbi, task, query)) {
4531                        dbi_result_free(result);
4532                        return -1;
4533                }
4534
4535        }
4536
4537        dbi_result_free(result);
4538
4539        return 0;
4540}
4541
4542static int og_queue_task_group_classrooms(struct og_dbi *dbi,
4543                                          struct og_task *task, char *query)
4544{
4545
4546        const char *msglog;
4547        dbi_result result;
4548
4549        result = dbi_conn_queryf(dbi->conn, query);
4550        if (!result) {
4551                dbi_conn_error(dbi->conn, &msglog);
4552                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
4553                       __func__, __LINE__, msglog);
4554                return -1;
4555        }
4556
4557        while (dbi_result_next_row(result)) {
4558                uint32_t group_id = dbi_result_get_uint(result, "idgrupo");
4559
4560                sprintf(query, "SELECT idgrupo FROM grupos "
4561                                "WHERE grupoid=%d AND tipo=%d", group_id, AMBITO_GRUPOSAULAS);
4562                if (og_queue_task_group_classrooms(dbi, task, query)) {
4563                        dbi_result_free(result);
4564                        return -1;
4565                }
4566
4567                sprintf(query,"SELECT idaula FROM aulas WHERE grupoid=%d", group_id);
4568                if (og_queue_task_classrooms(dbi, task, query)) {
4569                        dbi_result_free(result);
4570                        return -1;
4571                }
4572
4573        }
4574
4575        dbi_result_free(result);
4576
4577        return 0;
4578}
4579
4580static int og_queue_task_center(struct og_dbi *dbi, struct og_task *task,
4581                                char *query)
4582{
4583
4584        sprintf(query,"SELECT idgrupo FROM grupos WHERE idcentro=%i AND grupoid=0 AND tipo=%d",
4585                task->scope, AMBITO_GRUPOSAULAS);
4586        if (og_queue_task_group_classrooms(dbi, task, query))
4587                return -1;
4588
4589        sprintf(query,"SELECT idaula FROM aulas WHERE idcentro=%i AND grupoid=0",
4590                task->scope);
4591        if (og_queue_task_classrooms(dbi, task, query))
4592                return -1;
4593
4594        return 0;
4595}
4596
4597static int og_queue_task_clients(struct og_dbi *dbi, struct og_task *task)
4598{
4599        char query[4096];
4600
4601        switch (task->type_scope) {
4602                case AMBITO_CENTROS:
4603                        return og_queue_task_center(dbi, task, query);
4604                case AMBITO_GRUPOSAULAS:
4605                        sprintf(query, "SELECT idgrupo FROM grupos "
4606                                       "WHERE idgrupo=%i AND tipo=%d",
4607                                       task->scope, AMBITO_GRUPOSAULAS);
4608                        return og_queue_task_group_classrooms(dbi, task, query);
4609                case AMBITO_AULAS:
4610                        sprintf(query, "SELECT idaula FROM aulas "
4611                                       "WHERE idaula = %d", task->scope);
4612                        return og_queue_task_classrooms(dbi, task, query);
4613                case AMBITO_GRUPOSORDENADORES:
4614                        sprintf(query, "SELECT idgrupo FROM gruposordenadores "
4615                                       "WHERE idgrupo = %d", task->scope);
4616                        return og_queue_task_group_clients(dbi, task, query);
4617                case AMBITO_ORDENADORES:
4618                        sprintf(query, "SELECT ip, mac, idordenador "
4619                                       "FROM ordenadores "
4620                                       "WHERE idordenador = %d", task->scope);
4621                        return og_queue_task_command(dbi, task, query);
4622        }
4623        return 0;
4624}
4625
4626static int og_dbi_queue_procedure(struct og_dbi *dbi, struct og_task *task)
4627{
4628        uint32_t procedure_id;
4629        const char *msglog;
4630        dbi_result result;
4631
4632        result = dbi_conn_queryf(dbi->conn,
4633                        "SELECT parametros, procedimientoid "
4634                        "FROM procedimientos_acciones "
4635                        "WHERE idprocedimiento=%d ORDER BY orden", task->procedure_id);
4636        if (!result) {
4637                dbi_conn_error(dbi->conn, &msglog);
4638                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
4639                       __func__, __LINE__, msglog);
4640                return -1;
4641        }
4642
4643        while (dbi_result_next_row(result)) {
4644                procedure_id = dbi_result_get_uint(result, "procedimientoid");
4645                if (procedure_id > 0) {
4646                        task->procedure_id = procedure_id;
4647                        if (og_dbi_queue_procedure(dbi, task))
4648                                return -1;
4649                        continue;
4650                }
4651
4652                task->params    = strdup(dbi_result_get_string(result, "parametros"));
4653                if (og_queue_task_clients(dbi, task))
4654                        return -1;
4655        }
4656
4657        dbi_result_free(result);
4658
4659        return 0;
4660}
4661
4662static int og_dbi_queue_task(struct og_dbi *dbi, uint32_t task_id)
4663{
4664        struct og_task task = {};
4665        uint32_t task_id_next;
4666        const char *msglog;
4667        dbi_result result;
4668
4669        result = dbi_conn_queryf(dbi->conn,
4670                        "SELECT tareas_acciones.orden, "
4671                                "tareas_acciones.idprocedimiento, "
4672                                "tareas_acciones.tareaid, "
4673                                "tareas.ambito, "
4674                                "tareas.idambito, "
4675                                "tareas.restrambito "
4676                        " FROM tareas"
4677                                " INNER JOIN tareas_acciones ON tareas_acciones.idtarea=tareas.idtarea"
4678                        " WHERE tareas_acciones.idtarea=%u ORDER BY tareas_acciones.orden ASC", task_id);
4679        if (!result) {
4680                dbi_conn_error(dbi->conn, &msglog);
4681                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
4682                       __func__, __LINE__, msglog);
4683                return -1;
4684        }
4685
4686        while (dbi_result_next_row(result)) {
4687                task_id_next = dbi_result_get_uint(result, "procedimientoid");
4688
4689                if (task_id_next > 0) {
4690                        if (og_dbi_queue_task(dbi, task_id_next))
4691                                return -1;
4692
4693                        continue;
4694                }
4695                task.procedure_id = dbi_result_get_uint(result, "idprocedimiento");
4696                task.type_scope = dbi_result_get_uint(result, "ambito");
4697                task.scope = dbi_result_get_uint(result, "idambito");
4698                task.filtered_scope = dbi_result_get_string(result, "restrambito");
4699
4700                og_dbi_queue_procedure(dbi, &task);
4701        }
4702
4703        dbi_result_free(result);
4704
4705        return 0;
4706}
4707
4708void og_dbi_schedule_task(unsigned int task_id)
4709{
4710        struct og_msg_params params = {};
4711        bool duplicated = false;
4712        struct og_cmd *cmd;
4713        struct og_dbi *dbi;
4714        unsigned int i;
4715
4716        dbi = og_dbi_open(&dbi_config);
4717        if (!dbi) {
4718                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
4719                       __func__, __LINE__);
4720                return;
4721        }
4722        og_dbi_queue_task(dbi, task_id);
4723        og_dbi_close(dbi);
4724
4725        list_for_each_entry(cmd, &cmd_list, list) {
4726                for (i = 0; i < params.ips_array_len; i++) {
4727                        if (!strncmp(cmd->ip, params.ips_array[i],
4728                                     OG_DB_IP_MAXLEN)) {
4729                                duplicated = true;
4730                                break;
4731                        }
4732                }
4733
4734                if (!duplicated)
4735                        params.ips_array[params.ips_array_len++] = cmd->ip;
4736                else
4737                        duplicated = false;
4738        }
4739
4740        og_send_request("run/schedule", OG_METHOD_GET, &params, NULL);
4741}
4742
4743static int og_cmd_task_post(json_t *element, struct og_msg_params *params)
4744{
4745        struct og_cmd *cmd;
4746        struct og_dbi *dbi;
4747        const char *key;
4748        json_t *value;
4749        int err;
4750
4751        if (json_typeof(element) != JSON_OBJECT)
4752                return -1;
4753
4754        json_object_foreach(element, key, value) {
4755                if (!strcmp(key, "task")) {
4756                        err = og_json_parse_string(value, &params->task_id);
4757                        params->flags |= OG_REST_PARAM_TASK;
4758                }
4759
4760                if (err < 0)
4761                        break;
4762        }
4763
4764        if (!og_msg_params_validate(params, OG_REST_PARAM_TASK))
4765                return -1;
4766
4767        dbi = og_dbi_open(&dbi_config);
4768        if (!dbi) {
4769                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
4770                           __func__, __LINE__);
4771                return -1;
4772        }
4773
4774        og_dbi_queue_task(dbi, atoi(params->task_id));
4775        og_dbi_close(dbi);
4776
4777        list_for_each_entry(cmd, &cmd_list, list)
4778                params->ips_array[params->ips_array_len++] = cmd->ip;
4779
4780        return og_send_request("run/schedule", OG_METHOD_GET, params, NULL);
4781}
4782
4783static int og_dbi_schedule_get(void)
4784{
4785        uint32_t schedule_id, task_id;
4786        struct og_schedule_time time;
4787        struct og_dbi *dbi;
4788        const char *msglog;
4789        dbi_result result;
4790
4791        dbi = og_dbi_open(&dbi_config);
4792        if (!dbi) {
4793                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
4794                       __func__, __LINE__);
4795                return -1;
4796        }
4797
4798        result = dbi_conn_queryf(dbi->conn,
4799                                 "SELECT idprogramacion, tipoaccion, identificador, "
4800                                 "sesion, annos, meses, diario, dias, semanas, horas, "
4801                                 "ampm, minutos FROM programaciones "
4802                                 "WHERE suspendida = 0");
4803        if (!result) {
4804                dbi_conn_error(dbi->conn, &msglog);
4805                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
4806                       __func__, __LINE__, msglog);
4807                return -1;
4808        }
4809
4810        while (dbi_result_next_row(result)) {
4811                memset(&time, 0, sizeof(time));
4812                schedule_id = dbi_result_get_uint(result, "idprogramacion");
4813                task_id = dbi_result_get_uint(result, "identificador");
4814                time.years = dbi_result_get_uint(result, "annos");
4815                time.months = dbi_result_get_uint(result, "meses");
4816                time.weeks = dbi_result_get_uint(result, "semanas");
4817                time.week_days = dbi_result_get_uint(result, "dias");
4818                time.days = dbi_result_get_uint(result, "diario");
4819                time.hours = dbi_result_get_uint(result, "horas");
4820                time.am_pm = dbi_result_get_uint(result, "ampm");
4821                time.minutes = dbi_result_get_uint(result, "minutos");
4822
4823                og_schedule_create(schedule_id, task_id, &time);
4824        }
4825
4826        dbi_result_free(result);
4827
4828        return 0;
4829}
4830
4831static int og_dbi_schedule_create(struct og_dbi *dbi,
4832                                  struct og_msg_params *params,
4833                                  uint32_t *schedule_id)
4834{
4835        const char *msglog;
4836        dbi_result result;
4837        uint8_t suspended = 0;
4838        uint8_t type = 3;
4839
4840        result = dbi_conn_queryf(dbi->conn,
4841                                 "INSERT INTO programaciones (tipoaccion,"
4842                                 " identificador, nombrebloque, annos, meses,"
4843                                 " diario, horas, ampm, minutos, suspendida) VALUES (%d,"
4844                                 " %s, '%s', %d, %d, %d, %d, %d, %d, %d)", type,
4845                                 params->task_id, params->name, params->time.years,
4846                                 params->time.months, params->time.days,
4847                                 params->time.hours, params->time.am_pm,
4848                                 params->time.minutes, suspended);
4849        if (!result) {
4850                dbi_conn_error(dbi->conn, &msglog);
4851                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
4852                       __func__, __LINE__, msglog);
4853                return -1;
4854        }
4855        dbi_result_free(result);
4856
4857        *schedule_id = dbi_conn_sequence_last(dbi->conn, NULL);
4858
4859        return 0;
4860}
4861
4862static int og_dbi_schedule_update(struct og_dbi *dbi,
4863                                  struct og_msg_params *params)
4864{
4865        const char *msglog;
4866        dbi_result result;
4867        uint8_t type = 3;
4868
4869        result = dbi_conn_queryf(dbi->conn,
4870                                 "UPDATE programaciones SET tipoaccion=%d, "
4871                                 "identificador='%s', nombrebloque='%s', "
4872                                 "annos=%d, meses=%d, "
4873                                 "diario=%d, horas=%d, ampm=%d, minutos=%d "
4874                                 "WHERE idprogramacion='%s'",
4875                                 type, params->task_id, params->name,
4876                                 params->time.years, params->time.months,
4877                                 params->time.days, params->time.hours,
4878                                 params->time.am_pm, params->time.minutes,
4879                                 params->id);
4880
4881        if (!result) {
4882                dbi_conn_error(dbi->conn, &msglog);
4883                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
4884                       __func__, __LINE__, msglog);
4885                return -1;
4886        }
4887        dbi_result_free(result);
4888
4889        return 0;
4890}
4891
4892static int og_dbi_schedule_delete(struct og_dbi *dbi, uint32_t id)
4893{
4894        const char *msglog;
4895        dbi_result result;
4896
4897        result = dbi_conn_queryf(dbi->conn,
4898                                 "DELETE FROM programaciones WHERE idprogramacion=%d",
4899                                 id);
4900        if (!result) {
4901                dbi_conn_error(dbi->conn, &msglog);
4902                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
4903                       __func__, __LINE__, msglog);
4904                return -1;
4905        }
4906        dbi_result_free(result);
4907
4908        return 0;
4909}
4910
4911static struct ev_loop *og_loop;
4912
4913static int og_cmd_schedule_create(json_t *element, struct og_msg_params *params)
4914{
4915        uint32_t schedule_id;
4916        struct og_dbi *dbi;
4917        const char *key;
4918        json_t *value;
4919        int err;
4920
4921        if (json_typeof(element) != JSON_OBJECT)
4922                return -1;
4923
4924        json_object_foreach(element, key, value) {
4925                if (!strcmp(key, "task")) {
4926                        err = og_json_parse_string(value, &params->task_id);
4927                        params->flags |= OG_REST_PARAM_TASK;
4928                } else if (!strcmp(key, "name")) {
4929                        err = og_json_parse_string(value, &params->name);
4930                        params->flags |= OG_REST_PARAM_NAME;
4931                } else if (!strcmp(key, "time_params"))
4932                        err = og_json_parse_time_params(value, params);
4933
4934                if (err < 0)
4935                        break;
4936        }
4937
4938        if (!og_msg_params_validate(params, OG_REST_PARAM_TASK |
4939                                            OG_REST_PARAM_NAME |
4940                                            OG_REST_PARAM_TIME_YEARS |
4941                                            OG_REST_PARAM_TIME_MONTHS |
4942                                            OG_REST_PARAM_TIME_DAYS |
4943                                            OG_REST_PARAM_TIME_HOURS |
4944                                            OG_REST_PARAM_TIME_MINUTES |
4945                                            OG_REST_PARAM_TIME_AM_PM))
4946                return -1;
4947
4948        dbi = og_dbi_open(&dbi_config);
4949        if (!dbi) {
4950                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
4951                           __func__, __LINE__);
4952                return -1;
4953        }
4954
4955        err = og_dbi_schedule_create(dbi, params, &schedule_id);
4956        og_dbi_close(dbi);
4957
4958        if (err < 0)
4959                return -1;
4960
4961        og_schedule_create(schedule_id, atoi(params->task_id), &params->time);
4962        og_schedule_refresh(og_loop);
4963
4964        return err;
4965}
4966
4967static int og_cmd_schedule_update(json_t *element, struct og_msg_params *params)
4968{
4969        struct og_dbi *dbi;
4970        const char *key;
4971        json_t *value;
4972        int err;
4973
4974        if (json_typeof(element) != JSON_OBJECT)
4975                return -1;
4976
4977        json_object_foreach(element, key, value) {
4978                if (!strcmp(key, "id")) {
4979                        err = og_json_parse_string(value, &params->id);
4980                        params->flags |= OG_REST_PARAM_ID;
4981                } else if (!strcmp(key, "task")) {
4982                        err = og_json_parse_string(value, &params->task_id);
4983                        params->flags |= OG_REST_PARAM_TASK;
4984                } else if (!strcmp(key, "name")) {
4985                        err = og_json_parse_string(value, &params->name);
4986                        params->flags |= OG_REST_PARAM_NAME;
4987                } else if (!strcmp(key, "time_params"))
4988                        err = og_json_parse_time_params(value, params);
4989
4990                if (err < 0)
4991                        break;
4992        }
4993
4994        if (!og_msg_params_validate(params, OG_REST_PARAM_ID |
4995                                            OG_REST_PARAM_TASK |
4996                                            OG_REST_PARAM_NAME |
4997                                            OG_REST_PARAM_TIME_YEARS |
4998                                            OG_REST_PARAM_TIME_MONTHS |
4999                                            OG_REST_PARAM_TIME_DAYS |
5000                                            OG_REST_PARAM_TIME_HOURS |
5001                                            OG_REST_PARAM_TIME_MINUTES |
5002                                            OG_REST_PARAM_TIME_AM_PM))
5003                return -1;
5004
5005        dbi = og_dbi_open(&dbi_config);
5006        if (!dbi) {
5007                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
5008                           __func__, __LINE__);
5009                return -1;
5010        }
5011
5012        err = og_dbi_schedule_update(dbi, params);
5013        og_dbi_close(dbi);
5014
5015        if (err < 0)
5016                return err;
5017
5018        og_schedule_update(og_loop, atoi(params->id), atoi(params->task_id),
5019                           &params->time);
5020        og_schedule_refresh(og_loop);
5021
5022        return err;
5023}
5024
5025static int og_cmd_schedule_delete(json_t *element, struct og_msg_params *params)
5026{
5027        struct og_dbi *dbi;
5028        const char *key;
5029        json_t *value;
5030        int err;
5031
5032        if (json_typeof(element) != JSON_OBJECT)
5033                return -1;
5034
5035        json_object_foreach(element, key, value) {
5036                if (!strcmp(key, "id")) {
5037                        err = og_json_parse_string(value, &params->id);
5038                        params->flags |= OG_REST_PARAM_ID;
5039                } else {
5040                        return -1;
5041                }
5042
5043                if (err < 0)
5044                        break;
5045        }
5046
5047        if (!og_msg_params_validate(params, OG_REST_PARAM_ID))
5048                return -1;
5049
5050        dbi = og_dbi_open(&dbi_config);
5051        if (!dbi) {
5052                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
5053                           __func__, __LINE__);
5054                return -1;
5055        }
5056
5057        err = og_dbi_schedule_delete(dbi, atoi(params->id));
5058        og_dbi_close(dbi);
5059
5060        og_schedule_delete(og_loop, atoi(params->id));
5061
5062        return err;
5063}
5064
5065static int og_client_method_not_found(struct og_client *cli)
5066{
5067        /* To meet RFC 7231, this function MUST generate an Allow header field
5068         * containing the correct methods. For example: "Allow: POST\r\n"
5069         */
5070        char buf[] = "HTTP/1.1 405 Method Not Allowed\r\n"
5071                     "Content-Length: 0\r\n\r\n";
5072
5073        send(og_client_socket(cli), buf, strlen(buf), 0);
5074
5075        return -1;
5076}
5077
5078static int og_client_bad_request(struct og_client *cli)
5079{
5080        char buf[] = "HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n";
5081
5082        send(og_client_socket(cli), buf, strlen(buf), 0);
5083
5084        return -1;
5085}
5086
5087static int og_client_not_found(struct og_client *cli)
5088{
5089        char buf[] = "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n";
5090
5091        send(og_client_socket(cli), buf, strlen(buf), 0);
5092
5093        return -1;
5094}
5095
5096static int og_client_not_authorized(struct og_client *cli)
5097{
5098        char buf[] = "HTTP/1.1 401 Unauthorized\r\n"
5099                     "WWW-Authenticate: Basic\r\n"
5100                     "Content-Length: 0\r\n\r\n";
5101
5102        send(og_client_socket(cli), buf, strlen(buf), 0);
5103
5104        return -1;
5105}
5106
5107static int og_server_internal_error(struct og_client *cli)
5108{
5109        char buf[] = "HTTP/1.1 500 Internal Server Error\r\n"
5110                     "Content-Length: 0\r\n\r\n";
5111
5112        send(og_client_socket(cli), buf, strlen(buf), 0);
5113
5114        return -1;
5115}
5116
5117static int og_client_payload_too_large(struct og_client *cli)
5118{
5119        char buf[] = "HTTP/1.1 413 Payload Too Large\r\n"
5120                     "Content-Length: 0\r\n\r\n";
5121
5122        send(og_client_socket(cli), buf, strlen(buf), 0);
5123
5124        return -1;
5125}
5126
5127#define OG_MSG_RESPONSE_MAXLEN  65536
5128
5129static int og_client_ok(struct og_client *cli, char *buf_reply)
5130{
5131        char buf[OG_MSG_RESPONSE_MAXLEN] = {};
5132        int err = 0, len;
5133
5134        len = snprintf(buf, sizeof(buf),
5135                       "HTTP/1.1 200 OK\r\nContent-Length: %ld\r\n\r\n%s",
5136                       strlen(buf_reply), buf_reply);
5137        if (len >= (int)sizeof(buf))
5138                err = og_server_internal_error(cli);
5139
5140        send(og_client_socket(cli), buf, strlen(buf), 0);
5141
5142        return err;
5143}
5144
5145static int og_client_state_process_payload_rest(struct og_client *cli)
5146{
5147        char buf_reply[OG_MSG_RESPONSE_MAXLEN] = {};
5148        struct og_msg_params params = {};
5149        enum og_rest_method method;
5150        const char *cmd, *body;
5151        json_error_t json_err;
5152        json_t *root = NULL;
5153        int err = 0;
5154
5155        syslog(LOG_DEBUG, "%s:%hu %.32s ...\n",
5156               inet_ntoa(cli->addr.sin_addr),
5157               ntohs(cli->addr.sin_port), cli->buf);
5158
5159        if (!strncmp(cli->buf, "GET", strlen("GET"))) {
5160                method = OG_METHOD_GET;
5161                cmd = cli->buf + strlen("GET") + 2;
5162        } else if (!strncmp(cli->buf, "POST", strlen("POST"))) {
5163                method = OG_METHOD_POST;
5164                cmd = cli->buf + strlen("POST") + 2;
5165        } else
5166                return og_client_method_not_found(cli);
5167
5168        body = strstr(cli->buf, "\r\n\r\n") + 4;
5169
5170        if (strcmp(cli->auth_token, auth_token)) {
5171                syslog(LOG_ERR, "wrong Authentication key\n");
5172                return og_client_not_authorized(cli);
5173        }
5174
5175        if (cli->content_length) {
5176                root = json_loads(body, 0, &json_err);
5177                if (!root) {
5178                        syslog(LOG_ERR, "malformed json line %d: %s\n",
5179                               json_err.line, json_err.text);
5180                        return og_client_not_found(cli);
5181                }
5182        }
5183
5184        if (!strncmp(cmd, "clients", strlen("clients"))) {
5185                if (method != OG_METHOD_POST &&
5186                    method != OG_METHOD_GET)
5187                        return og_client_method_not_found(cli);
5188
5189                if (method == OG_METHOD_POST && !root) {
5190                        syslog(LOG_ERR, "command clients with no payload\n");
5191                        return og_client_bad_request(cli);
5192                }
5193                switch (method) {
5194                case OG_METHOD_POST:
5195                        err = og_cmd_post_clients(root, &params);
5196                        break;
5197                case OG_METHOD_GET:
5198                        err = og_cmd_get_clients(root, &params, buf_reply);
5199                        break;
5200                }
5201        } else if (!strncmp(cmd, "wol", strlen("wol"))) {
5202                if (method != OG_METHOD_POST)
5203                        return og_client_method_not_found(cli);
5204
5205                if (!root) {
5206                        syslog(LOG_ERR, "command wol with no payload\n");
5207                        return og_client_bad_request(cli);
5208                }
5209                err = og_cmd_wol(root, &params);
5210        } else if (!strncmp(cmd, "shell/run", strlen("shell/run"))) {
5211                if (method != OG_METHOD_POST)
5212                        return og_client_method_not_found(cli);
5213
5214                if (!root) {
5215                        syslog(LOG_ERR, "command run with no payload\n");
5216                        return og_client_bad_request(cli);
5217                }
5218                err = og_cmd_run_post(root, &params);
5219        } else if (!strncmp(cmd, "shell/output", strlen("shell/output"))) {
5220                if (method != OG_METHOD_POST)
5221                        return og_client_method_not_found(cli);
5222
5223                if (!root) {
5224                        syslog(LOG_ERR, "command output with no payload\n");
5225                        return og_client_bad_request(cli);
5226                }
5227
5228                err = og_cmd_run_get(root, &params, buf_reply);
5229        } else if (!strncmp(cmd, "session", strlen("session"))) {
5230                if (method != OG_METHOD_POST)
5231                        return og_client_method_not_found(cli);
5232
5233                if (!root) {
5234                        syslog(LOG_ERR, "command session with no payload\n");
5235                        return og_client_bad_request(cli);
5236                }
5237                err = og_cmd_session(root, &params);
5238        } else if (!strncmp(cmd, "poweroff", strlen("poweroff"))) {
5239                if (method != OG_METHOD_POST)
5240                        return og_client_method_not_found(cli);
5241
5242                if (!root) {
5243                        syslog(LOG_ERR, "command poweroff with no payload\n");
5244                        return og_client_bad_request(cli);
5245                }
5246                err = og_cmd_poweroff(root, &params);
5247        } else if (!strncmp(cmd, "reboot", strlen("reboot"))) {
5248                if (method != OG_METHOD_POST)
5249                        return og_client_method_not_found(cli);
5250
5251                if (!root) {
5252                        syslog(LOG_ERR, "command reboot with no payload\n");
5253                        return og_client_bad_request(cli);
5254                }
5255                err = og_cmd_reboot(root, &params);
5256        } else if (!strncmp(cmd, "stop", strlen("stop"))) {
5257                if (method != OG_METHOD_POST)
5258                        return og_client_method_not_found(cli);
5259
5260                if (!root) {
5261                        syslog(LOG_ERR, "command stop with no payload\n");
5262                        return og_client_bad_request(cli);
5263                }
5264                err = og_cmd_stop(root, &params);
5265        } else if (!strncmp(cmd, "refresh", strlen("refresh"))) {
5266                if (method != OG_METHOD_POST)
5267                        return og_client_method_not_found(cli);
5268
5269                if (!root) {
5270                        syslog(LOG_ERR, "command refresh with no payload\n");
5271                        return og_client_bad_request(cli);
5272                }
5273                err = og_cmd_refresh(root, &params);
5274        } else if (!strncmp(cmd, "hardware", strlen("hardware"))) {
5275                if (method != OG_METHOD_POST)
5276                        return og_client_method_not_found(cli);
5277
5278                if (!root) {
5279                        syslog(LOG_ERR, "command hardware with no payload\n");
5280                        return og_client_bad_request(cli);
5281                }
5282                err = og_cmd_hardware(root, &params);
5283        } else if (!strncmp(cmd, "software", strlen("software"))) {
5284                if (method != OG_METHOD_POST)
5285                        return og_client_method_not_found(cli);
5286
5287                if (!root) {
5288                        syslog(LOG_ERR, "command software with no payload\n");
5289                        return og_client_bad_request(cli);
5290                }
5291                err = og_cmd_software(root, &params);
5292        } else if (!strncmp(cmd, "image/create/basic",
5293                            strlen("image/create/basic"))) {
5294                if (method != OG_METHOD_POST)
5295                        return og_client_method_not_found(cli);
5296
5297                if (!root) {
5298                        syslog(LOG_ERR, "command create with no payload\n");
5299                        return og_client_bad_request(cli);
5300                }
5301                err = og_cmd_create_basic_image(root, &params);
5302        } else if (!strncmp(cmd, "image/create/incremental",
5303                            strlen("image/create/incremental"))) {
5304                if (method != OG_METHOD_POST)
5305                        return og_client_method_not_found(cli);
5306
5307                if (!root) {
5308                        syslog(LOG_ERR, "command create with no payload\n");
5309                        return og_client_bad_request(cli);
5310                }
5311                err = og_cmd_create_incremental_image(root, &params);
5312        } else if (!strncmp(cmd, "image/create", strlen("image/create"))) {
5313                if (method != OG_METHOD_POST)
5314                        return og_client_method_not_found(cli);
5315
5316                if (!root) {
5317                        syslog(LOG_ERR, "command create with no payload\n");
5318                        return og_client_bad_request(cli);
5319                }
5320                err = og_cmd_create_image(root, &params);
5321        } else if (!strncmp(cmd, "image/restore/basic",
5322                                strlen("image/restore/basic"))) {
5323                if (method != OG_METHOD_POST)
5324                        return og_client_method_not_found(cli);
5325
5326                if (!root) {
5327                        syslog(LOG_ERR, "command create with no payload\n");
5328                        return og_client_bad_request(cli);
5329                }
5330                err = og_cmd_restore_basic_image(root, &params);
5331        } else if (!strncmp(cmd, "image/restore/incremental",
5332                                strlen("image/restore/incremental"))) {
5333                if (method != OG_METHOD_POST)
5334                        return og_client_method_not_found(cli);
5335
5336                if (!root) {
5337                        syslog(LOG_ERR, "command create with no payload\n");
5338                        return og_client_bad_request(cli);
5339                }
5340                err = og_cmd_restore_incremental_image(root, &params);
5341        } else if (!strncmp(cmd, "image/restore", strlen("image/restore"))) {
5342                if (method != OG_METHOD_POST)
5343                        return og_client_method_not_found(cli);
5344
5345                if (!root) {
5346                        syslog(LOG_ERR, "command create with no payload\n");
5347                        return og_client_bad_request(cli);
5348                }
5349                err = og_cmd_restore_image(root, &params);
5350        } else if (!strncmp(cmd, "setup", strlen("setup"))) {
5351                if (method != OG_METHOD_POST)
5352                        return og_client_method_not_found(cli);
5353
5354                if (!root) {
5355                        syslog(LOG_ERR, "command create with no payload\n");
5356                        return og_client_bad_request(cli);
5357                }
5358                err = og_cmd_setup(root, &params);
5359        } else if (!strncmp(cmd, "run/schedule", strlen("run/schedule"))) {
5360                if (method != OG_METHOD_POST)
5361                        return og_client_method_not_found(cli);
5362
5363                if (!root) {
5364                        syslog(LOG_ERR, "command create with no payload\n");
5365                        return og_client_bad_request(cli);
5366                }
5367
5368                err = og_cmd_run_schedule(root, &params);
5369        } else if (!strncmp(cmd, "task/run", strlen("task/run"))) {
5370                if (method != OG_METHOD_POST)
5371                        return og_client_method_not_found(cli);
5372
5373                if (!root) {
5374                        syslog(LOG_ERR, "command task with no payload\n");
5375                        return og_client_bad_request(cli);
5376                }
5377                err = og_cmd_task_post(root, &params);
5378        } else if (!strncmp(cmd, "schedule/create",
5379                            strlen("schedule/create"))) {
5380                if (method != OG_METHOD_POST)
5381                        return og_client_method_not_found(cli);
5382
5383                if (!root) {
5384                        syslog(LOG_ERR, "command task with no payload\n");
5385                        return og_client_bad_request(cli);
5386                }
5387                err = og_cmd_schedule_create(root, &params);
5388        } else if (!strncmp(cmd, "schedule/delete",
5389                            strlen("schedule/delete"))) {
5390                if (method != OG_METHOD_POST)
5391                        return og_client_method_not_found(cli);
5392
5393                if (!root) {
5394                        syslog(LOG_ERR, "command task with no payload\n");
5395                        return og_client_bad_request(cli);
5396                }
5397                err = og_cmd_schedule_delete(root, &params);
5398        } else if (!strncmp(cmd, "schedule/update",
5399                            strlen("schedule/update"))) {
5400                if (method != OG_METHOD_POST)
5401                        return og_client_method_not_found(cli);
5402
5403                if (!root) {
5404                        syslog(LOG_ERR, "command task with no payload\n");
5405                        return og_client_bad_request(cli);
5406                }
5407                err = og_cmd_schedule_update(root, &params);
5408        } else {
5409                syslog(LOG_ERR, "unknown command: %.32s ...\n", cmd);
5410                err = og_client_not_found(cli);
5411        }
5412
5413        if (root)
5414                json_decref(root);
5415
5416        if (err < 0)
5417                return og_client_bad_request(cli);
5418
5419        err = og_client_ok(cli, buf_reply);
5420        if (err < 0) {
5421                syslog(LOG_ERR, "HTTP response to %s:%hu is too large\n",
5422                       inet_ntoa(cli->addr.sin_addr),
5423                       ntohs(cli->addr.sin_port));
5424        }
5425
5426        return err;
5427}
5428
5429static int og_client_state_recv_hdr_rest(struct og_client *cli)
5430{
5431        char *ptr;
5432
5433        ptr = strstr(cli->buf, "\r\n\r\n");
5434        if (!ptr)
5435                return 0;
5436
5437        cli->msg_len = ptr - cli->buf + 4;
5438
5439        ptr = strstr(cli->buf, "Content-Length: ");
5440        if (ptr) {
5441                sscanf(ptr, "Content-Length: %i[^\r\n]", &cli->content_length);
5442                if (cli->content_length < 0)
5443                        return -1;
5444                cli->msg_len += cli->content_length;
5445        }
5446
5447        ptr = strstr(cli->buf, "Authorization: ");
5448        if (ptr)
5449                sscanf(ptr, "Authorization: %63[^\r\n]", cli->auth_token);
5450
5451        return 1;
5452}
5453
5454static int og_client_recv(struct og_client *cli, int events)
5455{
5456        struct ev_io *io = &cli->io;
5457        int ret;
5458
5459        if (events & EV_ERROR) {
5460                syslog(LOG_ERR, "unexpected error event from client %s:%hu\n",
5461                               inet_ntoa(cli->addr.sin_addr),
5462                               ntohs(cli->addr.sin_port));
5463                return 0;
5464        }
5465
5466        ret = recv(io->fd, cli->buf + cli->buf_len,
5467                   sizeof(cli->buf) - cli->buf_len, 0);
5468        if (ret <= 0) {
5469                if (ret < 0) {
5470                        syslog(LOG_ERR, "error reading from client %s:%hu (%s)\n",
5471                               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port),
5472                               strerror(errno));
5473                } else {
5474                        syslog(LOG_DEBUG, "closed connection by %s:%hu\n",
5475                               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
5476                }
5477                return ret;
5478        }
5479
5480        return ret;
5481}
5482
5483static void og_client_read_cb(struct ev_loop *loop, struct ev_io *io, int events)
5484{
5485        struct og_client *cli;
5486        int ret;
5487
5488        cli = container_of(io, struct og_client, io);
5489
5490        ret = og_client_recv(cli, events);
5491        if (ret <= 0)
5492                goto close;
5493
5494        if (cli->keepalive_idx >= 0)
5495                return;
5496
5497        ev_timer_again(loop, &cli->timer);
5498
5499        cli->buf_len += ret;
5500        if (cli->buf_len >= sizeof(cli->buf)) {
5501                syslog(LOG_ERR, "client request from %s:%hu is too long\n",
5502                       inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
5503                og_client_payload_too_large(cli);
5504                goto close;
5505        }
5506
5507        switch (cli->state) {
5508        case OG_CLIENT_RECEIVING_HEADER:
5509                if (cli->rest)
5510                        ret = og_client_state_recv_hdr_rest(cli);
5511                else
5512                        ret = og_client_state_recv_hdr(cli);
5513
5514                if (ret < 0)
5515                        goto close;
5516                if (!ret)
5517                        return;
5518
5519                cli->state = OG_CLIENT_RECEIVING_PAYLOAD;
5520                /* Fall through. */
5521        case OG_CLIENT_RECEIVING_PAYLOAD:
5522                /* Still not enough data to process request. */
5523                if (cli->buf_len < cli->msg_len)
5524                        return;
5525
5526                cli->state = OG_CLIENT_PROCESSING_REQUEST;
5527                /* fall through. */
5528        case OG_CLIENT_PROCESSING_REQUEST:
5529                if (cli->rest) {
5530                        ret = og_client_state_process_payload_rest(cli);
5531                        if (ret < 0) {
5532                                syslog(LOG_ERR, "Failed to process HTTP request from %s:%hu\n",
5533                                       inet_ntoa(cli->addr.sin_addr),
5534                                       ntohs(cli->addr.sin_port));
5535                        }
5536                } else {
5537                        ret = og_client_state_process_payload(cli);
5538                }
5539                if (ret < 0)
5540                        goto close;
5541
5542                if (cli->keepalive_idx < 0) {
5543                        syslog(LOG_DEBUG, "server closing connection to %s:%hu\n",
5544                               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
5545                        goto close;
5546                } else {
5547                        syslog(LOG_DEBUG, "leaving client %s:%hu in keepalive mode\n",
5548                               inet_ntoa(cli->addr.sin_addr),
5549                               ntohs(cli->addr.sin_port));
5550                        og_client_keepalive(loop, cli);
5551                        og_client_reset_state(cli);
5552                }
5553                break;
5554        default:
5555                syslog(LOG_ERR, "unknown state, critical internal error\n");
5556                goto close;
5557        }
5558        return;
5559close:
5560        ev_timer_stop(loop, &cli->timer);
5561        og_client_release(loop, cli);
5562}
5563
5564enum og_agent_state {
5565        OG_AGENT_RECEIVING_HEADER       = 0,
5566        OG_AGENT_RECEIVING_PAYLOAD,
5567        OG_AGENT_PROCESSING_RESPONSE,
5568};
5569
5570static int og_agent_state_recv_hdr_rest(struct og_client *cli)
5571{
5572        char *ptr;
5573
5574        ptr = strstr(cli->buf, "\r\n\r\n");
5575        if (!ptr)
5576                return 0;
5577
5578        cli->msg_len = ptr - cli->buf + 4;
5579
5580        ptr = strstr(cli->buf, "Content-Length: ");
5581        if (ptr) {
5582                sscanf(ptr, "Content-Length: %i[^\r\n]", &cli->content_length);
5583                if (cli->content_length < 0)
5584                        return -1;
5585                cli->msg_len += cli->content_length;
5586        }
5587
5588        return 1;
5589}
5590
5591static void og_agent_reset_state(struct og_client *cli)
5592{
5593        cli->state = OG_AGENT_RECEIVING_HEADER;
5594        cli->buf_len = 0;
5595        cli->content_length = 0;
5596        memset(cli->buf, 0, sizeof(cli->buf));
5597}
5598
5599static int og_dbi_get_computer_info(struct og_computer *computer,
5600                                    struct in_addr addr)
5601{
5602        const char *msglog;
5603        struct og_dbi *dbi;
5604        dbi_result result;
5605
5606        dbi = og_dbi_open(&dbi_config);
5607        if (!dbi) {
5608                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
5609                       __func__, __LINE__);
5610                return -1;
5611        }
5612        result = dbi_conn_queryf(dbi->conn,
5613                                 "SELECT ordenadores.idordenador,"
5614                                 "       ordenadores.nombreordenador,"
5615                                 "       ordenadores.idaula,"
5616                                 "       centros.idcentro FROM ordenadores "
5617                                 "INNER JOIN aulas ON aulas.idaula=ordenadores.idaula "
5618                                 "INNER JOIN centros ON centros.idcentro=aulas.idcentro "
5619                                 "WHERE ordenadores.ip='%s'", inet_ntoa(addr));
5620        if (!result) {
5621                dbi_conn_error(dbi->conn, &msglog);
5622                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
5623                       __func__, __LINE__, msglog);
5624                return -1;
5625        }
5626        if (!dbi_result_next_row(result)) {
5627                syslog(LOG_ERR, "client does not exist in database (%s:%d)\n",
5628                       __func__, __LINE__);
5629                dbi_result_free(result);
5630                return -1;
5631        }
5632
5633        computer->id = dbi_result_get_uint(result, "idordenador");
5634        computer->center = dbi_result_get_uint(result, "idcentro");
5635        computer->room = dbi_result_get_uint(result, "idaula");
5636        strncpy(computer->name,
5637                dbi_result_get_string(result, "nombreordenador"),
5638                OG_COMPUTER_NAME_MAXLEN);
5639
5640        dbi_result_free(result);
5641        og_dbi_close(dbi);
5642
5643        return 0;
5644}
5645
5646static int og_resp_probe(struct og_client *cli, json_t *data)
5647{
5648        bool status = false;
5649        const char *key;
5650        json_t *value;
5651        int err = 0;
5652
5653        if (json_typeof(data) != JSON_OBJECT)
5654                return -1;
5655
5656        json_object_foreach(data, key, value) {
5657                if (!strcmp(key, "status")) {
5658                        err = og_json_parse_string(value, &cli->status);
5659                        if (err < 0)
5660                                return err;
5661
5662                        status = true;
5663                } else {
5664                        return -1;
5665                }
5666        }
5667
5668        return status ? 0 : -1;
5669}
5670
5671static int og_resp_shell_run(struct og_client *cli, json_t *data)
5672{
5673        const char *output = NULL;
5674        char filename[4096];
5675        const char *key;
5676        json_t *value;
5677        int err = -1;
5678        FILE *file;
5679
5680        if (json_typeof(data) != JSON_OBJECT)
5681                return -1;
5682
5683        json_object_foreach(data, key, value) {
5684                if (!strcmp(key, "out")) {
5685                        err = og_json_parse_string(value, &output);
5686                        if (err < 0)
5687                                return err;
5688                } else {
5689                        return -1;
5690                }
5691        }
5692
5693        if (!output) {
5694                syslog(LOG_ERR, "%s:%d: malformed json response\n",
5695                       __FILE__, __LINE__);
5696                return -1;
5697        }
5698
5699        sprintf(filename, "/tmp/_Seconsola_%s", inet_ntoa(cli->addr.sin_addr));
5700        file = fopen(filename, "wt");
5701        if (!file) {
5702                syslog(LOG_ERR, "cannot open file %s: %s\n",
5703                       filename, strerror(errno));
5704                return -1;
5705        }
5706
5707        fprintf(file, "%s", output);
5708        fclose(file);
5709
5710        return 0;
5711}
5712
5713#define OG_DB_INT_MAXLEN        11
5714
5715struct og_computer_legacy  {
5716        char center[OG_DB_INT_MAXLEN + 1];
5717        char id[OG_DB_INT_MAXLEN + 1];
5718        char hardware[8192];
5719};
5720
5721static int og_resp_hardware(json_t *data, struct og_client *cli)
5722{
5723        struct og_computer_legacy legacy = {};
5724        const char *hardware = NULL;
5725        struct og_computer computer;
5726        struct og_dbi *dbi;
5727        const char *key;
5728        json_t *value;
5729        int err = 0;
5730        bool res;
5731
5732        if (json_typeof(data) != JSON_OBJECT)
5733                return -1;
5734
5735        json_object_foreach(data, key, value) {
5736                if (!strcmp(key, "hardware")) {
5737                        err = og_json_parse_string(value, &hardware);
5738                        if (err < 0)
5739                                return -1;
5740                } else {
5741                        return -1;
5742                }
5743        }
5744
5745        if (!hardware) {
5746                syslog(LOG_ERR, "malformed response json\n");
5747                return -1;
5748        }
5749
5750        err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr);
5751        if (err < 0)
5752                return -1;
5753
5754        snprintf(legacy.center, sizeof(legacy.center), "%d", computer.center);
5755        snprintf(legacy.id, sizeof(legacy.id), "%d", computer.id);
5756        snprintf(legacy.hardware, sizeof(legacy.hardware), "%s", hardware);
5757
5758        dbi = og_dbi_open(&dbi_config);
5759        if (!dbi) {
5760                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
5761                       __func__, __LINE__);
5762                return -1;
5763        }
5764
5765        res = actualizaHardware(dbi, legacy.hardware, legacy.id, computer.name,
5766                                legacy.center);
5767        og_dbi_close(dbi);
5768
5769        if (!res) {
5770                syslog(LOG_ERR, "Problem updating client configuration\n");
5771                return -1;
5772        }
5773
5774        return 0;
5775}
5776
5777#define OG_DB_SMALLINT_MAXLEN   6
5778
5779struct og_software_legacy {
5780        char software[8192];
5781        char center[OG_DB_INT_MAXLEN + 1];
5782        char part[OG_DB_SMALLINT_MAXLEN + 1];
5783        char id[OG_DB_INT_MAXLEN + 1];
5784};
5785
5786static int og_resp_software(json_t *data, struct og_client *cli)
5787{
5788        struct og_software_legacy legacy = {};
5789        const char *partition = NULL;
5790        const char *software = NULL;
5791        struct og_computer computer;
5792        struct og_dbi *dbi;
5793        const char *key;
5794        json_t *value;
5795        int err = 0;
5796        bool res;
5797
5798        if (json_typeof(data) != JSON_OBJECT)
5799                return -1;
5800
5801        json_object_foreach(data, key, value) {
5802                if (!strcmp(key, "software"))
5803                        err = og_json_parse_string(value, &software);
5804                else if (!strcmp(key, "partition"))
5805                        err = og_json_parse_string(value, &partition);
5806                else
5807                        return -1;
5808
5809                if (err < 0)
5810                        return -1;
5811        }
5812
5813        if (!software || !partition) {
5814                syslog(LOG_ERR, "malformed response json\n");
5815                return -1;
5816        }
5817
5818        err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr);
5819        if (err < 0)
5820                return -1;
5821
5822        snprintf(legacy.software, sizeof(legacy.software), "%s", software);
5823        snprintf(legacy.part, sizeof(legacy.part), "%s", partition);
5824        snprintf(legacy.id, sizeof(legacy.id), "%d", computer.id);
5825        snprintf(legacy.center, sizeof(legacy.center), "%d", computer.center);
5826
5827        dbi = og_dbi_open(&dbi_config);
5828        if (!dbi) {
5829                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
5830                       __func__, __LINE__);
5831                return -1;
5832        }
5833
5834        res = actualizaSoftware(dbi, legacy.software, legacy.part, legacy.id,
5835                                computer.name, legacy.center);
5836        og_dbi_close(dbi);
5837
5838        if (!res) {
5839                syslog(LOG_ERR, "Problem updating client configuration\n");
5840                return -1;
5841        }
5842
5843        return 0;
5844}
5845
5846#define OG_PARAMS_RESP_REFRESH  (OG_PARAM_PART_DISK |           \
5847                                 OG_PARAM_PART_NUMBER |         \
5848                                 OG_PARAM_PART_CODE |           \
5849                                 OG_PARAM_PART_FILESYSTEM |     \
5850                                 OG_PARAM_PART_OS |             \
5851                                 OG_PARAM_PART_SIZE |           \
5852                                 OG_PARAM_PART_USED_SIZE)
5853
5854static int og_json_parse_partition_array(json_t *value,
5855                                         struct og_partition *partitions)
5856{
5857        json_t *element;
5858        int i, err;
5859
5860        if (json_typeof(value) != JSON_ARRAY)
5861                return -1;
5862
5863        for (i = 0; i < json_array_size(value) && i < OG_PARTITION_MAX; i++) {
5864                element = json_array_get(value, i);
5865
5866                err = og_json_parse_partition(element, &partitions[i],
5867                                              OG_PARAMS_RESP_REFRESH);
5868                if (err < 0)
5869                        return err;
5870        }
5871
5872        return 0;
5873}
5874
5875static int og_resp_refresh(json_t *data, struct og_client *cli)
5876{
5877        struct og_partition partitions[OG_PARTITION_MAX] = {};
5878        const char *serial_number = NULL;
5879        struct og_partition disk_setup;
5880        struct og_computer computer;
5881        char cfg[1024] = {};
5882        struct og_dbi *dbi;
5883        const char *key;
5884        unsigned int i;
5885        json_t *value;
5886        int err = 0;
5887        bool res;
5888
5889        if (json_typeof(data) != JSON_OBJECT)
5890                return -1;
5891
5892        json_object_foreach(data, key, value) {
5893                if (!strcmp(key, "disk_setup")) {
5894                        err = og_json_parse_partition(value,
5895                                                      &disk_setup,
5896                                                      OG_PARAMS_RESP_REFRESH);
5897                } else if (!strcmp(key, "partition_setup")) {
5898                        err = og_json_parse_partition_array(value, partitions);
5899                } else if (!strcmp(key, "serial_number")) {
5900                        err = og_json_parse_string(value, &serial_number);
5901                } else {
5902                        return -1;
5903                }
5904
5905                if (err < 0)
5906                        return err;
5907        }
5908
5909        err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr);
5910        if (err < 0)
5911                return -1;
5912
5913        if (strlen(serial_number) > 0)
5914                snprintf(cfg, sizeof(cfg), "ser=%s\n", serial_number);
5915
5916        if (!disk_setup.disk || !disk_setup.number || !disk_setup.code ||
5917            !disk_setup.filesystem || !disk_setup.os || !disk_setup.size ||
5918            !disk_setup.used_size)
5919                return -1;
5920
5921        snprintf(cfg + strlen(cfg), sizeof(cfg) - strlen(cfg),
5922                 "disk=%s\tpar=%s\tcpt=%s\tfsi=%s\tsoi=%s\ttam=%s\tuso=%s\n",
5923                 disk_setup.disk, disk_setup.number, disk_setup.code,
5924                 disk_setup.filesystem, disk_setup.os, disk_setup.size,
5925                 disk_setup.used_size);
5926
5927        for (i = 0; i < OG_PARTITION_MAX; i++) {
5928                if (!partitions[i].disk || !partitions[i].number ||
5929                    !partitions[i].code || !partitions[i].filesystem ||
5930                    !partitions[i].os || !partitions[i].size ||
5931                    !partitions[i].used_size)
5932                        continue;
5933
5934                snprintf(cfg + strlen(cfg), sizeof(cfg) - strlen(cfg),
5935                         "disk=%s\tpar=%s\tcpt=%s\tfsi=%s\tsoi=%s\ttam=%s\tuso=%s\n",
5936                         partitions[i].disk, partitions[i].number,
5937                         partitions[i].code, partitions[i].filesystem,
5938                         partitions[i].os, partitions[i].size,
5939                         partitions[i].used_size);
5940        }
5941
5942        dbi = og_dbi_open(&dbi_config);
5943        if (!dbi) {
5944                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
5945                                  __func__, __LINE__);
5946                return -1;
5947        }
5948        res = actualizaConfiguracion(dbi, cfg, computer.id);
5949        og_dbi_close(dbi);
5950
5951        if (!res) {
5952                syslog(LOG_ERR, "Problem updating client configuration\n");
5953                return -1;
5954        }
5955
5956        return 0;
5957}
5958
5959static int og_resp_setup(struct og_client *cli)
5960{
5961        struct og_msg_params params;
5962
5963        params.ips_array[0] = inet_ntoa(cli->addr.sin_addr);
5964        params.ips_array_len = 1;
5965
5966        return og_send_request("refresh", OG_METHOD_GET, &params, NULL);
5967}
5968
5969#define OG_DB_IMAGE_NAME_MAXLEN 50
5970#define OG_DB_IP_MAXLEN         15
5971#define OG_DB_INT8_MAXLEN       8
5972
5973struct og_image_legacy {
5974        char software_id[OG_DB_INT_MAXLEN + 1];
5975        char image_id[OG_DB_INT_MAXLEN + 1];
5976        char name[OG_DB_IMAGE_NAME_MAXLEN + 1];
5977        char repo[OG_DB_IP_MAXLEN + 1];
5978        char part[OG_DB_SMALLINT_MAXLEN + 1];
5979        char disk[OG_DB_SMALLINT_MAXLEN + 1];
5980        char code[OG_DB_INT8_MAXLEN + 1];
5981};
5982
5983static int og_resp_image_create(json_t *data, struct og_client *cli)
5984{
5985        struct og_software_legacy soft_legacy;
5986        struct og_image_legacy img_legacy;
5987        const char *partition = NULL;
5988        const char *software = NULL;
5989        const char *image_id = NULL;
5990        struct og_computer computer;
5991        const char *disk = NULL;
5992        const char *code = NULL;
5993        const char *name = NULL;
5994        const char *repo = NULL;
5995        struct og_dbi *dbi;
5996        const char *key;
5997        json_t *value;
5998        int err = 0;
5999        bool res;
6000
6001        if (json_typeof(data) != JSON_OBJECT)
6002                return -1;
6003
6004        json_object_foreach(data, key, value) {
6005                if (!strcmp(key, "software"))
6006                        err = og_json_parse_string(value, &software);
6007                else if (!strcmp(key, "partition"))
6008                        err = og_json_parse_string(value, &partition);
6009                else if (!strcmp(key, "disk"))
6010                        err = og_json_parse_string(value, &disk);
6011                else if (!strcmp(key, "code"))
6012                        err = og_json_parse_string(value, &code);
6013                else if (!strcmp(key, "id"))
6014                        err = og_json_parse_string(value, &image_id);
6015                else if (!strcmp(key, "name"))
6016                        err = og_json_parse_string(value, &name);
6017                else if (!strcmp(key, "repository"))
6018                        err = og_json_parse_string(value, &repo);
6019                else
6020                        return -1;
6021
6022                if (err < 0)
6023                        return err;
6024        }
6025
6026        if (!software || !partition || !disk || !code || !image_id || !name ||
6027            !repo) {
6028                syslog(LOG_ERR, "malformed response json\n");
6029                return -1;
6030        }
6031
6032        err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr);
6033        if (err < 0)
6034                return -1;
6035
6036        snprintf(soft_legacy.center, sizeof(soft_legacy.center), "%d",
6037                 computer.center);
6038        snprintf(soft_legacy.software, sizeof(soft_legacy.software), "%s",
6039                 software);
6040        snprintf(img_legacy.image_id, sizeof(img_legacy.image_id), "%s",
6041                 image_id);
6042        snprintf(soft_legacy.id, sizeof(soft_legacy.id), "%d", computer.id);
6043        snprintf(img_legacy.part, sizeof(img_legacy.part), "%s", partition);
6044        snprintf(img_legacy.disk, sizeof(img_legacy.disk), "%s", disk);
6045        snprintf(img_legacy.code, sizeof(img_legacy.code), "%s", code);
6046        snprintf(img_legacy.name, sizeof(img_legacy.name), "%s", name);
6047        snprintf(img_legacy.repo, sizeof(img_legacy.repo), "%s", repo);
6048
6049        dbi = og_dbi_open(&dbi_config);
6050        if (!dbi) {
6051                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
6052                       __func__, __LINE__);
6053                return -1;
6054        }
6055
6056        res = actualizaSoftware(dbi,
6057                                soft_legacy.software,
6058                                img_legacy.part,
6059                                soft_legacy.id,
6060                                computer.name,
6061                                soft_legacy.center);
6062        if (!res) {
6063                og_dbi_close(dbi);
6064                syslog(LOG_ERR, "Problem updating client configuration\n");
6065                return -1;
6066        }
6067
6068        res = actualizaCreacionImagen(dbi,
6069                                      img_legacy.image_id,
6070                                      img_legacy.disk,
6071                                      img_legacy.part,
6072                                      img_legacy.code,
6073                                      img_legacy.repo,
6074                                      soft_legacy.id);
6075        og_dbi_close(dbi);
6076
6077        if (!res) {
6078                syslog(LOG_ERR, "Problem updating client configuration\n");
6079                return -1;
6080        }
6081
6082        return 0;
6083}
6084
6085static int og_resp_image_restore(json_t *data, struct og_client *cli)
6086{
6087        struct og_software_legacy soft_legacy;
6088        struct og_image_legacy img_legacy;
6089        const char *partition = NULL;
6090        const char *image_id = NULL;
6091        struct og_computer computer;
6092        const char *disk = NULL;
6093        dbi_result query_result;
6094        struct og_dbi *dbi;
6095        const char *key;
6096        json_t *value;
6097        int err = 0;
6098        bool res;
6099
6100        if (json_typeof(data) != JSON_OBJECT)
6101                return -1;
6102
6103        json_object_foreach(data, key, value) {
6104                if (!strcmp(key, "partition"))
6105                        err = og_json_parse_string(value, &partition);
6106                else if (!strcmp(key, "disk"))
6107                        err = og_json_parse_string(value, &disk);
6108                else if (!strcmp(key, "image_id"))
6109                        err = og_json_parse_string(value, &image_id);
6110                else
6111                        return -1;
6112
6113                if (err < 0)
6114                        return err;
6115        }
6116
6117        if (!partition || !disk || !image_id) {
6118                syslog(LOG_ERR, "malformed response json\n");
6119                return -1;
6120        }
6121
6122        err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr);
6123        if (err < 0)
6124                return -1;
6125
6126        snprintf(img_legacy.image_id, sizeof(img_legacy.image_id), "%s",
6127                 image_id);
6128        snprintf(img_legacy.part, sizeof(img_legacy.part), "%s", partition);
6129        snprintf(img_legacy.disk, sizeof(img_legacy.disk), "%s", disk);
6130        snprintf(soft_legacy.id, sizeof(soft_legacy.id), "%d", computer.id);
6131
6132        dbi = og_dbi_open(&dbi_config);
6133        if (!dbi) {
6134                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
6135                       __func__, __LINE__);
6136                return -1;
6137        }
6138
6139        query_result = dbi_conn_queryf(dbi->conn,
6140                                       "SELECT idperfilsoft FROM imagenes "
6141                                       " WHERE idimagen='%s'",
6142                                       image_id);
6143        if (!query_result) {
6144                og_dbi_close(dbi);
6145                syslog(LOG_ERR, "failed to query database\n");
6146                return -1;
6147        }
6148        if (!dbi_result_next_row(query_result)) {
6149                dbi_result_free(query_result);
6150                og_dbi_close(dbi);
6151                syslog(LOG_ERR, "software profile does not exist in database\n");
6152                return -1;
6153        }
6154        snprintf(img_legacy.software_id, sizeof(img_legacy.software_id),
6155                 "%d", dbi_result_get_uint(query_result, "idperfilsoft"));
6156        dbi_result_free(query_result);
6157
6158        res = actualizaRestauracionImagen(dbi,
6159                                          img_legacy.image_id,
6160                                          img_legacy.disk,
6161                                          img_legacy.part,
6162                                          soft_legacy.id,
6163                                          img_legacy.software_id);
6164        og_dbi_close(dbi);
6165
6166        if (!res) {
6167                syslog(LOG_ERR, "Problem updating client configuration\n");
6168                return -1;
6169        }
6170
6171        return 0;
6172}
6173
6174static int og_agent_state_process_response(struct og_client *cli)
6175{
6176        json_error_t json_err;
6177        json_t *root;
6178        int err = -1;
6179        char *body;
6180
6181        if (strncmp(cli->buf, "HTTP/1.0 200 OK", strlen("HTTP/1.0 200 OK")))
6182                return -1;
6183
6184        if (!cli->content_length)
6185                return 0;
6186
6187        body = strstr(cli->buf, "\r\n\r\n") + 4;
6188
6189        root = json_loads(body, 0, &json_err);
6190        if (!root) {
6191                syslog(LOG_ERR, "%s:%d: malformed json line %d: %s\n",
6192                       __FILE__, __LINE__, json_err.line, json_err.text);
6193                return -1;
6194        }
6195
6196        if (!strncmp(cli->last_cmd, "probe", strlen("probe")))
6197                err = og_resp_probe(cli, root);
6198        else if (!strncmp(cli->last_cmd, "shell/run", strlen("shell/run")))
6199                err = og_resp_shell_run(cli, root);
6200        else if (!strncmp(cli->last_cmd, "hardware", strlen("hardware")))
6201                err = og_resp_hardware(root, cli);
6202        else if (!strncmp(cli->last_cmd, "software", strlen("software")))
6203                err = og_resp_software(root, cli);
6204        else if (!strncmp(cli->last_cmd, "refresh", strlen("refresh")))
6205                err = og_resp_refresh(root, cli);
6206        else if (!strncmp(cli->last_cmd, "setup", strlen("setup")))
6207                err = og_resp_setup(cli);
6208        else if (!strncmp(cli->last_cmd, "image/create", strlen("image/create")))
6209                err = og_resp_image_create(root, cli);
6210        else if (!strncmp(cli->last_cmd, "image/restore", strlen("image/restore")))
6211                err = og_resp_image_restore(root, cli);
6212        else
6213                err = -1;
6214
6215        return err;
6216}
6217
6218static void og_agent_read_cb(struct ev_loop *loop, struct ev_io *io, int events)
6219{
6220        struct og_client *cli;
6221        int ret;
6222
6223        cli = container_of(io, struct og_client, io);
6224
6225        ret = og_client_recv(cli, events);
6226        if (ret <= 0)
6227                goto close;
6228
6229        ev_timer_again(loop, &cli->timer);
6230
6231        cli->buf_len += ret;
6232        if (cli->buf_len >= sizeof(cli->buf)) {
6233                syslog(LOG_ERR, "client request from %s:%hu is too long\n",
6234                       inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
6235                goto close;
6236        }
6237
6238        switch (cli->state) {
6239        case OG_AGENT_RECEIVING_HEADER:
6240                ret = og_agent_state_recv_hdr_rest(cli);
6241                if (ret < 0)
6242                        goto close;
6243                if (!ret)
6244                        return;
6245
6246                cli->state = OG_AGENT_RECEIVING_PAYLOAD;
6247                /* Fall through. */
6248        case OG_AGENT_RECEIVING_PAYLOAD:
6249                /* Still not enough data to process request. */
6250                if (cli->buf_len < cli->msg_len)
6251                        return;
6252
6253                cli->state = OG_AGENT_PROCESSING_RESPONSE;
6254                /* fall through. */
6255        case OG_AGENT_PROCESSING_RESPONSE:
6256                ret = og_agent_state_process_response(cli);
6257                if (ret < 0) {
6258                        syslog(LOG_ERR, "Failed to process HTTP request from %s:%hu\n",
6259                               inet_ntoa(cli->addr.sin_addr),
6260                               ntohs(cli->addr.sin_port));
6261                        goto close;
6262                }
6263                syslog(LOG_DEBUG, "leaving client %s:%hu in keepalive mode\n",
6264                       inet_ntoa(cli->addr.sin_addr),
6265                       ntohs(cli->addr.sin_port));
6266                og_agent_reset_state(cli);
6267                break;
6268        default:
6269                syslog(LOG_ERR, "unknown state, critical internal error\n");
6270                goto close;
6271        }
6272        return;
6273close:
6274        ev_timer_stop(loop, &cli->timer);
6275        og_client_release(loop, cli);
6276}
6277
6278static void og_client_timer_cb(struct ev_loop *loop, ev_timer *timer, int events)
6279{
6280        struct og_client *cli;
6281
6282        cli = container_of(timer, struct og_client, timer);
6283        if (cli->keepalive_idx >= 0) {
6284                ev_timer_again(loop, &cli->timer);
6285                return;
6286        }
6287        syslog(LOG_ERR, "timeout request for client %s:%hu\n",
6288               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
6289
6290        og_client_release(loop, cli);
6291}
6292
6293static void og_agent_send_probe(struct og_client *cli)
6294{
6295        json_t *id, *name, *center, *room, *object;
6296        struct og_msg_params params;
6297        struct og_computer computer;
6298        int err;
6299
6300        err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr);
6301        if (err < 0)
6302                return;
6303
6304        params.ips_array[0] = inet_ntoa(cli->addr.sin_addr);
6305        params.ips_array_len = 1;
6306
6307        id = json_integer(computer.id);
6308        center = json_integer(computer.center);
6309        room = json_integer(computer.room);
6310        name = json_string(computer.name);
6311
6312        object = json_object();
6313        json_object_set_new(object, "id", id);
6314        json_object_set_new(object, "name", name);
6315        json_object_set_new(object, "center", center);
6316        json_object_set_new(object, "room", room);
6317
6318        err = og_send_request("probe", OG_METHOD_POST, &params, object);
6319        if (err < 0) {
6320                syslog(LOG_ERR, "Can't send probe to: %s\n",
6321                       params.ips_array[0]);
6322        } else {
6323                syslog(LOG_INFO, "Sent probe to: %s\n",
6324                       params.ips_array[0]);
6325        }
6326}
6327
6328static int socket_s, socket_rest, socket_agent_rest;
6329
6330static void og_server_accept_cb(struct ev_loop *loop, struct ev_io *io,
6331                                int events)
6332{
6333        struct sockaddr_in client_addr;
6334        socklen_t addrlen = sizeof(client_addr);
6335        struct og_client *cli;
6336        int client_sd;
6337
6338        if (events & EV_ERROR)
6339                return;
6340
6341        client_sd = accept(io->fd, (struct sockaddr *)&client_addr, &addrlen);
6342        if (client_sd < 0) {
6343                syslog(LOG_ERR, "cannot accept client connection\n");
6344                return;
6345        }
6346
6347        cli = (struct og_client *)calloc(1, sizeof(struct og_client));
6348        if (!cli) {
6349                close(client_sd);
6350                return;
6351        }
6352        memcpy(&cli->addr, &client_addr, sizeof(client_addr));
6353        if (io->fd == socket_agent_rest)
6354                cli->keepalive_idx = 0;
6355        else
6356                cli->keepalive_idx = -1;
6357
6358        if (io->fd == socket_rest)
6359                cli->rest = true;
6360        else if (io->fd == socket_agent_rest)
6361                cli->agent = true;
6362
6363        syslog(LOG_DEBUG, "connection from client %s:%hu\n",
6364               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
6365
6366        if (io->fd == socket_agent_rest)
6367                ev_io_init(&cli->io, og_agent_read_cb, client_sd, EV_READ);
6368        else
6369                ev_io_init(&cli->io, og_client_read_cb, client_sd, EV_READ);
6370
6371        ev_io_start(loop, &cli->io);
6372        if (io->fd == socket_agent_rest) {
6373                ev_timer_init(&cli->timer, og_client_timer_cb,
6374                              OG_AGENT_CLIENT_TIMEOUT, 0.);
6375        } else {
6376                ev_timer_init(&cli->timer, og_client_timer_cb,
6377                              OG_CLIENT_TIMEOUT, 0.);
6378        }
6379        ev_timer_start(loop, &cli->timer);
6380        list_add(&cli->list, &client_list);
6381
6382        if (io->fd == socket_agent_rest)
6383                og_agent_send_probe(cli);
6384}
6385
6386static int og_socket_server_init(const char *port)
6387{
6388        struct sockaddr_in local;
6389        int sd, on = 1;
6390
6391        sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
6392        if (sd < 0) {
6393                syslog(LOG_ERR, "cannot create main socket\n");
6394                return -1;
6395        }
6396        setsockopt(sd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(int));
6397
6398        local.sin_addr.s_addr = htonl(INADDR_ANY);
6399        local.sin_family = AF_INET;
6400        local.sin_port = htons(atoi(port));
6401
6402        if (bind(sd, (struct sockaddr *) &local, sizeof(local)) < 0) {
6403                close(sd);
6404                syslog(LOG_ERR, "cannot bind socket\n");
6405                return -1;
6406        }
6407
6408        listen(sd, 250);
6409
6410        return sd;
6411}
6412
6413int main(int argc, char *argv[])
6414{
6415        struct ev_io ev_io_server, ev_io_server_rest, ev_io_agent_rest;
6416        int i;
6417
6418        og_loop = ev_default_loop(0);
6419
6420        if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
6421                exit(EXIT_FAILURE);
6422
6423        openlog("ogAdmServer", LOG_PID, LOG_DAEMON);
6424
6425        /*--------------------------------------------------------------------------------------------------------
6426         Validación de parámetros de ejecución y lectura del fichero de configuración del servicio
6427         ---------------------------------------------------------------------------------------------------------*/
6428        if (!validacionParametros(argc, argv, 1)) // Valida parámetros de ejecución
6429                exit(EXIT_FAILURE);
6430
6431        if (!tomaConfiguracion(szPathFileCfg)) { // Toma parametros de configuracion
6432                exit(EXIT_FAILURE);
6433        }
6434
6435        /*--------------------------------------------------------------------------------------------------------
6436         // Inicializa array de información de los clientes
6437         ---------------------------------------------------------------------------------------------------------*/
6438        for (i = 0; i < MAXIMOS_CLIENTES; i++) {
6439                tbsockets[i].ip[0] = '\0';
6440                tbsockets[i].cli = NULL;
6441        }
6442        /*--------------------------------------------------------------------------------------------------------
6443         Creación y configuración del socket del servicio
6444         ---------------------------------------------------------------------------------------------------------*/
6445        socket_s = og_socket_server_init(puerto);
6446        if (socket_s < 0)
6447                exit(EXIT_FAILURE);
6448
6449        ev_io_init(&ev_io_server, og_server_accept_cb, socket_s, EV_READ);
6450        ev_io_start(og_loop, &ev_io_server);
6451
6452        socket_rest = og_socket_server_init("8888");
6453        if (socket_rest < 0)
6454                exit(EXIT_FAILURE);
6455
6456        ev_io_init(&ev_io_server_rest, og_server_accept_cb, socket_rest, EV_READ);
6457        ev_io_start(og_loop, &ev_io_server_rest);
6458
6459        socket_agent_rest = og_socket_server_init("8889");
6460        if (socket_agent_rest < 0)
6461                exit(EXIT_FAILURE);
6462
6463        ev_io_init(&ev_io_agent_rest, og_server_accept_cb, socket_agent_rest, EV_READ);
6464        ev_io_start(og_loop, &ev_io_agent_rest);
6465
6466        if (og_dbi_schedule_get() < 0)
6467                exit(EXIT_FAILURE);
6468
6469        og_schedule_next(og_loop);
6470
6471        infoLog(1); // Inicio de sesión
6472
6473        /* old log file has been deprecated. */
6474        og_log(97, false);
6475
6476        syslog(LOG_INFO, "Waiting for connections\n");
6477
6478        while (1)
6479                ev_loop(og_loop, 0);
6480
6481        exit(EXIT_SUCCESS);
6482}
Note: See TracBrowser for help on using the repository browser.