source: admin/Sources/Services/ogAdmServer/sources/ogAdmServer.c @ 7b89763

configure-oglivelgromero-new-oglivemainmaint-cronmount-efivarfsmultivmmultivm-ogboot-installerogClonningEngineogboot-installer-jenkinsoglive-ipv6test-python-scriptsticket-301ticket-50ticket-50-oldticket-577ticket-585ticket-611ticket-612ticket-693ticket-700ubu24tplunification2use-local-agent-oglivevarios-instalacion
Last change on this file since 7b89763 was 847eb13, checked in by Irina Gómez <irinagomez@…>, 3 years ago

#1066 #990 When ogAdmServer sends WOL packets it includes the netmask of the client to be able to boot the computer on another subnet.

  • Property mode set to 100644
File size: 147.6 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 <ev.h>
13#include <syslog.h>
14#include <sys/ioctl.h>
15#include <ifaddrs.h>
16#include <sys/types.h>
17#include <sys/stat.h>
18#include <fcntl.h>
19#include <jansson.h>
20
21static char usuario[LONPRM]; // Usuario de acceso a la base de datos
22static char pasguor[LONPRM]; // Password del usuario
23static char datasource[LONPRM]; // Dirección IP del gestor de base de datos
24static char catalog[LONPRM]; // Nombre de la base de datos
25static char interface[LONPRM]; // Interface name
26static char auth_token[LONPRM]; // API token
27
28static struct og_dbi_config dbi_config = {
29        .user           = usuario,
30        .passwd         = pasguor,
31        .host           = datasource,
32        .database       = catalog,
33};
34
35//________________________________________________________________________________________________________
36//      Función: tomaConfiguracion
37//
38//      Descripción:
39//              Lee el fichero de configuración del servicio
40//      Parámetros:
41//              filecfg : Ruta completa al fichero de configuración
42//      Devuelve:
43//              true: Si el proceso es correcto
44//              false: En caso de ocurrir algún error
45//________________________________________________________________________________________________________
46static bool tomaConfiguracion(const char *filecfg)
47{
48        char buf[1024], *line;
49        char *key, *value;
50        FILE *fcfg;
51
52        if (filecfg == NULL || strlen(filecfg) == 0) {
53                syslog(LOG_ERR, "No configuration file has been specified\n");
54                return false;
55        }
56
57        fcfg = fopen(filecfg, "rt");
58        if (fcfg == NULL) {
59                syslog(LOG_ERR, "Cannot open configuration file `%s'\n",
60                       filecfg);
61                return false;
62        }
63
64        servidoradm[0] = '\0'; //inicializar variables globales
65
66        line = fgets(buf, sizeof(buf), fcfg);
67        while (line != NULL) {
68                const char *delim = "=";
69
70                line[strlen(line) - 1] = '\0';
71
72                key = strtok(line, delim);
73                value = strtok(NULL, delim);
74
75                if (!strcmp(StrToUpper(key), "SERVIDORADM"))
76                        snprintf(servidoradm, sizeof(servidoradm), "%s", value);
77                else if (!strcmp(StrToUpper(key), "PUERTO"))
78                        snprintf(puerto, sizeof(puerto), "%s", value);
79                else if (!strcmp(StrToUpper(key), "USUARIO"))
80                        snprintf(usuario, sizeof(usuario), "%s", value);
81                else if (!strcmp(StrToUpper(key), "PASSWORD"))
82                        snprintf(pasguor, sizeof(pasguor), "%s", value);
83                else if (!strcmp(StrToUpper(key), "DATASOURCE"))
84                        snprintf(datasource, sizeof(datasource), "%s", value);
85                else if (!strcmp(StrToUpper(key), "CATALOG"))
86                        snprintf(catalog, sizeof(catalog), "%s", value);
87                else if (!strcmp(StrToUpper(key), "INTERFACE"))
88                        snprintf(interface, sizeof(interface), "%s", value);
89                else if (!strcmp(StrToUpper(key), "APITOKEN"))
90                        snprintf(auth_token, sizeof(auth_token), "%s", value);
91
92                line = fgets(buf, sizeof(buf), fcfg);
93        }
94
95        fclose(fcfg);
96
97        if (!servidoradm[0]) {
98                syslog(LOG_ERR, "Missing SERVIDORADM in configuration file\n");
99                return false;
100        }
101        if (!puerto[0]) {
102                syslog(LOG_ERR, "Missing PUERTO in configuration file\n");
103                return false;
104        }
105        if (!usuario[0]) {
106                syslog(LOG_ERR, "Missing USUARIO in configuration file\n");
107                return false;
108        }
109        if (!pasguor[0]) {
110                syslog(LOG_ERR, "Missing PASSWORD in configuration file\n");
111                return false;
112        }
113        if (!datasource[0]) {
114                syslog(LOG_ERR, "Missing DATASOURCE in configuration file\n");
115                return false;
116        }
117        if (!catalog[0]) {
118                syslog(LOG_ERR, "Missing CATALOG in configuration file\n");
119                return false;
120        }
121        if (!interface[0])
122                syslog(LOG_ERR, "Missing INTERFACE in configuration file\n");
123
124        return true;
125}
126
127enum og_client_state {
128        OG_CLIENT_RECEIVING_HEADER      = 0,
129        OG_CLIENT_RECEIVING_PAYLOAD,
130        OG_CLIENT_PROCESSING_REQUEST,
131};
132
133#define OG_MSG_REQUEST_MAXLEN   16384
134
135/* Shut down connection if there is no complete message after 10 seconds. */
136#define OG_CLIENT_TIMEOUT       10
137
138struct og_client {
139        struct ev_io            io;
140        struct ev_timer         timer;
141        struct sockaddr_in      addr;
142        enum og_client_state    state;
143        char                    buf[OG_MSG_REQUEST_MAXLEN];
144        unsigned int            buf_len;
145        unsigned int            msg_len;
146        int                     keepalive_idx;
147        bool                    rest;
148        int                     content_length;
149        char                    auth_token[64];
150};
151
152static inline int og_client_socket(const struct og_client *cli)
153{
154        return cli->io.fd;
155}
156
157// ________________________________________________________________________________________________________
158// Función: clienteDisponible
159//
160//      Descripción:
161//              Comprueba la disponibilidad del cliente para recibir comandos interactivos
162//      Parametros:
163//              - ip : La ip del cliente a buscar
164//              - idx: (Salida)  Indice que ocupa el cliente, de estar ya registrado
165//      Devuelve:
166//              true: Si el cliente está disponible
167//              false: En caso contrario
168// ________________________________________________________________________________________________________
169bool clienteDisponible(char *ip, int* idx)
170{
171        int estado;
172
173        if (clienteExistente(ip, idx)) {
174                estado = strcmp(tbsockets[*idx].estado, CLIENTE_OCUPADO); // Cliente ocupado
175                if (estado == 0)
176                        return false;
177
178                estado = strcmp(tbsockets[*idx].estado, CLIENTE_APAGADO); // Cliente apagado
179                if (estado == 0)
180                        return false;
181
182                estado = strcmp(tbsockets[*idx].estado, CLIENTE_INICIANDO); // Cliente en proceso de inclusión
183                if (estado == 0)
184                        return false;
185
186                return true; // En caso contrario el cliente está disponible
187        }
188        return false; // Cliente no está registrado en el sistema
189}
190// ________________________________________________________________________________________________________
191// Función: clienteExistente
192//
193//      Descripción:
194//              Comprueba si el cliente está registrado en la tabla de socket del sistema
195//      Parametros:
196//              - ip : La ip del cliente a buscar
197//              - idx:(Salida)  Indice que ocupa el cliente, de estar ya registrado
198//      Devuelve:
199//              true: Si el cliente está registrado
200//              false: En caso contrario
201// ________________________________________________________________________________________________________
202bool clienteExistente(char *ip, int* idx)
203{
204        int i;
205        for (i = 0; i < MAXIMOS_CLIENTES; i++) {
206                if (contieneIP(ip, tbsockets[i].ip)) { // Si existe la IP en la cadena
207                        *idx = i;
208                        return true;
209                }
210        }
211        return false;
212}
213// ________________________________________________________________________________________________________
214// Función: hayHueco
215//
216//      Descripción:
217//              Esta función devuelve true o false dependiendo de que haya hueco en la tabla de sockets para un nuevo cliente.
218//      Parametros:
219//              - idx:   Primer indice libre que se podrn utilizar
220//      Devuelve:
221//              true: Si el proceso es correcto
222//              false: En caso de ocurrir algún error
223// ________________________________________________________________________________________________________
224static bool hayHueco(int *idx)
225{
226        int i;
227
228        for (i = 0; i < MAXIMOS_CLIENTES; i++) {
229                if (strncmp(tbsockets[i].ip, "\0", 1) == 0) { // Hay un hueco
230                        *idx = i;
231                        return true;
232                }
233        }
234        return false;
235}
236// ________________________________________________________________________________________________________
237// Función: InclusionClienteWin
238//
239//      Descripción:
240//              Esta función incorpora el socket de un nuevo cliente Windows o Linux a la tabla de clientes
241//      Parámetros:
242//              - socket_c: Socket del cliente que envió el mensaje
243//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
244//      Devuelve:
245//              true: Si el proceso es correcto
246//              false: En caso de ocurrir algún error
247// ________________________________________________________________________________________________________
248static bool InclusionClienteWinLnx(TRAMA *ptrTrama, struct og_client *cli)
249{
250        int socket_c = og_client_socket(cli);
251        int res,idordenador,lon;
252        char nombreordenador[LONFIL];
253
254        res = procesoInclusionClienteWinLnx(socket_c, ptrTrama, &idordenador,
255                                            nombreordenador);
256
257        // Prepara la trama de respuesta
258
259        initParametros(ptrTrama,0);
260        ptrTrama->tipo=MSG_RESPUESTA;
261        lon = sprintf(ptrTrama->parametros, "nfn=RESPUESTA_InclusionClienteWinLnx\r");
262        lon += sprintf(ptrTrama->parametros + lon, "ido=%d\r", idordenador);
263        lon += sprintf(ptrTrama->parametros + lon, "npc=%s\r", nombreordenador);       
264        lon += sprintf(ptrTrama->parametros + lon, "res=%d\r", res);   
265
266        if (!mandaTrama(&socket_c, ptrTrama)) {
267                syslog(LOG_ERR, "failed to send response to %s:%hu reason=%s\n",
268                       inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port),
269                       strerror(errno));
270                return false;
271        }
272        return true;
273}
274// ________________________________________________________________________________________________________
275// Función: procesoInclusionClienteWinLnx
276//
277//      Descripción:
278//              Implementa el proceso de inclusión en el sistema del Cliente Windows o Linux
279//      Parámetros de entrada:
280//              - socket_c: Socket del cliente que envió el mensaje
281//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
282//      Parámetros de salida:
283//              - ido: Identificador del ordenador
284//              - nombreordenador: Nombre del ordenador
285//      Devuelve:
286//              Código del error producido en caso de ocurrir algún error, 0 si el proceso es correcto
287// ________________________________________________________________________________________________________
288bool procesoInclusionClienteWinLnx(int socket_c, TRAMA *ptrTrama, int *idordenador, char *nombreordenador)
289 {
290        struct og_dbi *dbi;
291        const char *msglog;
292        dbi_result result;
293        char *iph;
294
295        // Toma parámetros
296        iph = copiaParametro("iph",ptrTrama); // Toma ip
297
298        dbi = og_dbi_open(&dbi_config);
299        if (!dbi) {
300                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
301                       __func__, __LINE__);
302                goto err_dbi_open;
303        }
304
305        result = dbi_conn_queryf(dbi->conn,
306                        "SELECT idordenador,nombreordenador FROM ordenadores "
307                                " WHERE ordenadores.ip = '%s'", iph);
308        if (!result) {
309                dbi_conn_error(dbi->conn, &msglog);
310                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
311                       __func__, __LINE__, msglog);
312                goto err_query_fail;
313        }
314
315        if (!dbi_result_next_row(result)) {
316                syslog(LOG_ERR, "client does not exist in database (%s:%d)\n",
317                       __func__, __LINE__);
318                dbi_result_free(result);
319                goto err_query_fail;
320        }
321
322        syslog(LOG_DEBUG, "Client %s requesting inclusion\n", iph);
323
324        *idordenador = dbi_result_get_uint(result, "idordenador");
325        nombreordenador = (char *)dbi_result_get_string(result, "nombreordenador");
326
327        dbi_result_free(result);
328        og_dbi_close(dbi);
329
330        if (!registraCliente(iph)) { // Incluyendo al cliente en la tabla de sokets
331                liberaMemoria(iph);
332                syslog(LOG_ERR, "client table is full\n");
333                return false;
334        }
335        liberaMemoria(iph);
336        return true;
337
338err_query_fail:
339        og_dbi_close(dbi);
340err_dbi_open:
341        liberaMemoria(iph);
342        return false;
343}
344// ________________________________________________________________________________________________________
345// Función: InclusionCliente
346//
347//      Descripción:
348//              Esta función incorpora el socket de un nuevo cliente a la tabla de clientes y le devuelve alguna de sus propiedades:
349//              nombre, identificador, tamaño de la caché , etc ...
350//      Parámetros:
351//              - socket_c: Socket del cliente que envió el mensaje
352//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
353//      Devuelve:
354//              true: Si el proceso es correcto
355//              false: En caso de ocurrir algún error
356// ________________________________________________________________________________________________________
357static bool InclusionCliente(TRAMA *ptrTrama, struct og_client *cli)
358{
359        int socket_c = og_client_socket(cli);
360
361        if (!procesoInclusionCliente(cli, ptrTrama)) {
362                initParametros(ptrTrama,0);
363                strcpy(ptrTrama->parametros, "nfn=RESPUESTA_InclusionCliente\rres=0\r");
364                if (!mandaTrama(&socket_c, ptrTrama)) {
365                        syslog(LOG_ERR, "failed to send response to %s:%hu reason=%s\n",
366                               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port),
367                               strerror(errno));
368                        return false;
369                }
370        }
371        return true;
372}
373// ________________________________________________________________________________________________________
374// Función: procesoInclusionCliente
375//
376//      Descripción:
377//              Implementa el proceso de inclusión en el sistema del Cliente
378//      Parámetros:
379//              - socket_c: Socket del cliente que envió el mensaje
380//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
381//      Devuelve:
382//              true: Si el proceso es correcto
383//              false: En caso de ocurrir algún error
384// ________________________________________________________________________________________________________
385bool procesoInclusionCliente(struct og_client *cli, TRAMA *ptrTrama)
386{
387        int socket_c = og_client_socket(cli);
388        const char *msglog, *str;
389        struct og_dbi *dbi;
390        dbi_result result;
391
392        char *iph, *cfg;
393        char nombreordenador[LONFIL];
394        int lon, resul, idordenador, cache, idproautoexec, idaula, idcentro;
395
396        // Toma parámetros
397        iph = copiaParametro("iph",ptrTrama); // Toma ip
398        cfg = copiaParametro("cfg",ptrTrama); // Toma configuracion
399
400        dbi = og_dbi_open(&dbi_config);
401        if (!dbi) {
402                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
403                       __func__, __LINE__);
404                goto err_dbi_open;
405        }
406
407        // Recupera los datos del cliente
408        result = dbi_conn_queryf(dbi->conn,
409                        "SELECT ordenadores.*,aulas.idaula,centros.idcentro FROM ordenadores "
410                                " INNER JOIN aulas ON aulas.idaula=ordenadores.idaula"
411                                " INNER JOIN centros ON centros.idcentro=aulas.idcentro"
412                                " WHERE ordenadores.ip = '%s'", iph);
413
414        if (!result) {
415                dbi_conn_error(dbi->conn, &msglog);
416                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
417                       __func__, __LINE__, msglog);
418                goto err_query_fail;
419        }
420
421        if (!dbi_result_next_row(result)) {
422                syslog(LOG_ERR, "client does not exist in database (%s:%d)\n",
423                       __func__, __LINE__);
424                dbi_result_free(result);
425                goto err_query_fail;
426        }
427
428        syslog(LOG_DEBUG, "Client %s requesting inclusion\n", iph);
429
430        idordenador = dbi_result_get_uint(result, "idordenador");
431        str = (char *)dbi_result_get_string(result, "nombreordenador");
432        sprintf(nombreordenador, "%s", str);
433        cache = dbi_result_get_uint(result, "cache");
434        idproautoexec = dbi_result_get_uint(result, "idproautoexec");
435        idaula = dbi_result_get_uint(result, "idaula");
436        idcentro = dbi_result_get_uint(result, "idcentro");
437        dbi_result_free(result);
438
439        resul = actualizaConfiguracion(dbi, cfg, idordenador); // Actualiza la configuración del ordenador
440        liberaMemoria(cfg);
441        og_dbi_close(dbi);
442
443        if (!resul) {
444                liberaMemoria(iph);
445                syslog(LOG_ERR, "Cannot add client to database\n");
446                return false;
447        }
448
449        if (!registraCliente(iph)) { // Incluyendo al cliente en la tabla de sokets
450                liberaMemoria(iph);
451                syslog(LOG_ERR, "client table is full\n");
452                return false;
453        }
454
455        /*------------------------------------------------------------------------------------------------------------------------------
456         Prepara la trama de respuesta
457         -------------------------------------------------------------------------------------------------------------------------------*/
458        initParametros(ptrTrama,0);
459        ptrTrama->tipo=MSG_RESPUESTA;
460        lon = sprintf(ptrTrama->parametros, "nfn=RESPUESTA_InclusionCliente\r");
461        lon += sprintf(ptrTrama->parametros + lon, "ido=%d\r", idordenador);
462        lon += sprintf(ptrTrama->parametros + lon, "npc=%s\r", nombreordenador);
463        lon += sprintf(ptrTrama->parametros + lon, "che=%d\r", cache);
464        lon += sprintf(ptrTrama->parametros + lon, "exe=%d\r", idproautoexec);
465        lon += sprintf(ptrTrama->parametros + lon, "ida=%d\r", idaula);
466        lon += sprintf(ptrTrama->parametros + lon, "idc=%d\r", idcentro);
467        lon += sprintf(ptrTrama->parametros + lon, "res=%d\r", 1); // Confirmación proceso correcto
468
469        if (!mandaTrama(&socket_c, ptrTrama)) {
470                syslog(LOG_ERR, "failed to send response to %s:%hu reason=%s\n",
471                       inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port),
472                       strerror(errno));
473                return false;
474        }
475        liberaMemoria(iph);
476        return true;
477
478err_query_fail:
479        og_dbi_close(dbi);
480err_dbi_open:
481        liberaMemoria(iph);
482        liberaMemoria(cfg);
483        return false;
484}
485// ________________________________________________________________________________________________________
486// Función: actualizaConfiguracion
487//
488//      Descripción:
489//              Esta función actualiza la base de datos con la configuracion de particiones de un cliente
490//      Parámetros:
491//              - db: Objeto base de datos (ya operativo)
492//              - tbl: Objeto tabla
493//              - cfg: cadena con una Configuración
494//              - ido: Identificador del ordenador cliente
495//      Devuelve:
496//              true: Si el proceso es correcto
497//              false: En caso de ocurrir algún error
498//      Especificaciones:
499//              Los parametros de la configuración son:
500//                      par= Número de partición
501//                      cpt= Codigo o tipo de partición
502//                      sfi= Sistema de ficheros que está implementado en la partición
503//                      soi= Nombre del sistema de ficheros instalado en la partición
504//                      tam= Tamaño de la partición
505// ________________________________________________________________________________________________________
506bool actualizaConfiguracion(struct og_dbi *dbi, char *cfg, int ido)
507{
508        int lon, p, c,i, dato, swu, idsoi, idsfi,k;
509        char *ptrPar[MAXPAR], *ptrCfg[7], *ptrDual[2], tbPar[LONSTD];
510        char *ser, *disk, *par, *cpt, *sfi, *soi, *tam, *uso; // Parametros de configuración.
511        dbi_result result, result_update;
512        const char *msglog;
513
514        lon = 0;
515        p = splitCadena(ptrPar, cfg, '\n');
516        for (i = 0; i < p; i++) {
517                c = splitCadena(ptrCfg, ptrPar[i], '\t');
518
519                // Si la 1ª línea solo incluye el número de serie del equipo; actualizar BD.
520                if (i == 0 && c == 1) {
521                        splitCadena(ptrDual, ptrCfg[0], '=');
522                        ser = ptrDual[1];
523                        if (strlen(ser) > 0) {
524                                // Solo actualizar si número de serie no existía.
525                                result = dbi_conn_queryf(dbi->conn,
526                                                "UPDATE ordenadores SET numserie='%s'"
527                                                " WHERE idordenador=%d AND numserie IS NULL",
528                                                ser, ido);
529                                if (!result) {
530                                        dbi_conn_error(dbi->conn, &msglog);
531                                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
532                                               __func__, __LINE__, msglog);
533                                        return false;
534                                }
535                                dbi_result_free(result);
536                        }
537                        continue;
538                }
539
540                // Distribución de particionado.
541                disk = par = cpt = sfi = soi = tam = uso = NULL;
542
543                splitCadena(ptrDual, ptrCfg[0], '=');
544                disk = ptrDual[1]; // Número de disco
545
546                splitCadena(ptrDual, ptrCfg[1], '=');
547                par = ptrDual[1]; // Número de partición
548
549                k=splitCadena(ptrDual, ptrCfg[2], '=');
550                if(k==2){
551                        cpt = ptrDual[1]; // Código de partición
552                }else{
553                        cpt = (char*)"0";
554                }
555
556                k=splitCadena(ptrDual, ptrCfg[3], '=');
557                if(k==2){
558                        sfi = ptrDual[1]; // Sistema de ficheros
559                        /* Comprueba existencia del s0xistema de ficheros instalado */
560                        idsfi = checkDato(dbi, sfi, "sistemasficheros", "descripcion","idsistemafichero");
561                }
562                else
563                        idsfi=0;
564
565                k=splitCadena(ptrDual, ptrCfg[4], '=');
566                if(k==2){ // Sistema operativo detecdtado
567                        soi = ptrDual[1]; // Nombre del S.O. instalado
568                        /* Comprueba existencia del sistema operativo instalado */
569                        idsoi = checkDato(dbi, soi, "nombresos", "nombreso", "idnombreso");
570                }
571                else
572                        idsoi=0;
573
574                splitCadena(ptrDual, ptrCfg[5], '=');
575                tam = ptrDual[1]; // Tamaño de la partición
576
577                splitCadena(ptrDual, ptrCfg[6], '=');
578                uso = ptrDual[1]; // Porcentaje de uso del S.F.
579
580                lon += sprintf(tbPar + lon, "(%s, %s),", disk, par);
581
582                result = dbi_conn_queryf(dbi->conn,
583                                "SELECT numdisk, numpar, tamano, uso, idsistemafichero, idnombreso"
584                                "  FROM ordenadores_particiones"
585                                " WHERE idordenador=%d AND numdisk=%s AND numpar=%s",
586                                ido, disk, par);
587                if (!result) {
588                        dbi_conn_error(dbi->conn, &msglog);
589                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
590                               __func__, __LINE__, msglog);
591                        return false;
592                }
593                if (!dbi_result_next_row(result)) {
594                        result_update = dbi_conn_queryf(dbi->conn,
595                                        "INSERT INTO ordenadores_particiones(idordenador,numdisk,numpar,codpar,tamano,uso,idsistemafichero,idnombreso,idimagen)"
596                                        " VALUES(%d,%s,%s,0x%s,%s,%s,%d,%d,0)",
597                                        ido, disk, par, cpt, tam, uso, idsfi, idsoi);
598                        if (!result_update) {
599                                dbi_conn_error(dbi->conn, &msglog);
600                                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
601                                       __func__, __LINE__, msglog);
602                                return false;
603                        }
604                        dbi_result_free(result_update);
605
606                } else { // Existe el registro
607                        swu = true; // Se supone que algún dato ha cambiado
608
609                        dato = dbi_result_get_ulonglong(result, "tamano");
610                        if (atoi(tam) == dato) {// Parámetro tamaño igual al almacenado
611                                dato = dbi_result_get_uint(result, "idsistemafichero");
612                                if (idsfi == dato) {// Parámetro sistema de fichero igual al almacenado
613                                        dato = dbi_result_get_uint(result, "idnombreso");
614                                        if (idsoi == dato) {// Parámetro sistema de fichero distinto al almacenado
615                                                swu = false; // Todos los parámetros de la partición son iguales, no se actualiza
616                                        }
617                                }
618                        }
619                        if (swu) { // Hay que actualizar los parámetros de la partición
620                                result_update = dbi_conn_queryf(dbi->conn,
621                                        "UPDATE ordenadores_particiones SET "
622                                        " codpar=0x%s,"
623                                        " tamano=%s,"
624                                        " uso=%s,"
625                                        " idsistemafichero=%d,"
626                                        " idnombreso=%d,"
627                                        " idimagen=0,"
628                                        " idperfilsoft=0,"
629                                        " fechadespliegue=NULL"
630                                        " WHERE idordenador=%d AND numdisk=%s AND numpar=%s",
631                                        cpt, tam, uso, idsfi, idsoi, ido, disk, par);
632                        } else {  // Actualizar porcentaje de uso.
633                                result_update = dbi_conn_queryf(dbi->conn,
634                                        "UPDATE ordenadores_particiones SET "
635                                        " codpar=0x%s,"
636                                        " uso=%s"
637                                        " WHERE idordenador=%d AND numdisk=%s AND numpar=%s",
638                                        cpt, uso, ido, disk, par);
639                        }
640                        if (!result_update) {
641                                dbi_conn_error(dbi->conn, &msglog);
642                                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
643                                       __func__, __LINE__, msglog);
644                                return false;
645                        }
646
647                        dbi_result_free(result_update);
648                }
649                dbi_result_free(result);
650        }
651        lon += sprintf(tbPar + lon, "(0,0)");
652        // Eliminar particiones almacenadas que ya no existen
653        result_update = dbi_conn_queryf(dbi->conn,
654                "DELETE FROM ordenadores_particiones WHERE idordenador=%d AND (numdisk, numpar) NOT IN (%s)",
655                        ido, tbPar);
656        if (!result_update) {
657                dbi_conn_error(dbi->conn, &msglog);
658                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
659                       __func__, __LINE__, msglog);
660                return false;
661        }
662        dbi_result_free(result_update);
663
664        return true;
665}
666// ________________________________________________________________________________________________________
667// Función: checkDato
668//
669//      Descripción:
670//               Esta función comprueba si existe un dato en una tabla y si no es así lo incluye. devuelve en
671//              cualquier caso el identificador del registro existenet o del insertado
672//      Parámetros:
673//              - db: Objeto base de datos (ya operativo)
674//              - tbl: Objeto tabla
675//              - dato: Dato
676//              - tabla: Nombre de la tabla
677//              - nomdato: Nombre del dato en la tabla
678//              - nomidentificador: Nombre del identificador en la tabla
679//      Devuelve:
680//              El identificador del registro existente o el del insertado
681//
682//      Especificaciones:
683//              En caso de producirse algún error se devuelve el valor 0
684// ________________________________________________________________________________________________________
685
686int checkDato(struct og_dbi *dbi, char *dato, const char *tabla,
687                     const char *nomdato, const char *nomidentificador)
688{
689        const char *msglog;
690        int identificador;
691        dbi_result result;
692
693        if (strlen(dato) == 0)
694                return (0); // EL dato no tiene valor
695        result = dbi_conn_queryf(dbi->conn,
696                        "SELECT %s FROM %s WHERE %s ='%s'", nomidentificador,
697                        tabla, nomdato, dato);
698
699        // Ejecuta consulta
700        if (!result) {
701                dbi_conn_error(dbi->conn, &msglog);
702                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
703                       __func__, __LINE__, msglog);
704                return (0);
705        }
706        if (!dbi_result_next_row(result)) { //  Software NO existente
707                dbi_result_free(result);
708
709                result = dbi_conn_queryf(dbi->conn,
710                                "INSERT INTO %s (%s) VALUES('%s')", tabla, nomdato, dato);
711                if (!result) {
712                        dbi_conn_error(dbi->conn, &msglog);
713                        og_info((char *)msglog);
714                        return (0);
715                }
716                // Recupera el identificador del software
717                identificador = dbi_conn_sequence_last(dbi->conn, NULL);
718        } else {
719                identificador = dbi_result_get_uint(result, nomidentificador);
720        }
721        dbi_result_free(result);
722
723        return (identificador);
724}
725// ________________________________________________________________________________________________________
726// Función: registraCliente
727//
728//      Descripción:
729//               Incluye al cliente en la tabla de sokets
730//      Parámetros:
731//              - iph: Dirección ip del cliente
732//      Devuelve:
733//              true: Si el proceso es correcto
734//              false: En caso de ocurrir algún error
735// ________________________________________________________________________________________________________
736bool registraCliente(char *iph)
737{
738        int idx;
739
740        if (!clienteExistente(iph, &idx)) { // Si no existe la IP ...
741                if (!hayHueco(&idx)) { // Busca hueco para el nuevo cliente
742                        return false; // No hay huecos
743                }
744        }
745        strcpy(tbsockets[idx].ip, iph); // Copia IP
746        strcpy(tbsockets[idx].estado, CLIENTE_INICIANDO); // Actualiza el estado del cliente
747        return true;
748}
749// ________________________________________________________________________________________________________
750// Función: AutoexecCliente
751//
752//      Descripción:
753//              Envía archivo de autoexec al cliente
754//      Parámetros:
755//              - socket_c: Socket del cliente que envió el mensaje
756//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
757//      Devuelve:
758//              true: Si el proceso es correcto
759//              false: En caso de ocurrir algún error
760// ________________________________________________________________________________________________________
761static bool AutoexecCliente(TRAMA *ptrTrama, struct og_client *cli)
762{
763        int socket_c = og_client_socket(cli);
764        int lon;
765        char *iph, *exe;
766        FILE *fileexe;
767        char fileautoexec[LONPRM];
768        char parametros[LONGITUD_PARAMETROS];
769        struct og_dbi *dbi;
770
771        iph = copiaParametro("iph",ptrTrama); // Toma dirección IP del cliente
772        exe = copiaParametro("exe",ptrTrama); // Toma identificador del procedimiento inicial
773
774        sprintf(fileautoexec, "/tmp/Sautoexec-%s", iph);
775        liberaMemoria(iph);
776        fileexe = fopen(fileautoexec, "wb"); // Abre fichero de script
777        if (fileexe == NULL) {
778                syslog(LOG_ERR, "cannot create temporary file\n");
779                return false;
780        }
781
782        dbi = og_dbi_open(&dbi_config);
783        if (!dbi) {
784                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
785                       __func__, __LINE__);
786                return false;
787        }
788        initParametros(ptrTrama,0);
789        if (recorreProcedimientos(dbi, parametros, fileexe, exe)) {
790                lon = sprintf(ptrTrama->parametros, "nfn=RESPUESTA_AutoexecCliente\r");
791                lon += sprintf(ptrTrama->parametros + lon, "nfl=%s\r", fileautoexec);
792                lon += sprintf(ptrTrama->parametros + lon, "res=1\r");
793        } else {
794                lon = sprintf(ptrTrama->parametros, "nfn=RESPUESTA_AutoexecCliente\r");
795                lon += sprintf(ptrTrama->parametros + lon, "res=0\r");
796        }
797
798        og_dbi_close(dbi);
799        fclose(fileexe);
800
801        if (!mandaTrama(&socket_c, ptrTrama)) {
802                liberaMemoria(exe);
803                syslog(LOG_ERR, "failed to send response to %s:%hu reason=%s\n",
804                       inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port),
805                       strerror(errno));
806                return false;
807        }
808        liberaMemoria(exe);
809        return true;
810}
811// ________________________________________________________________________________________________________
812// Función: recorreProcedimientos
813//
814//      Descripción:
815//              Crea un archivo con el código de un procedimiento separando cada comando  por un salto de linea
816//      Parámetros:
817//              Database db,char* parametros,FILE* fileexe,char* idp
818//      Devuelve:
819//              true: Si el proceso es correcto
820//              false: En caso de ocurrir algún error
821// ________________________________________________________________________________________________________
822bool recorreProcedimientos(struct og_dbi *dbi, char *parametros, FILE *fileexe, char *idp)
823{
824        char idprocedimiento[LONPRM];
825        int procedimientoid, lsize;
826        const char *msglog, *param;
827        dbi_result result;
828
829        result = dbi_conn_queryf(dbi->conn,
830                        "SELECT procedimientoid,parametros FROM procedimientos_acciones"
831                                " WHERE idprocedimiento=%s ORDER BY orden", idp);
832        if (!result) {
833                dbi_conn_error(dbi->conn, &msglog);
834                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
835                       __func__, __LINE__, msglog);
836                return false;
837        }
838        while (dbi_result_next_row(result)) {
839                procedimientoid = dbi_result_get_uint(result, "procedimientoid");
840                if (procedimientoid > 0) { // Procedimiento recursivo
841                        sprintf(idprocedimiento, "%d", procedimientoid);
842                        if (!recorreProcedimientos(dbi, parametros, fileexe, idprocedimiento)) {
843                                return false;
844                        }
845                } else {
846                        param = dbi_result_get_string(result, "parametros");
847                        sprintf(parametros, "%s@", param);
848                        lsize = strlen(parametros);
849                        fwrite(parametros, 1, lsize, fileexe); // Escribe el código a ejecutar
850                }
851        }
852        dbi_result_free(result);
853
854        return true;
855}
856// ________________________________________________________________________________________________________
857// Función: ComandosPendientes
858//
859//      Descripción:
860//              Esta función busca en la base de datos,comandos pendientes de ejecutar por un  ordenador  concreto
861//      Parámetros:
862//              - socket_c: Socket del cliente que envió el mensaje
863//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
864//      Devuelve:
865//              true: Si el proceso es correcto
866//              false: En caso de ocurrir algún error
867// ________________________________________________________________________________________________________
868static bool ComandosPendientes(TRAMA *ptrTrama, struct og_client *cli)
869{
870        int socket_c = og_client_socket(cli);
871        char *ido,*iph,pids[LONPRM];
872        int ids, idx;
873
874        iph = copiaParametro("iph",ptrTrama); // Toma dirección IP
875        ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
876
877        if (!clienteExistente(iph, &idx)) { // Busca índice del cliente
878                liberaMemoria(iph);
879                liberaMemoria(ido);
880                syslog(LOG_ERR, "client does not exist\n");
881                return false;
882        }
883        if (buscaComandos(ido, ptrTrama, &ids)) { // Existen comandos pendientes
884                ptrTrama->tipo = MSG_COMANDO;
885                sprintf(pids, "\rids=%d\r", ids);
886                strcat(ptrTrama->parametros, pids);
887                strcpy(tbsockets[idx].estado, CLIENTE_OCUPADO);
888        } else {
889                initParametros(ptrTrama,0);
890                strcpy(ptrTrama->parametros, "nfn=NoComandosPtes\r");
891        }
892        if (!mandaTrama(&socket_c, ptrTrama)) {
893                liberaMemoria(iph);
894                liberaMemoria(ido);
895                syslog(LOG_ERR, "failed to send response to %s:%hu reason=%s\n",
896                       inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port),
897                       strerror(errno));
898                return false;
899        }
900        liberaMemoria(iph);
901        liberaMemoria(ido);     
902        return true;
903}
904// ________________________________________________________________________________________________________
905// Función: buscaComandos
906//
907//      Descripción:
908//              Busca en la base de datos,comandos pendientes de ejecutar por el cliente
909//      Parámetros:
910//              - ido: Identificador del ordenador
911//              - cmd: Parámetros del comando (Salida)
912//              - ids: Identificador de la sesion(Salida)
913//      Devuelve:
914//              true: Si el proceso es correcto
915//              false: En caso de ocurrir algún error
916// ________________________________________________________________________________________________________
917bool buscaComandos(char *ido, TRAMA *ptrTrama, int *ids)
918{
919        const char *param, *msglog;
920        struct og_dbi *dbi;
921        dbi_result result;
922        unsigned int lonprm;
923
924        dbi = og_dbi_open(&dbi_config);
925        if (!dbi) {
926                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
927                       __func__, __LINE__);
928                goto err_dbi_open;
929        }
930        result = dbi_conn_queryf(dbi->conn,
931                        "SELECT sesion, parametros"\
932                        " FROM acciones WHERE idordenador=%s AND estado='%d'"\
933                        " ORDER BY idaccion", ido, ACCION_INICIADA);
934        if (!result) {
935                dbi_conn_error(dbi->conn, &msglog);
936                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
937                       __func__, __LINE__, msglog);
938                goto err_query_fail;
939        }
940        if (!dbi_result_next_row(result)) {
941                dbi_result_free(result);
942                og_dbi_close(dbi);
943                return false; // No hay comandos pendientes
944        }
945
946        *ids = dbi_result_get_uint(result, "sesion");
947        param = dbi_result_get_string(result, "parametros");
948        lonprm = strlen(param);
949
950        if(!initParametros(ptrTrama,lonprm + LONGITUD_PARAMETROS)){
951                syslog(LOG_ERR, "%s:%d OOM\n", __FILE__, __LINE__);
952                goto err_init_params;
953        }
954        sprintf(ptrTrama->parametros, "%s", param);
955
956        dbi_result_free(result);
957        og_dbi_close(dbi);
958
959        return true; // Hay comandos pendientes, se toma el primero de la cola
960
961err_init_params:
962        dbi_result_free(result);
963err_query_fail:
964        og_dbi_close(dbi);
965err_dbi_open:
966        return false;
967}
968// ________________________________________________________________________________________________________
969// Función: DisponibilidadComandos
970//
971//      Descripción:
972//              Esta función habilita a un cliente para recibir comandos desde la consola
973//      Parámetros:
974//              - socket_c: Socket del cliente que envió el mensaje
975//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
976//      Devuelve:
977//              true: Si el proceso es correcto
978//              false: En caso de ocurrir algún error
979// ________________________________________________________________________________________________________
980//
981static bool DisponibilidadComandos(TRAMA *ptrTrama, struct og_client *cli)
982{
983        char *iph, *tpc;
984        int idx;
985
986        iph = copiaParametro("iph",ptrTrama); // Toma ip
987        if (!clienteExistente(iph, &idx)) { // Busca índice del cliente
988                liberaMemoria(iph);
989                syslog(LOG_ERR, "client does not exist\n");
990                return false;
991        }
992        tpc = copiaParametro("tpc",ptrTrama); // Tipo de cliente (Plataforma y S.O.)
993        strcpy(tbsockets[idx].estado, tpc);
994        cli->keepalive_idx = idx;
995        liberaMemoria(iph);
996        liberaMemoria(tpc);             
997        return true;
998}
999// ________________________________________________________________________________________________________
1000// Función: respuestaEstandar
1001//
1002//      Descripción:
1003//              Esta función actualiza la base de datos con el resultado de la ejecución de un comando con seguimiento
1004//      Parámetros:
1005//              - res: resultado de la ejecución del comando
1006//              - der: Descripción del error si hubiese habido
1007//              - iph: Dirección IP
1008//              - ids: identificador de la sesión
1009//              - ido: Identificador del ordenador que notifica
1010//              - db: Objeto base de datos (operativo)
1011//              - tbl: Objeto tabla
1012//      Devuelve:
1013//              true: Si el proceso es correcto
1014//              false: En caso de ocurrir algún error
1015// ________________________________________________________________________________________________________
1016static bool respuestaEstandar(TRAMA *ptrTrama, char *iph, char *ido,
1017                              struct og_dbi *dbi)
1018{
1019        char *res, *ids, *der;
1020        char fechafin[LONPRM];
1021        const char *msglog;
1022        dbi_result result;
1023        struct tm* st;
1024        int idaccion;
1025
1026        ids = copiaParametro("ids",ptrTrama);
1027        res = copiaParametro("res",ptrTrama);
1028
1029        if (ids == NULL) {
1030                if (atoi(res) == ACCION_FALLIDA) {
1031                        liberaMemoria(res);
1032                        return false;
1033                }
1034                liberaMemoria(res);
1035                return true;
1036        }
1037
1038        if (atoi(ids) == 0) {
1039                liberaMemoria(ids);
1040                if (atoi(res) == ACCION_FALLIDA) {
1041                        liberaMemoria(res);
1042                        return false;
1043                }
1044                liberaMemoria(res);
1045                return true;
1046        }
1047
1048        result = dbi_conn_queryf(dbi->conn,
1049                        "SELECT * FROM acciones WHERE idordenador=%s"
1050                        " AND sesion=%s ORDER BY idaccion", ido,ids);
1051
1052        liberaMemoria(ids);
1053
1054        if (!result) {
1055                dbi_conn_error(dbi->conn, &msglog);
1056                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1057                       __func__, __LINE__, msglog);
1058                return false;
1059        }
1060        if (!dbi_result_next_row(result)) {
1061                syslog(LOG_ERR, "no actions available\n");
1062                dbi_result_free(result);
1063                return true;
1064        }
1065
1066        idaccion = dbi_result_get_uint(result, "idaccion");
1067        dbi_result_free(result);
1068
1069        st = tomaHora();
1070        sprintf(fechafin, "%d/%d/%d %d:%d:%d", st->tm_year + 1900, st->tm_mon + 1,
1071                        st->tm_mday, st->tm_hour, st->tm_min, st->tm_sec);
1072
1073        der = copiaParametro("der",ptrTrama); // Toma descripción del error (si hubiera habido)
1074
1075        result = dbi_conn_queryf(dbi->conn,
1076                        "UPDATE acciones"\
1077                        "   SET resultado='%s',estado='%d',fechahorafin='%s',descrinotificacion='%s'"\
1078                        " WHERE idordenador=%s AND idaccion=%d",
1079                        res, ACCION_FINALIZADA, fechafin, der, ido, idaccion);
1080        if (!result) {
1081                dbi_conn_error(dbi->conn, &msglog);
1082                liberaMemoria(res);
1083                liberaMemoria(der);
1084                og_info((char *)msglog);
1085                return false;
1086        }
1087        dbi_result_free(result);
1088
1089        liberaMemoria(der);
1090
1091        if (atoi(res) == ACCION_FALLIDA) {
1092                liberaMemoria(res);
1093                return false;
1094        }
1095
1096        liberaMemoria(res);
1097        return true;
1098}
1099
1100static bool og_send_cmd(char *ips_array[], int ips_array_len,
1101                        const char *state, TRAMA *ptrTrama)
1102{
1103        int i, idx;
1104
1105        for (i = 0; i < ips_array_len; i++) {
1106                if (clienteDisponible(ips_array[i], &idx)) { // Si el cliente puede recibir comandos
1107                        int sock = tbsockets[idx].cli ? tbsockets[idx].cli->io.fd : -1;
1108
1109                        strcpy(tbsockets[idx].estado, state); // Actualiza el estado del cliente
1110                        if (sock >= 0 && !mandaTrama(&sock, ptrTrama)) {
1111                                syslog(LOG_ERR, "failed to send response to %s:%s\n",
1112                                       ips_array[i], strerror(errno));
1113                        }
1114                }
1115        }
1116        return true;
1117}
1118
1119// ________________________________________________________________________________________________________
1120// Función: enviaComando
1121//
1122//      Descripción:
1123//              Envía un comando a los clientes
1124//      Parámetros:
1125//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1126//              - estado: Estado en el se deja al cliente mientras se ejecuta el comando
1127//      Devuelve:
1128//              true: Si el proceso es correcto
1129//              false: En caso de ocurrir algún error
1130// ________________________________________________________________________________________________________
1131bool enviaComando(TRAMA* ptrTrama, const char *estado)
1132{
1133        char *iph, *Ipes, *ptrIpes[MAXIMOS_CLIENTES];
1134        int lon;
1135
1136        iph = copiaParametro("iph",ptrTrama); // Toma dirección/es IP
1137        lon = strlen(iph); // Calcula longitud de la cadena de direccion/es IPE/S
1138        Ipes = (char*) reservaMemoria(lon + 1);
1139        if (Ipes == NULL) {
1140                syslog(LOG_ERR, "%s:%d OOM\n", __FILE__, __LINE__);
1141                return false;
1142        }
1143       
1144        strcpy(Ipes, iph); // Copia cadena de IPES
1145        liberaMemoria(iph);
1146
1147        lon = splitCadena(ptrIpes, Ipes, ';');
1148        FINCADaINTRO(ptrTrama);
1149
1150        if (!og_send_cmd(ptrIpes, lon, estado, ptrTrama))
1151                return false;
1152
1153        liberaMemoria(Ipes);
1154        return true;
1155}
1156//______________________________________________________________________________________________________
1157// Función: respuestaConsola
1158//
1159//      Descripción:
1160//              Envia una respuesta a la consola sobre el resultado de la ejecución de un comando
1161//      Parámetros:
1162//              - socket_c: (Salida) Socket utilizado para el envío
1163//              - res: Resultado del envío del comando
1164//      Devuelve:
1165//              true: Si el proceso es correcto
1166//              false: En caso de ocurrir algún error
1167// ________________________________________________________________________________________________________
1168bool respuestaConsola(int socket_c, TRAMA *ptrTrama, int res)
1169{
1170        initParametros(ptrTrama,0);
1171        sprintf(ptrTrama->parametros, "res=%d\r", res);
1172        if (!mandaTrama(&socket_c, ptrTrama)) {
1173                syslog(LOG_ERR, "%s:%d failed to send response: %s\n",
1174                       __func__, __LINE__, strerror(errno));
1175                return false;
1176        }
1177        return true;
1178}
1179// ________________________________________________________________________________________________________
1180// Función: Levanta
1181//
1182//      Descripción:
1183//              Enciende ordenadores a través de la red cuyas macs se pasan como parámetro
1184//      Parámetros:
1185//              - iph: Cadena de direcciones ip separadas por ";"
1186//              - mac: Cadena de direcciones mac separadas por ";"
1187//              - mar: Método de arranque (1=Broadcast, 2=Unicast)
1188//      Devuelve:
1189//              true: Si el proceso es correcto
1190//              false: En caso de ocurrir algún error
1191// ________________________________________________________________________________________________________
1192bool Levanta(char *ptrIP[], char *ptrMacs[], char *ptrNetmasks[], int lon, char *mar)
1193{
1194        unsigned int on = 1;
1195        struct sockaddr_in local;
1196        int i, res;
1197        int s;
1198
1199        /* Creación de socket para envío de magig packet */
1200        s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1201        if (s < 0) {
1202                syslog(LOG_ERR, "cannot create socket for magic packet\n");
1203                return false;
1204        }
1205        res = setsockopt(s, SOL_SOCKET, SO_BROADCAST, (unsigned int *) &on,
1206                         sizeof(on));
1207        if (res < 0) {
1208                syslog(LOG_ERR, "cannot set broadcast socket\n");
1209                return false;
1210        }
1211
1212        memset(&local, 0, sizeof(local));
1213        local.sin_family = AF_INET;
1214        local.sin_port = htons(PUERTO_WAKEUP);
1215        local.sin_addr.s_addr = htonl(INADDR_ANY);
1216
1217        for (i = 0; i < lon; i++) {
1218                if (!WakeUp(s, ptrIP[i], ptrMacs[i], ptrNetmasks[i], mar)) {
1219                        syslog(LOG_ERR, "problem sending magic packet\n");
1220                        close(s);
1221                        return false;
1222                }
1223        }
1224        close(s);
1225        return true;
1226}
1227
1228#define OG_WOL_SEQUENCE         6
1229#define OG_WOL_MACADDR_LEN      6
1230#define OG_WOL_REPEAT           16
1231
1232struct wol_msg {
1233        char secuencia_FF[OG_WOL_SEQUENCE];
1234        char macbin[OG_WOL_REPEAT][OG_WOL_MACADDR_LEN];
1235};
1236
1237static bool wake_up_broadcast(int sd, struct sockaddr_in *client,
1238                              const struct wol_msg *msg, const struct in_addr *addr)
1239{
1240        struct sockaddr_in *broadcast_addr;
1241        struct ifaddrs *ifaddr, *ifa;
1242        int ret1, ret2;
1243
1244        if (getifaddrs(&ifaddr) < 0) {
1245                syslog(LOG_ERR, "cannot get list of addresses\n");
1246                return false;
1247        }
1248
1249
1250        client->sin_addr.s_addr = htonl(INADDR_BROADCAST);
1251
1252        for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
1253                if (ifa->ifa_addr == NULL ||
1254                    ifa->ifa_addr->sa_family != AF_INET ||
1255                    strcmp(ifa->ifa_name, interface) != 0)
1256                        continue;
1257
1258                broadcast_addr =
1259                        (struct sockaddr_in *)ifa->ifa_ifu.ifu_broadaddr;
1260                client->sin_addr.s_addr = broadcast_addr->sin_addr.s_addr;
1261                break;
1262        }
1263        freeifaddrs(ifaddr);
1264
1265        ret1 = sendto(sd, msg, sizeof(*msg), 0,
1266                     (struct sockaddr *)client, sizeof(*client));
1267        client->sin_addr.s_addr = addr->s_addr;
1268        ret2 = sendto(sd, msg, sizeof(*msg), 0,
1269                     (struct sockaddr *)client, sizeof(*client));
1270        if ((ret1 < 0) & (ret2 < 0)) {
1271                syslog(LOG_ERR, "failed to send broadcast wol\n");
1272                return false;
1273        }
1274
1275        return true;
1276}
1277
1278static bool wake_up_unicast(int sd, struct sockaddr_in *client,
1279                            const struct wol_msg *msg,
1280                            const struct in_addr *addr)
1281{
1282        int ret;
1283
1284        client->sin_addr.s_addr = addr->s_addr;
1285
1286        ret = sendto(sd, msg, sizeof(*msg), 0,
1287                     (struct sockaddr *)client, sizeof(*client));
1288        if (ret < 0) {
1289                syslog(LOG_ERR, "failed to send unicast wol\n");
1290                return false;
1291        }
1292
1293        return true;
1294}
1295
1296
1297
1298enum wol_delivery_type {
1299        OG_WOL_BROADCAST = 1,
1300        OG_WOL_UNICAST = 2
1301};
1302
1303//_____________________________________________________________________________________________________________
1304// Función: WakeUp
1305//
1306//       Descripción:
1307//              Enciende el ordenador cuya MAC se pasa como parámetro
1308//      Parámetros:
1309//              - s : Socket para enviar trama magic packet
1310//              - iph : Cadena con la dirección ip
1311//              - mac : Cadena con la dirección mac en formato XXXXXXXXXXXX
1312//              - mar: Método de arranque (1=Broadcast, 2=Unicast)
1313//      Devuelve:
1314//              true: Si el proceso es correcto
1315//              false: En caso de ocurrir algún error
1316//_____________________________________________________________________________________________________________
1317//
1318bool WakeUp(int s, char* iph, char *mac, char *netmask, char *mar)
1319{
1320        unsigned int macaddr[OG_WOL_MACADDR_LEN];
1321        char HDaddress_bin[OG_WOL_MACADDR_LEN];
1322        struct sockaddr_in WakeUpCliente;
1323        struct wol_msg Trama_WakeUp;
1324        struct in_addr addr, netmask_addr, broadcast_addr ={};
1325        bool ret;
1326        int i;
1327
1328        if (!inet_aton(iph, &addr)) {
1329                syslog(LOG_ERR, "bad IP address\n");
1330                return false;
1331        }
1332
1333        if (!inet_aton(netmask, &netmask_addr)) {
1334                syslog(LOG_ERR, "bad netmask address: %s\n", netmask);
1335                return false;
1336        }
1337        broadcast_addr.s_addr = addr.s_addr | ~netmask_addr.s_addr;
1338
1339        for (i = 0; i < 6; i++) // Primera secuencia de la trama Wake Up (0xFFFFFFFFFFFF)
1340                Trama_WakeUp.secuencia_FF[i] = 0xFF;
1341
1342        sscanf(mac, "%02x%02x%02x%02x%02x%02x",
1343               &macaddr[0], &macaddr[1], &macaddr[2],
1344               &macaddr[3], &macaddr[4], &macaddr[5]);
1345
1346        for (i = 0; i < 6; i++)
1347                HDaddress_bin[i] = (uint8_t)macaddr[i];
1348
1349        for (i = 0; i < 16; i++) // Segunda secuencia de la trama Wake Up , repetir 16 veces su la MAC
1350                memcpy(&Trama_WakeUp.macbin[i][0], &HDaddress_bin, 6);
1351
1352        /* Creación de socket del cliente que recibe la trama magic packet */
1353        WakeUpCliente.sin_family = AF_INET;
1354        WakeUpCliente.sin_port = htons((short) PUERTO_WAKEUP);
1355
1356        switch (atoi(mar)) {
1357        case OG_WOL_BROADCAST:
1358                ret = wake_up_broadcast(s, &WakeUpCliente, &Trama_WakeUp, &broadcast_addr );
1359                break;
1360        case OG_WOL_UNICAST:
1361                ret = wake_up_unicast(s, &WakeUpCliente, &Trama_WakeUp, &addr);
1362                break;
1363        default:
1364                syslog(LOG_ERR, "unknown wol type\n");
1365                ret = false;
1366                break;
1367        }
1368        return ret;
1369}
1370// ________________________________________________________________________________________________________
1371// Función: RESPUESTA_Arrancar
1372//
1373//      Descripción:
1374//              Respuesta del cliente al comando Arrancar
1375//      Parámetros:
1376//              - socket_c: Socket del cliente que envió el mensaje
1377//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1378//      Devuelve:
1379//              true: Si el proceso es correcto
1380//              false: En caso de ocurrir algún error
1381// ________________________________________________________________________________________________________
1382static bool RESPUESTA_Arrancar(TRAMA* ptrTrama, struct og_client *cli)
1383{
1384        struct og_dbi *dbi;
1385        char *iph, *ido;
1386        char *tpc;
1387        int i;
1388
1389        dbi = og_dbi_open(&dbi_config);
1390        if (!dbi) {
1391                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
1392                       __func__, __LINE__);
1393                return false;
1394        }
1395
1396        iph = copiaParametro("iph",ptrTrama); // Toma dirección ip
1397        ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
1398
1399        if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) {
1400                liberaMemoria(iph);
1401                liberaMemoria(ido);
1402                syslog(LOG_ERR, "failed to register notification\n");
1403                og_dbi_close(dbi);
1404                return false;
1405        }
1406
1407        tpc = copiaParametro("tpc",ptrTrama); // Tipo de cliente (Plataforma y S.O.)
1408        if (clienteExistente(iph, &i)) // Actualiza estado
1409                strcpy(tbsockets[i].estado, tpc);
1410
1411        liberaMemoria(iph);
1412        liberaMemoria(ido);
1413        liberaMemoria(tpc);
1414        og_dbi_close(dbi);
1415
1416        return true;
1417}
1418// ________________________________________________________________________________________________________
1419// Función: RESPUESTA_Apagar
1420//
1421//      Descripción:
1422//              Respuesta del cliente al comando Apagar
1423//      Parámetros:
1424//              - socket_c: Socket del cliente que envió el mensaje
1425//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1426//      Devuelve:
1427//              true: Si el proceso es correcto
1428//              false: En caso de ocurrir algún error
1429// ________________________________________________________________________________________________________
1430static bool RESPUESTA_Apagar(TRAMA* ptrTrama, struct og_client *cli)
1431{
1432        struct og_dbi *dbi;
1433        char *iph, *ido;
1434        int i;
1435
1436        dbi = og_dbi_open(&dbi_config);
1437        if (!dbi) {
1438                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
1439                       __func__, __LINE__);
1440                return false;
1441        }
1442
1443        iph = copiaParametro("iph",ptrTrama); // Toma dirección ip
1444        ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
1445
1446        if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) {
1447                liberaMemoria(iph);
1448                liberaMemoria(ido);
1449                syslog(LOG_ERR, "failed to register notification\n");
1450                og_dbi_close(dbi);
1451                return false; // Error al registrar notificacion
1452        }
1453
1454        if (clienteExistente(iph, &i)) // Actualiza estado
1455                strcpy(tbsockets[i].estado, CLIENTE_APAGADO);
1456
1457        liberaMemoria(iph);
1458        liberaMemoria(ido);
1459        og_dbi_close(dbi);
1460
1461        return true;
1462}
1463// ________________________________________________________________________________________________________
1464// Función: RESPUESTA_CrearImagen
1465//
1466//      Descripción:
1467//              Respuesta del cliente al comando CrearImagen
1468//      Parámetros:
1469//              - socket_c: Socket del cliente que envió el mensaje
1470//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1471//      Devuelve:
1472//              true: Si el proceso es correcto
1473//              false: En caso de ocurrir algún error
1474// ________________________________________________________________________________________________________
1475static bool RESPUESTA_CrearImagen(TRAMA* ptrTrama, struct og_client *cli)
1476{
1477        char *iph, *dsk, *par, *cpt, *ipr, *ido;
1478        struct og_dbi *dbi;
1479        char *idi;
1480        bool res;
1481
1482        dbi = og_dbi_open(&dbi_config);
1483        if (!dbi) {
1484                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
1485                       __func__, __LINE__);
1486                return false;
1487        }
1488
1489        iph = copiaParametro("iph",ptrTrama); // Toma dirección ip
1490        ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
1491
1492        if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) {
1493                liberaMemoria(iph);
1494                liberaMemoria(ido);
1495                syslog(LOG_ERR, "failed to register notification\n");
1496                og_dbi_close(dbi);
1497                return false; // Error al registrar notificacion
1498        }
1499
1500        // Acciones posteriores
1501        idi = copiaParametro("idi",ptrTrama);
1502        dsk = copiaParametro("dsk",ptrTrama);
1503        par = copiaParametro("par",ptrTrama);
1504        cpt = copiaParametro("cpt",ptrTrama);
1505        ipr = copiaParametro("ipr",ptrTrama);
1506
1507        res=actualizaCreacionImagen(dbi, idi, dsk, par, cpt, ipr, ido);
1508
1509        liberaMemoria(idi);
1510        liberaMemoria(par);
1511        liberaMemoria(cpt);
1512        liberaMemoria(ipr);
1513        og_dbi_close(dbi);
1514
1515        if (!res)
1516                syslog(LOG_ERR, "Problem processing update\n");
1517
1518        return res;
1519}
1520// ________________________________________________________________________________________________________
1521// Función: actualizaCreacionImagen
1522//
1523//      Descripción:
1524//              Esta función actualiza la base de datos con el resultado de la creación de una imagen
1525//      Parámetros:
1526//              - db: Objeto base de datos (ya operativo)
1527//              - tbl: Objeto tabla
1528//              - idi: Identificador de la imagen
1529//              - dsk: Disco de donde se creó
1530//              - par: Partición de donde se creó
1531//              - cpt: Código de partición
1532//              - ipr: Ip del repositorio
1533//              - ido: Identificador del ordenador modelo
1534//      Devuelve:
1535//              true: Si el proceso es correcto
1536//              false: En caso de ocurrir algún error
1537// ________________________________________________________________________________________________________
1538bool actualizaCreacionImagen(struct og_dbi *dbi, char *idi, char *dsk,
1539                             char *par, char *cpt, char *ipr, char *ido)
1540{
1541        const char *msglog;
1542        dbi_result result;
1543        int idr,ifs;
1544
1545        /* Toma identificador del repositorio correspondiente al ordenador modelo */
1546        result = dbi_conn_queryf(dbi->conn,
1547                        "SELECT repositorios.idrepositorio"
1548                        "  FROM repositorios"
1549                        "  LEFT JOIN ordenadores USING (idrepositorio)"
1550                        " WHERE repositorios.ip='%s' AND ordenadores.idordenador=%s", ipr, ido);
1551
1552        if (!result) {
1553                dbi_conn_error(dbi->conn, &msglog);
1554                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1555                       __func__, __LINE__, msglog);
1556                return false;
1557        }
1558        if (!dbi_result_next_row(result)) {
1559                syslog(LOG_ERR,
1560                       "repository does not exist in database (%s:%d)\n",
1561                       __func__, __LINE__);
1562                dbi_result_free(result);
1563                return false;
1564        }
1565        idr = dbi_result_get_uint(result, "idrepositorio");
1566        dbi_result_free(result);
1567
1568        /* Toma identificador del perfilsoftware */
1569        result = dbi_conn_queryf(dbi->conn,
1570                        "SELECT idperfilsoft"
1571                        "  FROM ordenadores_particiones"
1572                        " WHERE idordenador=%s AND numdisk=%s AND numpar=%s", ido, dsk, par);
1573
1574        if (!result) {
1575                dbi_conn_error(dbi->conn, &msglog);
1576                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1577                       __func__, __LINE__, msglog);
1578                return false;
1579        }
1580        if (!dbi_result_next_row(result)) {
1581                syslog(LOG_ERR,
1582                       "software profile does not exist in database (%s:%d)\n",
1583                       __func__, __LINE__);
1584                dbi_result_free(result);
1585                return false;
1586        }
1587        ifs = dbi_result_get_uint(result, "idperfilsoft");
1588        dbi_result_free(result);
1589
1590        /* Actualizar los datos de la imagen */
1591        result = dbi_conn_queryf(dbi->conn,
1592                "UPDATE imagenes"
1593                "   SET idordenador=%s, numdisk=%s, numpar=%s, codpar=%s,"
1594                "       idperfilsoft=%d, idrepositorio=%d,"
1595                "       fechacreacion=NOW(), revision=revision+1"
1596                " WHERE idimagen=%s", ido, dsk, par, cpt, ifs, idr, idi);
1597
1598        if (!result) {
1599                dbi_conn_error(dbi->conn, &msglog);
1600                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1601                       __func__, __LINE__, msglog);
1602                return false;
1603        }
1604        dbi_result_free(result);
1605
1606        /* Actualizar los datos en el cliente */
1607        result = dbi_conn_queryf(dbi->conn,
1608                "UPDATE ordenadores_particiones"
1609                "   SET idimagen=%s, revision=(SELECT revision FROM imagenes WHERE idimagen=%s),"
1610                "       fechadespliegue=NOW()"
1611                " WHERE idordenador=%s AND numdisk=%s AND numpar=%s",
1612                idi, idi, ido, dsk, par);
1613        if (!result) {
1614                dbi_conn_error(dbi->conn, &msglog);
1615                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1616                       __func__, __LINE__, msglog);
1617                return false;
1618        }
1619        dbi_result_free(result);
1620
1621        return true;
1622}
1623// ________________________________________________________________________________________________________
1624// Función: RESPUESTA_CrearImagenBasica
1625//
1626//      Descripción:
1627//              Respuesta del cliente al comando CrearImagenBasica
1628//      Parámetros:
1629//              - socket_c: Socket del cliente que envió el mensaje
1630//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1631//      Devuelve:
1632//              true: Si el proceso es correcto
1633//              false: En caso de ocurrir algún error
1634// ________________________________________________________________________________________________________
1635static bool RESPUESTA_CrearImagenBasica(TRAMA* ptrTrama, struct og_client *cli)
1636{
1637        // La misma respuesta que la creación de imagen monolítica
1638        return RESPUESTA_CrearImagen(ptrTrama, cli);
1639}
1640// ________________________________________________________________________________________________________
1641// Función: RESPUESTA_CrearSoftIncremental
1642//
1643//      Descripción:
1644//              Respuesta del cliente al comando crearImagenDiferencial
1645//      Parámetros:
1646//              - socket_c: Socket del cliente que envió el mensaje
1647//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1648//      Devuelve:
1649//              true: Si el proceso es correcto
1650//              false: En caso de ocurrir algún error
1651// ________________________________________________________________________________________________________
1652static bool RESPUESTA_CrearSoftIncremental(TRAMA* ptrTrama, struct og_client *cli)
1653{
1654        char *iph,*par,*ido,*idf;
1655        int ifs;
1656        const char *msglog;
1657        struct og_dbi *dbi;
1658        dbi_result result;
1659
1660        dbi = og_dbi_open(&dbi_config);
1661        if (!dbi) {
1662                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
1663                       __func__, __LINE__);
1664                return false;
1665        }
1666
1667        iph = copiaParametro("iph",ptrTrama); // Toma dirección ip
1668        ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
1669
1670        if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) {
1671                og_dbi_close(dbi);
1672                liberaMemoria(iph);
1673                liberaMemoria(ido);
1674                syslog(LOG_ERR, "failed to register notification\n");
1675                return false;
1676        }
1677
1678        par = copiaParametro("par",ptrTrama);
1679
1680        /* Toma identificador del perfilsoftware creado por el inventario de software */
1681        result = dbi_conn_queryf(dbi->conn,
1682                                 "SELECT idperfilsoft FROM ordenadores_particiones WHERE idordenador=%s AND numpar=%s",
1683                                 ido, par);
1684        liberaMemoria(iph);
1685        liberaMemoria(ido);     
1686        liberaMemoria(par);     
1687
1688        if (!result) {
1689                dbi_conn_error(dbi->conn, &msglog);
1690                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1691                       __func__, __LINE__, msglog);
1692                og_dbi_close(dbi);
1693                return false;
1694        }
1695        if (!dbi_result_next_row(result)) {
1696                syslog(LOG_ERR,
1697                       "software profile does not exist in database (%s:%d)\n",
1698                       __func__, __LINE__);
1699                dbi_result_free(result);
1700                og_dbi_close(dbi);
1701                return false;
1702        }
1703        ifs = dbi_result_get_uint(result, "idperfilsoft");
1704        dbi_result_free(result);
1705
1706        /* Actualizar los datos de la imagen */
1707        idf = copiaParametro("idf", ptrTrama);
1708        result = dbi_conn_queryf(dbi->conn,
1709                                 "UPDATE imagenes SET idperfilsoft=%d WHERE idimagen=%s",
1710                                 ifs, idf);
1711        liberaMemoria(idf);     
1712
1713        if (!result) {
1714                dbi_conn_error(dbi->conn, &msglog);
1715                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1716                       __func__, __LINE__, msglog);
1717                og_dbi_close(dbi);
1718                return false;
1719        }
1720        dbi_result_free(result);
1721
1722        og_dbi_close(dbi);
1723
1724        return true;
1725}
1726// ________________________________________________________________________________________________________
1727// Función: RESPUESTA_RestaurarImagen
1728//
1729//      Descripción:
1730//              Respuesta del cliente al comando RestaurarImagen
1731//      Parámetros:
1732//              - socket_c: Socket del cliente que envió el mensaje
1733//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1734//      Devuelve:
1735//              true: Si el proceso es correcto
1736//              false: En caso de ocurrir algún error
1737// ________________________________________________________________________________________________________
1738//
1739static bool RESPUESTA_RestaurarImagen(TRAMA* ptrTrama, struct og_client *cli)
1740{
1741        bool res;
1742        char *iph, *ido, *idi, *dsk, *par, *ifs, *cfg;
1743        struct og_dbi *dbi;
1744
1745        dbi = og_dbi_open(&dbi_config);
1746        if (!dbi) {
1747                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
1748                       __func__, __LINE__);
1749                return false;
1750        }
1751
1752        iph = copiaParametro("iph",ptrTrama); // Toma dirección ip
1753        ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
1754
1755        if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) {
1756                og_dbi_close(dbi);
1757                liberaMemoria(iph);
1758                liberaMemoria(ido);
1759                syslog(LOG_ERR, "failed to register notification\n");
1760                return false;
1761        }
1762
1763        // Acciones posteriores
1764        idi = copiaParametro("idi",ptrTrama); // Toma identificador de la imagen
1765        dsk = copiaParametro("dsk",ptrTrama); // Número de disco
1766        par = copiaParametro("par",ptrTrama); // Número de partición
1767        ifs = copiaParametro("ifs",ptrTrama); // Identificador del perfil software contenido
1768        cfg = copiaParametro("cfg",ptrTrama); // Configuración de discos
1769        if(cfg){
1770                actualizaConfiguracion(dbi, cfg, atoi(ido)); // Actualiza la configuración del ordenador
1771                liberaMemoria(cfg);     
1772        }
1773        res=actualizaRestauracionImagen(dbi, idi, dsk, par, ido, ifs);
1774       
1775        liberaMemoria(iph);
1776        liberaMemoria(ido);
1777        liberaMemoria(idi);
1778        liberaMemoria(par);
1779        liberaMemoria(ifs);
1780        og_dbi_close(dbi);
1781
1782        if(!res)
1783                syslog(LOG_ERR, "Problem after restoring image\n");
1784
1785        return res;
1786}
1787// ________________________________________________________________________________________________________
1788//
1789// Función: RESPUESTA_RestaurarImagenBasica
1790//
1791//      Descripción:
1792//              Respuesta del cliente al comando RestaurarImagen
1793//      Parámetros:
1794//              - socket_c: Socket del cliente que envió el mensaje
1795//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1796//      Devuelve:
1797//              true: Si el proceso es correcto
1798//              false: En caso de ocurrir algún error
1799// ________________________________________________________________________________________________________
1800//
1801static bool RESPUESTA_RestaurarImagenBasica(TRAMA* ptrTrama, struct og_client *cli)
1802{
1803        return RESPUESTA_RestaurarImagen(ptrTrama, cli);
1804}
1805// ________________________________________________________________________________________________________
1806// Función: RESPUESTA_RestaurarSoftIncremental
1807//
1808//      Descripción:
1809//              Respuesta del cliente al comando RestaurarSoftIncremental
1810//      Parámetros:
1811//              - socket_c: Socket del cliente que envió el mensaje
1812//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1813//      Devuelve:
1814//              true: Si el proceso es correcto
1815//              false: En caso de ocurrir algún error
1816// ________________________________________________________________________________________________________
1817static bool RESPUESTA_RestaurarSoftIncremental(TRAMA* ptrTrama, struct og_client *cli)
1818{
1819        return RESPUESTA_RestaurarImagen(ptrTrama, cli);
1820}
1821// ________________________________________________________________________________________________________
1822// Función: actualizaRestauracionImagen
1823//
1824//      Descripción:
1825//              Esta función actualiza la base de datos con el resultado de la restauración de una imagen
1826//      Parámetros:
1827//              - db: Objeto base de datos (ya operativo)
1828//              - tbl: Objeto tabla
1829//              - idi: Identificador de la imagen
1830//              - dsk: Disco de donde se restauró
1831//              - par: Partición de donde se restauró
1832//              - ido: Identificador del cliente donde se restauró
1833//              - ifs: Identificador del perfil software contenido      en la imagen
1834//      Devuelve:
1835//              true: Si el proceso es correcto
1836//              false: En caso de ocurrir algún error
1837// ________________________________________________________________________________________________________
1838bool actualizaRestauracionImagen(struct og_dbi *dbi, char *idi,
1839                                 char *dsk, char *par, char *ido, char *ifs)
1840{
1841        const char *msglog;
1842        dbi_result result;
1843
1844        /* Actualizar los datos de la imagen */
1845        result = dbi_conn_queryf(dbi->conn,
1846                        "UPDATE ordenadores_particiones"
1847                        "   SET idimagen=%s, idperfilsoft=%s, fechadespliegue=NOW(),"
1848                        "       revision=(SELECT revision FROM imagenes WHERE idimagen=%s),"
1849                        "       idnombreso=IFNULL((SELECT idnombreso FROM perfilessoft WHERE idperfilsoft=%s),0)"
1850                        " WHERE idordenador=%s AND numdisk=%s AND numpar=%s", idi, ifs, idi, ifs, ido, dsk, par);
1851
1852        if (!result) {
1853                dbi_conn_error(dbi->conn, &msglog);
1854                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1855                       __func__, __LINE__, msglog);
1856                return false;
1857        }
1858        dbi_result_free(result);
1859
1860        return true;
1861}
1862// ________________________________________________________________________________________________________
1863// Función: RESPUESTA_EjecutarScript
1864//
1865//      Descripción:
1866//              Respuesta del cliente al comando EjecutarScript
1867//      Parámetros:
1868//              - socket_c: Socket del cliente que envió el mensaje
1869//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1870//      Devuelve:
1871//              true: Si el proceso es correcto
1872//              false: En caso de ocurrir algún error
1873// ________________________________________________________________________________________________________
1874static bool RESPUESTA_EjecutarScript(TRAMA* ptrTrama, struct og_client *cli)
1875{
1876        char *iph, *ido,*cfg;
1877        struct og_dbi *dbi;
1878        bool res = true;
1879
1880        dbi = og_dbi_open(&dbi_config);
1881        if (!dbi) {
1882                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
1883                       __func__, __LINE__);
1884                return false;
1885        }
1886
1887        iph = copiaParametro("iph",ptrTrama); // Toma dirección ip
1888        ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
1889
1890        if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) {
1891                og_dbi_close(dbi);
1892                liberaMemoria(iph);
1893                liberaMemoria(ido);
1894                syslog(LOG_ERR, "failed to register notification\n");
1895                return false;
1896        }
1897       
1898        cfg = copiaParametro("cfg",ptrTrama); // Toma configuración de particiones
1899        if(cfg){
1900                res = actualizaConfiguracion(dbi, cfg, atoi(ido)); // Actualiza la configuración del ordenador
1901                liberaMemoria(cfg);     
1902        }
1903
1904        liberaMemoria(iph);
1905        liberaMemoria(ido);
1906        og_dbi_close(dbi);
1907
1908        if (!res)
1909                syslog(LOG_ERR, "Problem updating client configuration\n");
1910
1911        return res;
1912}
1913// ________________________________________________________________________________________________________
1914// Función: RESPUESTA_InventarioHardware
1915//
1916//      Descripción:
1917//              Respuesta del cliente al comando InventarioHardware
1918//      Parámetros:
1919//              - socket_c: Socket del cliente que envió el mensaje
1920//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1921//      Devuelve:
1922//              true: Si el proceso es correcto
1923//              false: En caso de ocurrir algún error
1924// ________________________________________________________________________________________________________
1925static bool RESPUESTA_InventarioHardware(TRAMA* ptrTrama, struct og_client *cli)
1926{
1927        bool res;
1928        char *iph, *ido, *idc, *npc, *hrd, *buffer;
1929        struct og_dbi *dbi;
1930
1931        dbi = og_dbi_open(&dbi_config);
1932        if (!dbi) {
1933                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
1934                       __func__, __LINE__);
1935                return false;
1936        }
1937
1938        iph = copiaParametro("iph",ptrTrama); // Toma dirección ip del cliente
1939        ido = copiaParametro("ido",ptrTrama); // Toma identificador del cliente
1940
1941        if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) {
1942                og_dbi_close(dbi);
1943                liberaMemoria(iph);
1944                liberaMemoria(ido);
1945                syslog(LOG_ERR, "failed to register notification\n");
1946                return false;
1947        }
1948        // Lee archivo de inventario enviado anteriormente
1949        hrd = copiaParametro("hrd",ptrTrama);
1950        buffer = rTrim(leeArchivo(hrd));
1951       
1952        npc = copiaParametro("npc",ptrTrama);
1953        idc = copiaParametro("idc",ptrTrama); // Toma identificador del Centro
1954       
1955        if (buffer)
1956                res=actualizaHardware(dbi, buffer, ido, npc, idc);
1957        else
1958                res = false;
1959
1960        liberaMemoria(iph);
1961        liberaMemoria(ido);                     
1962        liberaMemoria(npc);                     
1963        liberaMemoria(idc);             
1964        liberaMemoria(buffer);         
1965        og_dbi_close(dbi);
1966
1967        if (!res)
1968                syslog(LOG_ERR, "Problem updating client configuration\n");
1969
1970        return res;
1971}
1972// ________________________________________________________________________________________________________
1973// Función: actualizaHardware
1974//
1975//              Descripción:
1976//                      Actualiza la base de datos con la configuracion hardware del cliente
1977//              Parámetros:
1978//                      - db: Objeto base de datos (ya operativo)
1979//                      - tbl: Objeto tabla
1980//                      - hrd: cadena con el inventario hardware
1981//                      - ido: Identificador del ordenador
1982//                      - npc: Nombre del ordenador
1983//                      - idc: Identificador del centro o Unidad organizativa
1984// ________________________________________________________________________________________________________
1985//
1986bool actualizaHardware(struct og_dbi *dbi, char *hrd, char *ido, char *npc,
1987                       char *idc)
1988{
1989        const char *msglog;
1990        int idtipohardware, idperfilhard;
1991        int lon, i, j, aux;
1992        bool retval;
1993        char *whard;
1994        int tbidhardware[MAXHARDWARE];
1995        char *tbHardware[MAXHARDWARE],*dualHardware[2], strInt[LONINT], *idhardwares;
1996        dbi_result result;
1997
1998        /* Toma Centro (Unidad Organizativa) */
1999        result = dbi_conn_queryf(dbi->conn,
2000                                 "SELECT idperfilhard FROM ordenadores WHERE idordenador=%s",
2001                                 ido);
2002        if (!result) {
2003                dbi_conn_error(dbi->conn, &msglog);
2004                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2005                       __func__, __LINE__, msglog);
2006                return false;
2007        }
2008        if (!dbi_result_next_row(result)) {
2009                syslog(LOG_ERR, "client does not exist in database (%s:%d)\n",
2010                       __func__, __LINE__);
2011                dbi_result_free(result);
2012                return false;
2013        }
2014        idperfilhard = dbi_result_get_uint(result, "idperfilhard");
2015        dbi_result_free(result);
2016
2017        whard=escaparCadena(hrd); // Codificar comillas simples
2018        if(!whard)
2019                return false;
2020        /* Recorre componentes hardware*/
2021        lon = splitCadena(tbHardware, whard, '\n');
2022        if (lon > MAXHARDWARE)
2023                lon = MAXHARDWARE; // Limita el número de componentes hardware
2024        /*
2025         for (i=0;i<lon;i++){
2026         sprintf(msglog,"Linea de inventario: %s",tbHardware[i]);
2027         RegistraLog(msglog,false);
2028         }
2029         */
2030        for (i = 0; i < lon; i++) {
2031                splitCadena(dualHardware, rTrim(tbHardware[i]), '=');
2032                //sprintf(msglog,"nemonico: %s",dualHardware[0]);
2033                //RegistraLog(msglog,false);
2034                //sprintf(msglog,"valor: %s",dualHardware[1]);
2035                //RegistraLog(msglog,false);
2036                result = dbi_conn_queryf(dbi->conn,
2037                                         "SELECT idtipohardware,descripcion FROM tipohardwares WHERE nemonico='%s'",
2038                                         dualHardware[0]);
2039                if (!result) {
2040                        dbi_conn_error(dbi->conn, &msglog);
2041                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2042                               __func__, __LINE__, msglog);
2043                        return false;
2044                }
2045                if (!dbi_result_next_row(result)) { //  Tipo de Hardware NO existente
2046                        dbi_result_free(result);
2047                        return false;
2048                } else { //  Tipo de Hardware Existe
2049                        idtipohardware = dbi_result_get_uint(result, "idtipohardware");
2050                        dbi_result_free(result);
2051
2052                        result = dbi_conn_queryf(dbi->conn,
2053                                                 "SELECT idhardware FROM hardwares WHERE idtipohardware=%d AND descripcion='%s'",
2054                                                 idtipohardware, dualHardware[1]);
2055
2056                        if (!result) {
2057                                dbi_conn_error(dbi->conn, &msglog);
2058                                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2059                                       __func__, __LINE__, msglog);
2060                                return false;
2061                        }
2062
2063                        if (!dbi_result_next_row(result)) { //  Hardware NO existente
2064                                dbi_result_free(result);
2065                                result = dbi_conn_queryf(dbi->conn,
2066                                                        "INSERT hardwares (idtipohardware,descripcion,idcentro,grupoid) "
2067                                                        " VALUES(%d,'%s',%s,0)", idtipohardware,
2068                                                dualHardware[1], idc);
2069                                if (!result) {
2070                                        dbi_conn_error(dbi->conn, &msglog);
2071                                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2072                                               __func__, __LINE__, msglog);
2073                                        return false;
2074                                }
2075
2076                                // Recupera el identificador del hardware
2077                                tbidhardware[i] = dbi_conn_sequence_last(dbi->conn, NULL);
2078                        } else {
2079                                tbidhardware[i] = dbi_result_get_uint(result, "idhardware");
2080                        }
2081                        dbi_result_free(result);
2082                }
2083        }
2084        // Ordena tabla de identificadores para cosultar si existe un pefil con esas especificaciones
2085
2086        for (i = 0; i < lon - 1; i++) {
2087                for (j = i + 1; j < lon; j++) {
2088                        if (tbidhardware[i] > tbidhardware[j]) {
2089                                aux = tbidhardware[i];
2090                                tbidhardware[i] = tbidhardware[j];
2091                                tbidhardware[j] = aux;
2092                        }
2093                }
2094        }
2095        /* Crea cadena de identificadores de componentes hardware separados por coma */
2096        sprintf(strInt, "%d", tbidhardware[lon - 1]); // Pasa a cadena el último identificador que es de mayor longitud
2097        aux = strlen(strInt); // Calcula longitud de cadena para reservar espacio a todos los perfiles
2098        idhardwares = reservaMemoria(sizeof(aux) * lon + lon);
2099        if (idhardwares == NULL) {
2100                syslog(LOG_ERR, "%s:%d OOM\n", __FILE__, __LINE__);
2101                return false;
2102        }
2103        aux = sprintf(idhardwares, "%d", tbidhardware[0]);
2104        for (i = 1; i < lon; i++)
2105                aux += sprintf(idhardwares + aux, ",%d", tbidhardware[i]);
2106
2107        if (!cuestionPerfilHardware(dbi, idc, ido, idperfilhard, idhardwares,
2108                        npc, tbidhardware, lon)) {
2109                syslog(LOG_ERR, "Problem updating client hardware\n");
2110                retval=false;
2111        }
2112        else {
2113                retval=true;
2114        }
2115        liberaMemoria(whard);
2116        liberaMemoria(idhardwares);
2117        return (retval);
2118}
2119// ________________________________________________________________________________________________________
2120// Función: cuestionPerfilHardware
2121//
2122//              Descripción:
2123//                      Comprueba existencia de perfil hardware y actualización de éste para el ordenador
2124//              Parámetros:
2125//                      - db: Objeto base de datos (ya operativo)
2126//                      - tbl: Objeto tabla
2127//                      - idc: Identificador de la Unidad organizativa donde se encuentra el cliente
2128//                      - ido: Identificador del ordenador
2129//                      - tbidhardware: Identificador del tipo de hardware
2130//                      - con: Número de componentes detectados para configurar un el perfil hardware
2131//                      - npc: Nombre del cliente
2132// ________________________________________________________________________________________________________
2133bool cuestionPerfilHardware(struct og_dbi *dbi, char *idc, char *ido,
2134                int idperfilhardware, char *idhardwares, char *npc, int *tbidhardware,
2135                int lon)
2136{
2137        const char *msglog;
2138        dbi_result result;
2139        int i;
2140        int nwidperfilhard;
2141
2142        // Busca perfil hard del ordenador que contenga todos los componentes hardware encontrados
2143        result = dbi_conn_queryf(dbi->conn,
2144                "SELECT idperfilhard FROM"
2145                " (SELECT perfileshard_hardwares.idperfilhard as idperfilhard,"
2146                "       group_concat(cast(perfileshard_hardwares.idhardware AS char( 11) )"
2147                "       ORDER BY perfileshard_hardwares.idhardware SEPARATOR ',' ) AS idhardwares"
2148                " FROM  perfileshard_hardwares"
2149                " GROUP BY perfileshard_hardwares.idperfilhard) AS temp"
2150                " WHERE idhardwares LIKE '%s'", idhardwares);
2151
2152        if (!result) {
2153                dbi_conn_error(dbi->conn, &msglog);
2154                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2155                       __func__, __LINE__, msglog);
2156                return false;
2157        }
2158        if (!dbi_result_next_row(result)) {
2159                // No existe un perfil hardware con esos componentes de componentes hardware, lo crea
2160                dbi_result_free(result);
2161                result = dbi_conn_queryf(dbi->conn,
2162                                "INSERT perfileshard  (descripcion,idcentro,grupoid)"
2163                                " VALUES('Perfil hardware (%s) ',%s,0)", npc, idc);
2164                if (!result) {
2165                        dbi_conn_error(dbi->conn, &msglog);
2166                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2167                               __func__, __LINE__, msglog);
2168                        return false;
2169                }
2170                dbi_result_free(result);
2171
2172                // Recupera el identificador del nuevo perfil hardware
2173                nwidperfilhard = dbi_conn_sequence_last(dbi->conn, NULL);
2174
2175                // Crea la relación entre perfiles y componenetes hardware
2176                for (i = 0; i < lon; i++) {
2177                        result = dbi_conn_queryf(dbi->conn,
2178                                        "INSERT perfileshard_hardwares  (idperfilhard,idhardware)"
2179                                                " VALUES(%d,%d)", nwidperfilhard, tbidhardware[i]);
2180                        if (!result) {
2181                                dbi_conn_error(dbi->conn, &msglog);
2182                                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2183                                       __func__, __LINE__, msglog);
2184                                return false;
2185                        }
2186                        dbi_result_free(result);
2187                }
2188        } else { // Existe un perfil con todos esos componentes
2189                nwidperfilhard = dbi_result_get_uint(result, "idperfilhard");
2190                dbi_result_free(result);
2191        }
2192        if (idperfilhardware != nwidperfilhard) { // No coinciden los perfiles
2193                // Actualiza el identificador del perfil hardware del ordenador
2194                result = dbi_conn_queryf(dbi->conn,
2195                        "UPDATE ordenadores SET idperfilhard=%d"
2196                        " WHERE idordenador=%s", nwidperfilhard, ido);
2197                if (!result) {
2198                        dbi_conn_error(dbi->conn, &msglog);
2199                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2200                               __func__, __LINE__, msglog);
2201                        return false;
2202                }
2203                dbi_result_free(result);
2204        }
2205        /* Eliminar Relación de hardwares con Perfiles hardware que quedan húerfanos */
2206        result = dbi_conn_queryf(dbi->conn,
2207                "DELETE FROM perfileshard_hardwares WHERE idperfilhard IN "
2208                " (SELECT idperfilhard FROM perfileshard WHERE idperfilhard NOT IN"
2209                " (SELECT DISTINCT idperfilhard from ordenadores))");
2210        if (!result) {
2211                dbi_conn_error(dbi->conn, &msglog);
2212                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2213                       __func__, __LINE__, msglog);
2214                return false;
2215        }
2216        dbi_result_free(result);
2217
2218        /* Eliminar Perfiles hardware que quedan húerfanos */
2219        result = dbi_conn_queryf(dbi->conn,
2220                        "DELETE FROM perfileshard WHERE idperfilhard NOT IN"
2221                        " (SELECT DISTINCT idperfilhard FROM ordenadores)");
2222        if (!result) {
2223                dbi_conn_error(dbi->conn, &msglog);
2224                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2225                       __func__, __LINE__, msglog);
2226                return false;
2227        }
2228        dbi_result_free(result);
2229
2230        /* Eliminar Relación de hardwares con Perfiles hardware que quedan húerfanos */
2231        result = dbi_conn_queryf(dbi->conn,
2232                        "DELETE FROM perfileshard_hardwares WHERE idperfilhard NOT IN"
2233                        " (SELECT idperfilhard FROM perfileshard)");
2234        if (!result) {
2235                dbi_conn_error(dbi->conn, &msglog);
2236                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2237                       __func__, __LINE__, msglog);
2238                return false;
2239        }
2240        dbi_result_free(result);
2241
2242        return true;
2243}
2244// ________________________________________________________________________________________________________
2245// Función: RESPUESTA_InventarioSoftware
2246//
2247//      Descripción:
2248//              Respuesta del cliente al comando InventarioSoftware
2249//      Parámetros:
2250//              - socket_c: Socket del cliente que envió el mensaje
2251//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
2252//      Devuelve:
2253//              true: Si el proceso es correcto
2254//              false: En caso de ocurrir algún error
2255// ________________________________________________________________________________________________________
2256static bool RESPUESTA_InventarioSoftware(TRAMA* ptrTrama, struct og_client *cli)
2257{
2258        bool res;
2259        char *iph, *ido, *npc, *idc, *par, *sft, *buffer;
2260        struct og_dbi *dbi;
2261
2262        dbi = og_dbi_open(&dbi_config);
2263        if (!dbi) {
2264                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
2265                       __func__, __LINE__);
2266                return false;
2267        }
2268
2269        iph = copiaParametro("iph",ptrTrama); // Toma dirección ip
2270        ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
2271
2272        if (!respuestaEstandar(ptrTrama, iph, ido, dbi)) {
2273                og_dbi_close(dbi);
2274                liberaMemoria(iph);
2275                liberaMemoria(ido);
2276                syslog(LOG_ERR, "failed to register notification\n");
2277                return false;
2278        }
2279
2280        npc = copiaParametro("npc",ptrTrama);
2281        idc = copiaParametro("idc",ptrTrama); // Toma identificador del Centro 
2282        par = copiaParametro("par",ptrTrama);
2283        sft = copiaParametro("sft",ptrTrama);
2284
2285        buffer = rTrim(leeArchivo(sft));
2286        if (buffer)
2287                res=actualizaSoftware(dbi, buffer, par, ido, npc, idc);
2288        else
2289                res = false;
2290
2291        liberaMemoria(iph);
2292        liberaMemoria(ido);     
2293        liberaMemoria(npc);     
2294        liberaMemoria(idc);     
2295        liberaMemoria(par);     
2296        liberaMemoria(sft);     
2297        og_dbi_close(dbi);
2298
2299        if (!res)
2300                syslog(LOG_ERR, "cannot update software\n");
2301
2302        return res;
2303}
2304// ________________________________________________________________________________________________________
2305// Función: actualizaSoftware
2306//
2307//      Descripción:
2308//              Actualiza la base de datos con la configuración software del cliente
2309//      Parámetros:
2310//              - db: Objeto base de datos (ya operativo)
2311//              - tbl: Objeto tabla
2312//              - sft: cadena con el inventario software
2313//              - par: Número de la partición
2314//              - ido: Identificador del ordenador del cliente en la tabla
2315//              - npc: Nombre del ordenador
2316//              - idc: Identificador del centro o Unidad organizativa
2317//      Devuelve:
2318//              true: Si el proceso es correcto
2319//              false: En caso de ocurrir algún error
2320//
2321//      Versión 1.1.0: Se incluye el sistema operativo. Autora: Irina Gómez - ETSII Universidad Sevilla
2322// ________________________________________________________________________________________________________
2323bool actualizaSoftware(struct og_dbi *dbi, char *sft, char *par,char *ido,
2324                       char *npc, char *idc)
2325{
2326        int i, j, lon, aux, idperfilsoft, idnombreso;
2327        bool retval;
2328        char *wsft;
2329        int tbidsoftware[MAXSOFTWARE];
2330        char *tbSoftware[MAXSOFTWARE], strInt[LONINT], *idsoftwares;
2331        const char *msglog;
2332        dbi_result result;
2333
2334        /* Toma Centro (Unidad Organizativa) y perfil software */
2335        result = dbi_conn_queryf(dbi->conn,
2336                "SELECT idperfilsoft,numpar"
2337                " FROM ordenadores_particiones"
2338                " WHERE idordenador=%s", ido);
2339        if (!result) {
2340                dbi_conn_error(dbi->conn, &msglog);
2341                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2342                       __func__, __LINE__, msglog);
2343                return false;
2344        }
2345        idperfilsoft = 0; // Por defecto se supone que el ordenador no tiene aún detectado el perfil software
2346        while (dbi_result_next_row(result)) {
2347                aux = dbi_result_get_uint(result, "numpar");
2348                if (aux == atoi(par)) { // Se encuentra la partición
2349                        idperfilsoft = dbi_result_get_uint(result, "idperfilsoft");
2350                        break;
2351                }
2352        }
2353        dbi_result_free(result);
2354        wsft=escaparCadena(sft); // Codificar comillas simples
2355        if(!wsft)
2356                return false;
2357
2358        /* Recorre componentes software*/
2359        lon = splitCadena(tbSoftware, wsft, '\n');
2360
2361        if (lon == 0)
2362                return true; // No hay lineas que procesar
2363        if (lon > MAXSOFTWARE)
2364                lon = MAXSOFTWARE; // Limita el número de componentes software
2365
2366        idnombreso = 0;
2367        for (i = 0; i < lon; i++) {
2368                // Primera línea es el sistema operativo: se obtiene identificador
2369                if (i == 0) {
2370                        idnombreso = checkDato(dbi, rTrim(tbSoftware[i]), "nombresos", "nombreso", "idnombreso");
2371                        continue;
2372                }
2373
2374                result = dbi_conn_queryf(dbi->conn,
2375                                "SELECT idsoftware FROM softwares WHERE descripcion ='%s'",
2376                                rTrim(tbSoftware[i]));
2377                if (!result) {
2378                        dbi_conn_error(dbi->conn, &msglog);
2379                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2380                               __func__, __LINE__, msglog);
2381                        return false;
2382                }
2383
2384                if (!dbi_result_next_row(result)) {
2385                        dbi_result_free(result);
2386                        result = dbi_conn_queryf(dbi->conn,
2387                                                "INSERT INTO softwares (idtiposoftware,descripcion,idcentro,grupoid)"
2388                                                " VALUES(2,'%s',%s,0)", tbSoftware[i], idc);
2389                        if (!result) { // Error al insertar
2390                                dbi_conn_error(dbi->conn, &msglog);
2391                                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2392                                       __func__, __LINE__, msglog);
2393                                return false;
2394                        }
2395
2396                        // Recupera el identificador del software
2397                        tbidsoftware[i] = dbi_conn_sequence_last(dbi->conn, NULL);
2398                } else {
2399                        tbidsoftware[i] = dbi_result_get_uint(result, "idsoftware");
2400                }
2401                dbi_result_free(result);
2402        }
2403
2404        // Ordena tabla de identificadores para cosultar si existe un pefil con esas especificaciones
2405
2406        for (i = 0; i < lon - 1; i++) {
2407                for (j = i + 1; j < lon; j++) {
2408                        if (tbidsoftware[i] > tbidsoftware[j]) {
2409                                aux = tbidsoftware[i];
2410                                tbidsoftware[i] = tbidsoftware[j];
2411                                tbidsoftware[j] = aux;
2412                        }
2413                }
2414        }
2415        /* Crea cadena de identificadores de componentes software separados por coma */
2416        sprintf(strInt, "%d", tbidsoftware[lon - 1]); // Pasa a cadena el último identificador que es de mayor longitud
2417        aux = strlen(strInt); // Calcula longitud de cadena para reservar espacio a todos los perfiles
2418        idsoftwares = reservaMemoria((sizeof(aux)+1) * lon + lon);
2419        if (idsoftwares == NULL) {
2420                syslog(LOG_ERR, "%s:%d OOM\n", __FILE__, __LINE__);
2421                return false;
2422        }
2423        aux = sprintf(idsoftwares, "%d", tbidsoftware[0]);
2424        for (i = 1; i < lon; i++)
2425                aux += sprintf(idsoftwares + aux, ",%d", tbidsoftware[i]);
2426
2427        // Comprueba existencia de perfil software y actualización de éste para el ordenador
2428        if (!cuestionPerfilSoftware(dbi, idc, ido, idperfilsoft, idnombreso, idsoftwares,
2429                        npc, par, tbidsoftware, lon)) {
2430                syslog(LOG_ERR, "cannot update software\n");
2431                og_info((char *)msglog);
2432                retval=false;
2433        }
2434        else {
2435                retval=true;
2436        }
2437        liberaMemoria(wsft);
2438        liberaMemoria(idsoftwares);
2439        return (retval);
2440}
2441// ________________________________________________________________________________________________________
2442// Función: CuestionPerfilSoftware
2443//
2444//      Parámetros:
2445//              - db: Objeto base de datos (ya operativo)
2446//              - tbl: Objeto tabla
2447//              - idcentro: Identificador del centro en la tabla
2448//              - ido: Identificador del ordenador del cliente en la tabla
2449//              - idnombreso: Identificador del sistema operativo
2450//              - idsoftwares: Cadena con los identificadores de componentes software separados por comas
2451//              - npc: Nombre del ordenador del cliente
2452//              - particion: Número de la partición
2453//              - tbidsoftware: Array con los identificadores de componentes software
2454//              - lon: Número de componentes
2455//      Devuelve:
2456//              true: Si el proceso es correcto
2457//              false: En caso de ocurrir algún error
2458//
2459//      Versión 1.1.0: Se incluye el sistema operativo. Autora: Irina Gómez - ETSII Universidad Sevilla
2460//_________________________________________________________________________________________________________
2461bool cuestionPerfilSoftware(struct og_dbi *dbi, char *idc, char *ido,
2462                            int idperfilsoftware, int idnombreso,
2463                            char *idsoftwares, char *npc, char *par,
2464                            int *tbidsoftware, int lon)
2465{
2466        int i, nwidperfilsoft;
2467        const char *msglog;
2468        dbi_result result;
2469
2470        // Busca perfil soft del ordenador que contenga todos los componentes software encontrados
2471        result = dbi_conn_queryf(dbi->conn,
2472                "SELECT idperfilsoft FROM"
2473                " (SELECT perfilessoft_softwares.idperfilsoft as idperfilsoft,"
2474                "       group_concat(cast(perfilessoft_softwares.idsoftware AS char( 11) )"
2475                "       ORDER BY perfilessoft_softwares.idsoftware SEPARATOR ',' ) AS idsoftwares"
2476                " FROM  perfilessoft_softwares"
2477                " GROUP BY perfilessoft_softwares.idperfilsoft) AS temp"
2478                " WHERE idsoftwares LIKE '%s'", idsoftwares);
2479
2480        if (!result) {
2481                dbi_conn_error(dbi->conn, &msglog);
2482                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2483                       __func__, __LINE__, msglog);
2484                return false;
2485        }
2486        if (!dbi_result_next_row(result)) { // No existe un perfil software con esos componentes de componentes software, lo crea
2487                dbi_result_free(result);
2488                result = dbi_conn_queryf(dbi->conn,
2489                                "INSERT perfilessoft  (descripcion, idcentro, grupoid, idnombreso)"
2490                                " VALUES('Perfil Software (%s, Part:%s) ',%s,0,%i)", npc, par, idc,idnombreso);
2491                if (!result) {
2492                        dbi_conn_error(dbi->conn, &msglog);
2493                        og_info((char *)msglog);
2494                        return false;
2495                }
2496
2497                dbi_result_free(result);
2498                // Recupera el identificador del nuevo perfil software
2499                nwidperfilsoft = dbi_conn_sequence_last(dbi->conn, NULL);
2500
2501                // Crea la relación entre perfiles y componenetes software
2502                for (i = 0; i < lon; i++) {
2503                        result = dbi_conn_queryf(dbi->conn,
2504                                                "INSERT perfilessoft_softwares (idperfilsoft,idsoftware)"
2505                                                " VALUES(%d,%d)", nwidperfilsoft, tbidsoftware[i]);
2506                        if (!result) {
2507                                dbi_conn_error(dbi->conn, &msglog);
2508                                og_info((char *)msglog);
2509                                return false;
2510                        }
2511                        dbi_result_free(result);
2512                }
2513        } else { // Existe un perfil con todos esos componentes
2514                nwidperfilsoft = dbi_result_get_uint(result, "idperfilsoft");
2515                dbi_result_free(result);
2516        }
2517
2518        if (idperfilsoftware != nwidperfilsoft) { // No coinciden los perfiles
2519                // Actualiza el identificador del perfil software del ordenador
2520                result = dbi_conn_queryf(dbi->conn,
2521                                "UPDATE ordenadores_particiones SET idperfilsoft=%d,idimagen=0"
2522                                " WHERE idordenador=%s AND numpar=%s", nwidperfilsoft, ido, par);
2523                if (!result) { // Error al insertar
2524                        dbi_conn_error(dbi->conn, &msglog);
2525                        og_info((char *)msglog);
2526                        return false;
2527                }
2528                dbi_result_free(result);
2529        }
2530
2531        /* DEPURACIÓN DE PERFILES SOFTWARE */
2532
2533         /* Eliminar Relación de softwares con Perfiles software que quedan húerfanos */
2534        result = dbi_conn_queryf(dbi->conn,
2535                "DELETE FROM perfilessoft_softwares WHERE idperfilsoft IN "\
2536                " (SELECT idperfilsoft FROM perfilessoft WHERE idperfilsoft NOT IN"\
2537                " (SELECT DISTINCT idperfilsoft from ordenadores_particiones) AND idperfilsoft NOT IN"\
2538                " (SELECT DISTINCT idperfilsoft from imagenes))");
2539        if (!result) {
2540                dbi_conn_error(dbi->conn, &msglog);
2541                og_info((char *)msglog);
2542                return false;
2543        }
2544        dbi_result_free(result),
2545        /* Eliminar Perfiles software que quedan húerfanos */
2546        result = dbi_conn_queryf(dbi->conn,
2547                "DELETE FROM perfilessoft WHERE idperfilsoft NOT IN"
2548                " (SELECT DISTINCT idperfilsoft from ordenadores_particiones)"\
2549                " AND  idperfilsoft NOT IN"\
2550                " (SELECT DISTINCT idperfilsoft from imagenes)");
2551        if (!result) {
2552                dbi_conn_error(dbi->conn, &msglog);
2553                og_info((char *)msglog);
2554                return false;
2555        }
2556        dbi_result_free(result),
2557
2558        /* Eliminar Relación de softwares con Perfiles software que quedan húerfanos */
2559        result = dbi_conn_queryf(dbi->conn,
2560                        "DELETE FROM perfilessoft_softwares WHERE idperfilsoft NOT IN"
2561                        " (SELECT idperfilsoft from perfilessoft)");
2562        if (!result) {
2563                dbi_conn_error(dbi->conn, &msglog);
2564                og_info((char *)msglog);
2565                return false;
2566        }
2567        dbi_result_free(result);
2568
2569        return true;
2570}
2571// ________________________________________________________________________________________________________
2572// Función: enviaArchivo
2573//
2574//      Descripción:
2575//              Envia un archivo por la red, por bloques
2576//      Parámetros:
2577//              - socket_c: Socket del cliente que envió el mensaje
2578//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
2579//      Devuelve:
2580//              true: Si el proceso es correcto
2581//              false: En caso de ocurrir algún error
2582// ________________________________________________________________________________________________________
2583static bool enviaArchivo(TRAMA *ptrTrama, struct og_client *cli)
2584{
2585        int socket_c = og_client_socket(cli);
2586        char *nfl;
2587
2588        // Toma parámetros
2589        nfl = copiaParametro("nfl",ptrTrama); // Toma nombre completo del archivo
2590        if (!sendArchivo(&socket_c, nfl)) {
2591                liberaMemoria(nfl);
2592                syslog(LOG_ERR, "Problem sending file\n");
2593                return false;
2594        }
2595        liberaMemoria(nfl);
2596        return true;
2597}
2598// ________________________________________________________________________________________________________
2599// Función: enviaArchivo
2600//
2601//      Descripción:
2602//              Envia un archivo por la red, por bloques
2603//      Parámetros:
2604//              - socket_c: Socket del cliente que envió el mensaje
2605//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
2606//      Devuelve:
2607//              true: Si el proceso es correcto
2608//              false: En caso de ocurrir algún error
2609// ________________________________________________________________________________________________________
2610static bool recibeArchivo(TRAMA *ptrTrama, struct og_client *cli)
2611{
2612        int socket_c = og_client_socket(cli);
2613        char *nfl;
2614
2615        // Toma parámetros
2616        nfl = copiaParametro("nfl",ptrTrama); // Toma nombre completo del archivo
2617        ptrTrama->tipo = MSG_NOTIFICACION;
2618        enviaFlag(&socket_c, ptrTrama);
2619        if (!recArchivo(&socket_c, nfl)) {
2620                liberaMemoria(nfl);
2621                syslog(LOG_ERR, "Problem receiving file\n");
2622                return false;
2623        }
2624        liberaMemoria(nfl);
2625        return true;
2626}
2627// ________________________________________________________________________________________________________
2628// Función: envioProgramacion
2629//
2630//      Descripción:
2631//              Envia un comando de actualización a todos los ordenadores que han sido programados con
2632//              alguna acción para que entren en el bucle de comandos pendientes y las ejecuten
2633//      Parámetros:
2634//              - socket_c: Socket del cliente que envió el mensaje
2635//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
2636//      Devuelve:
2637//              true: Si el proceso es correcto
2638//              false: En caso de ocurrir algún error
2639// ________________________________________________________________________________________________________
2640static bool envioProgramacion(TRAMA *ptrTrama, struct og_client *cli)
2641{
2642        char *ptrIP[MAXIMOS_CLIENTES],*ptrMacs[MAXIMOS_CLIENTES],*ptrNetmasks[MAXIMOS_CLIENTES];
2643        char *idp, *iph, *mac, *netmask;
2644        int idx,idcomando,lon;
2645        const char *msglog;
2646        struct og_dbi *dbi;
2647        dbi_result result;
2648
2649        dbi = og_dbi_open(&dbi_config);
2650        if (!dbi) {
2651                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
2652                       __func__, __LINE__);
2653                return false;
2654        }
2655
2656        idp = copiaParametro("idp",ptrTrama); // Toma identificador de la programación de la tabla acciones
2657
2658        result = dbi_conn_queryf(dbi->conn,
2659                        "SELECT ordenadores.ip,ordenadores.mac,aulas.netmask, acciones.idcomando FROM acciones "\
2660                        " INNER JOIN ordenadores ON ordenadores.ip=acciones.ip"\
2661                        " INNER JOIN aulas ON ordenadores.idaula=aulas.idaula "\
2662                        " WHERE acciones.idprogramacion=%s",idp);
2663
2664        liberaMemoria(idp);
2665
2666        if (!result) {
2667                dbi_conn_error(dbi->conn, &msglog);
2668                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2669                       __func__, __LINE__, msglog);
2670                og_dbi_close(dbi);
2671                return false;
2672        }
2673
2674        /* Prepara la trama de actualizacion */
2675
2676        initParametros(ptrTrama,0);
2677        ptrTrama->tipo=MSG_COMANDO;
2678        sprintf(ptrTrama->parametros, "nfn=Actualizar\r");
2679
2680        while (dbi_result_next_row(result)) {
2681                iph = (char *)dbi_result_get_string(result, "ip");
2682                idcomando = dbi_result_get_uint(result, "idcomando");
2683
2684                if (idcomando == 1){ // Arrancar
2685                        mac = (char *)dbi_result_get_string(result, "mac");
2686                        netmask = (char *)dbi_result_get_string(result, "netmask");
2687                        lon = splitCadena(ptrIP, iph, ';');
2688                        lon = splitCadena(ptrMacs, mac, ';');
2689                        lon = splitCadena(ptrNetmasks, netmask, ';');
2690
2691                        // Se manda por broadcast y por unicast
2692                        if (!Levanta(ptrIP, ptrMacs, ptrNetmasks, lon, (char*)"1")) {
2693                                dbi_result_free(result);
2694                                og_dbi_close(dbi);
2695                                return false;
2696                        }
2697
2698                        if (!Levanta(ptrIP, ptrMacs, ptrNetmasks, lon, (char*)"2")) {
2699                                dbi_result_free(result);
2700                                og_dbi_close(dbi);
2701                                return false;
2702                        }
2703
2704                }
2705                if (clienteDisponible(iph, &idx)) { // Si el cliente puede recibir comandos
2706                        int sock = tbsockets[idx].cli ? tbsockets[idx].cli->io.fd : -1;
2707
2708                        strcpy(tbsockets[idx].estado, CLIENTE_OCUPADO); // Actualiza el estado del cliente
2709                        if (sock >= 0 && !mandaTrama(&sock, ptrTrama)) {
2710                                syslog(LOG_ERR, "failed to send response: %s\n",
2711                                       strerror(errno));
2712                        }
2713                        //close(tbsockets[idx].sock); // Cierra el socket del cliente hasta nueva disponibilidad
2714                }
2715        }
2716        dbi_result_free(result);
2717        og_dbi_close(dbi);
2718
2719        return true; // No existen registros
2720}
2721
2722// This object stores function handler for messages
2723static struct {
2724        const char *nf; // Nombre de la función
2725        bool (*fcn)(TRAMA *, struct og_client *cli);
2726} tbfuncionesServer[] = {
2727        { "InclusionCliente",                   InclusionCliente,       },
2728        { "InclusionClienteWinLnx",             InclusionClienteWinLnx, },
2729        { "AutoexecCliente",                    AutoexecCliente,        },
2730        { "ComandosPendientes",                 ComandosPendientes,     },
2731        { "DisponibilidadComandos",             DisponibilidadComandos, },
2732        { "RESPUESTA_Arrancar",                 RESPUESTA_Arrancar,     },
2733        { "RESPUESTA_Apagar",                   RESPUESTA_Apagar,       },
2734        { "RESPUESTA_Reiniciar",                RESPUESTA_Apagar,       },
2735        { "RESPUESTA_IniciarSesion",            RESPUESTA_Apagar, },
2736        { "RESPUESTA_CrearImagen",              RESPUESTA_CrearImagen,  },
2737        { "RESPUESTA_CrearImagenBasica",        RESPUESTA_CrearImagenBasica, },
2738        { "RESPUESTA_CrearSoftIncremental",     RESPUESTA_CrearSoftIncremental, },
2739        { "RESPUESTA_RestaurarImagen",          RESPUESTA_RestaurarImagen },
2740        { "RESPUESTA_RestaurarImagenBasica",    RESPUESTA_RestaurarImagenBasica, },
2741        { "RESPUESTA_RestaurarSoftIncremental", RESPUESTA_RestaurarSoftIncremental, },
2742        { "RESPUESTA_Configurar",               RESPUESTA_EjecutarScript, },
2743        { "RESPUESTA_EjecutarScript",           RESPUESTA_EjecutarScript, },
2744        { "RESPUESTA_InventarioHardware",       RESPUESTA_InventarioHardware, },
2745        { "RESPUESTA_InventarioSoftware",       RESPUESTA_InventarioSoftware, },
2746        { "enviaArchivo",                       enviaArchivo,           },
2747        { "recibeArchivo",                      recibeArchivo,          },
2748        { "envioProgramacion",                  envioProgramacion,      },
2749        { NULL,                                 NULL,                   },
2750};
2751
2752// ________________________________________________________________________________________________________
2753// Función: gestionaTrama
2754//
2755//              Descripción:
2756//                      Procesa las tramas recibidas .
2757//              Parametros:
2758//                      - s : Socket usado para comunicaciones
2759//      Devuelve:
2760//              true: Si el proceso es correcto
2761//              false: En caso de ocurrir algún error
2762// ________________________________________________________________________________________________________
2763static void gestionaTrama(TRAMA *ptrTrama, struct og_client *cli)
2764{
2765        int i, res;
2766        char *nfn;
2767
2768        if (ptrTrama){
2769                INTROaFINCAD(ptrTrama);
2770                nfn = copiaParametro("nfn",ptrTrama); // Toma nombre de la función
2771
2772                for (i = 0; tbfuncionesServer[i].fcn; i++) {
2773                        if (!strncmp(tbfuncionesServer[i].nf, nfn,
2774                                     strlen(tbfuncionesServer[i].nf))) {
2775                                res = tbfuncionesServer[i].fcn(ptrTrama, cli);
2776                                if (!res) {
2777                                        syslog(LOG_ERR, "Failed handling of %s for client %s:%hu\n",
2778                                               tbfuncionesServer[i].nf,
2779                                               inet_ntoa(cli->addr.sin_addr),
2780                                               ntohs(cli->addr.sin_port));
2781                                } else {
2782                                        syslog(LOG_DEBUG, "Successful handling of %s for client %s:%hu\n",
2783                                               tbfuncionesServer[i].nf,
2784                                               inet_ntoa(cli->addr.sin_addr),
2785                                               ntohs(cli->addr.sin_port));
2786                                }
2787                                break;
2788                        }
2789                }
2790                if (!tbfuncionesServer[i].fcn)
2791                        syslog(LOG_ERR, "unknown request %s from client %s:%hu\n",
2792                               nfn, inet_ntoa(cli->addr.sin_addr),
2793                               ntohs(cli->addr.sin_port));
2794
2795                liberaMemoria(nfn);
2796        }
2797}
2798
2799static void og_client_release(struct ev_loop *loop, struct og_client *cli)
2800{
2801        if (cli->keepalive_idx >= 0) {
2802                syslog(LOG_DEBUG, "closing keepalive connection for %s:%hu in slot %d\n",
2803                       inet_ntoa(cli->addr.sin_addr),
2804                       ntohs(cli->addr.sin_port), cli->keepalive_idx);
2805                tbsockets[cli->keepalive_idx].cli = NULL;
2806        }
2807
2808        ev_io_stop(loop, &cli->io);
2809        close(cli->io.fd);
2810        free(cli);
2811}
2812
2813static void og_client_keepalive(struct ev_loop *loop, struct og_client *cli)
2814{
2815        struct og_client *old_cli;
2816
2817        old_cli = tbsockets[cli->keepalive_idx].cli;
2818        if (old_cli && old_cli != cli) {
2819                syslog(LOG_DEBUG, "closing old keepalive connection for %s:%hu\n",
2820                       inet_ntoa(old_cli->addr.sin_addr),
2821                       ntohs(old_cli->addr.sin_port));
2822
2823                og_client_release(loop, old_cli);
2824        }
2825        tbsockets[cli->keepalive_idx].cli = cli;
2826}
2827
2828static void og_client_reset_state(struct og_client *cli)
2829{
2830        cli->state = OG_CLIENT_RECEIVING_HEADER;
2831        cli->buf_len = 0;
2832}
2833
2834static int og_client_state_recv_hdr(struct og_client *cli)
2835{
2836        char hdrlen[LONHEXPRM];
2837
2838        /* Still too short to validate protocol fingerprint and message
2839         * length.
2840         */
2841        if (cli->buf_len < 15 + LONHEXPRM)
2842                return 0;
2843
2844        if (strncmp(cli->buf, "@JMMLCAMDJ_MCDJ", 15)) {
2845                syslog(LOG_ERR, "bad fingerprint from client %s:%hu, closing\n",
2846                       inet_ntoa(cli->addr.sin_addr),
2847                       ntohs(cli->addr.sin_port));
2848                return -1;
2849        }
2850
2851        memcpy(hdrlen, &cli->buf[LONGITUD_CABECERATRAMA], LONHEXPRM);
2852        cli->msg_len = strtol(hdrlen, NULL, 16);
2853
2854        /* Header announces more that we can fit into buffer. */
2855        if (cli->msg_len >= sizeof(cli->buf)) {
2856                syslog(LOG_ERR, "too large message %u bytes from %s:%hu\n",
2857                       cli->msg_len, inet_ntoa(cli->addr.sin_addr),
2858                       ntohs(cli->addr.sin_port));
2859                return -1;
2860        }
2861
2862        return 1;
2863}
2864
2865static TRAMA *og_msg_alloc(char *data, unsigned int len)
2866{
2867        TRAMA *ptrTrama;
2868
2869        ptrTrama = (TRAMA *)reservaMemoria(sizeof(TRAMA));
2870        if (!ptrTrama) {
2871                syslog(LOG_ERR, "OOM\n");
2872                return NULL;
2873        }
2874
2875        initParametros(ptrTrama, len);
2876        memcpy(ptrTrama, "@JMMLCAMDJ_MCDJ", LONGITUD_CABECERATRAMA);
2877        memcpy(ptrTrama->parametros, data, len);
2878        ptrTrama->lonprm = len;
2879
2880        return ptrTrama;
2881}
2882
2883static void og_msg_free(TRAMA *ptrTrama)
2884{
2885        liberaMemoria(ptrTrama->parametros);
2886        liberaMemoria(ptrTrama);
2887}
2888
2889static int og_client_state_process_payload(struct og_client *cli)
2890{
2891        TRAMA *ptrTrama;
2892        char *data;
2893        int len;
2894
2895        len = cli->msg_len - (LONGITUD_CABECERATRAMA + LONHEXPRM);
2896        data = &cli->buf[LONGITUD_CABECERATRAMA + LONHEXPRM];
2897
2898        ptrTrama = og_msg_alloc(data, len);
2899        if (!ptrTrama)
2900                return -1;
2901
2902        gestionaTrama(ptrTrama, cli);
2903
2904        og_msg_free(ptrTrama);
2905
2906        return 1;
2907}
2908
2909#define OG_CLIENTS_MAX  4096
2910#define OG_PARTITION_MAX 4
2911
2912struct og_partition {
2913        const char      *number;
2914        const char      *code;
2915        const char      *size;
2916        const char      *filesystem;
2917        const char      *format;
2918};
2919
2920struct og_sync_params {
2921        const char      *sync;
2922        const char      *diff;
2923        const char      *remove;
2924        const char      *compress;
2925        const char      *cleanup;
2926        const char      *cache;
2927        const char      *cleanup_cache;
2928        const char      *remove_dst;
2929        const char      *diff_id;
2930        const char      *diff_name;
2931        const char      *path;
2932        const char      *method;
2933};
2934
2935struct og_msg_params {
2936        const char      *ips_array[OG_CLIENTS_MAX];
2937        const char      *mac_array[OG_CLIENTS_MAX];
2938        const char      *netmask_array[OG_CLIENTS_MAX];
2939        unsigned int    ips_array_len;
2940        const char      *wol_type;
2941        char            run_cmd[4096];
2942        const char      *disk;
2943        const char      *partition;
2944        const char      *repository;
2945        const char      *name;
2946        const char      *id;
2947        const char      *code;
2948        const char      *type;
2949        const char      *profile;
2950        const char      *cache;
2951        const char      *cache_size;
2952        bool            echo;
2953        struct og_partition     partition_setup[OG_PARTITION_MAX];
2954        struct og_sync_params sync_setup;
2955        uint64_t        flags;
2956};
2957
2958#define OG_REST_PARAM_ADDR                      (1UL << 0)
2959#define OG_REST_PARAM_MAC                       (1UL << 1)
2960#define OG_REST_PARAM_WOL_TYPE                  (1UL << 2)
2961#define OG_REST_PARAM_RUN_CMD                   (1UL << 3)
2962#define OG_REST_PARAM_DISK                      (1UL << 4)
2963#define OG_REST_PARAM_PARTITION                 (1UL << 5)
2964#define OG_REST_PARAM_REPO                      (1UL << 6)
2965#define OG_REST_PARAM_NAME                      (1UL << 7)
2966#define OG_REST_PARAM_ID                        (1UL << 8)
2967#define OG_REST_PARAM_CODE                      (1UL << 9)
2968#define OG_REST_PARAM_TYPE                      (1UL << 10)
2969#define OG_REST_PARAM_PROFILE                   (1UL << 11)
2970#define OG_REST_PARAM_CACHE                     (1UL << 12)
2971#define OG_REST_PARAM_CACHE_SIZE                (1UL << 13)
2972#define OG_REST_PARAM_PART_0                    (1UL << 14)
2973#define OG_REST_PARAM_PART_1                    (1UL << 15)
2974#define OG_REST_PARAM_PART_2                    (1UL << 16)
2975#define OG_REST_PARAM_PART_3                    (1UL << 17)
2976#define OG_REST_PARAM_SYNC_SYNC                 (1UL << 18)
2977#define OG_REST_PARAM_SYNC_DIFF                 (1UL << 19)
2978#define OG_REST_PARAM_SYNC_REMOVE               (1UL << 20)
2979#define OG_REST_PARAM_SYNC_COMPRESS             (1UL << 21)
2980#define OG_REST_PARAM_SYNC_CLEANUP              (1UL << 22)
2981#define OG_REST_PARAM_SYNC_CACHE                (1UL << 23)
2982#define OG_REST_PARAM_SYNC_CLEANUP_CACHE        (1UL << 24)
2983#define OG_REST_PARAM_SYNC_REMOVE_DST           (1UL << 25)
2984#define OG_REST_PARAM_SYNC_DIFF_ID              (1UL << 26)
2985#define OG_REST_PARAM_SYNC_DIFF_NAME            (1UL << 27)
2986#define OG_REST_PARAM_SYNC_PATH                 (1UL << 28)
2987#define OG_REST_PARAM_SYNC_METHOD               (1UL << 29)
2988#define OG_REST_PARAM_ECHO                      (1UL << 30)
2989
2990static bool og_msg_params_validate(const struct og_msg_params *params,
2991                                   const uint64_t flags)
2992{
2993        return (params->flags & flags) == flags;
2994}
2995
2996static int og_json_parse_clients(json_t *element, struct og_msg_params *params)
2997{
2998        unsigned int i;
2999        json_t *k;
3000
3001        if (json_typeof(element) != JSON_ARRAY)
3002                return -1;
3003
3004        for (i = 0; i < json_array_size(element); i++) {
3005                k = json_array_get(element, i);
3006                if (json_typeof(k) != JSON_STRING)
3007                        return -1;
3008
3009                params->ips_array[params->ips_array_len++] =
3010                        json_string_value(k);
3011
3012                params->flags |= OG_REST_PARAM_ADDR;
3013        }
3014
3015        return 0;
3016}
3017
3018static int og_json_parse_string(json_t *element, const char **str)
3019{
3020        if (json_typeof(element) != JSON_STRING)
3021                return -1;
3022
3023        *str = json_string_value(element);
3024        return 0;
3025}
3026
3027static int og_json_parse_bool(json_t *element, bool *value)
3028{
3029        if (json_typeof(element) == JSON_TRUE)
3030                *value = true;
3031        else if (json_typeof(element) == JSON_FALSE)
3032                *value = false;
3033        else
3034                return -1;
3035
3036        return 0;
3037}
3038
3039static int og_json_parse_sync_params(json_t *element,
3040                                     struct og_msg_params *params)
3041{
3042        const char *key;
3043        json_t *value;
3044        int err = 0;
3045
3046        json_object_foreach(element, key, value) {
3047                if (!strcmp(key, "sync")) {
3048                        err = og_json_parse_string(value, &params->sync_setup.sync);
3049                        params->flags |= OG_REST_PARAM_SYNC_SYNC;
3050                } else if (!strcmp(key, "diff")) {
3051                        err = og_json_parse_string(value, &params->sync_setup.diff);
3052                        params->flags |= OG_REST_PARAM_SYNC_DIFF;
3053                } else if (!strcmp(key, "remove")) {
3054                        err = og_json_parse_string(value, &params->sync_setup.remove);
3055                        params->flags |= OG_REST_PARAM_SYNC_REMOVE;
3056                } else if (!strcmp(key, "compress")) {
3057                        err = og_json_parse_string(value, &params->sync_setup.compress);
3058                        params->flags |= OG_REST_PARAM_SYNC_COMPRESS;
3059                } else if (!strcmp(key, "cleanup")) {
3060                        err = og_json_parse_string(value, &params->sync_setup.cleanup);
3061                        params->flags |= OG_REST_PARAM_SYNC_CLEANUP;
3062                } else if (!strcmp(key, "cache")) {
3063                        err = og_json_parse_string(value, &params->sync_setup.cache);
3064                        params->flags |= OG_REST_PARAM_SYNC_CACHE;
3065                } else if (!strcmp(key, "cleanup_cache")) {
3066                        err = og_json_parse_string(value, &params->sync_setup.cleanup_cache);
3067                        params->flags |= OG_REST_PARAM_SYNC_CLEANUP_CACHE;
3068                } else if (!strcmp(key, "remove_dst")) {
3069                        err = og_json_parse_string(value, &params->sync_setup.remove_dst);
3070                        params->flags |= OG_REST_PARAM_SYNC_REMOVE_DST;
3071                } else if (!strcmp(key, "diff_id")) {
3072                        err = og_json_parse_string(value, &params->sync_setup.diff_id);
3073                        params->flags |= OG_REST_PARAM_SYNC_DIFF_ID;
3074                } else if (!strcmp(key, "diff_name")) {
3075                        err = og_json_parse_string(value, &params->sync_setup.diff_name);
3076                        params->flags |= OG_REST_PARAM_SYNC_DIFF_NAME;
3077                } else if (!strcmp(key, "path")) {
3078                        err = og_json_parse_string(value, &params->sync_setup.path);
3079                        params->flags |= OG_REST_PARAM_SYNC_PATH;
3080                } else if (!strcmp(key, "method")) {
3081                        err = og_json_parse_string(value, &params->sync_setup.method);
3082                        params->flags |= OG_REST_PARAM_SYNC_METHOD;
3083                }
3084
3085                if (err != 0)
3086                        return err;
3087        }
3088        return err;
3089}
3090
3091#define OG_PARAM_PART_NUMBER                    (1UL << 0)
3092#define OG_PARAM_PART_CODE                      (1UL << 1)
3093#define OG_PARAM_PART_FILESYSTEM                (1UL << 2)
3094#define OG_PARAM_PART_SIZE                      (1UL << 3)
3095#define OG_PARAM_PART_FORMAT                    (1UL << 4)
3096
3097static int og_json_parse_partition(json_t *element,
3098                                   struct og_msg_params *params,
3099                                   unsigned int i)
3100{
3101        struct og_partition *part = &params->partition_setup[i];
3102        uint64_t flags = 0UL;
3103        const char *key;
3104        json_t *value;
3105        int err = 0;
3106
3107        json_object_foreach(element, key, value) {
3108                if (!strcmp(key, "partition")) {
3109                        err = og_json_parse_string(value, &part->number);
3110                        flags |= OG_PARAM_PART_NUMBER;
3111                } else if (!strcmp(key, "code")) {
3112                        err = og_json_parse_string(value, &part->code);
3113                        flags |= OG_PARAM_PART_CODE;
3114                } else if (!strcmp(key, "filesystem")) {
3115                        err = og_json_parse_string(value, &part->filesystem);
3116                        flags |= OG_PARAM_PART_FILESYSTEM;
3117                } else if (!strcmp(key, "size")) {
3118                        err = og_json_parse_string(value, &part->size);
3119                        flags |= OG_PARAM_PART_SIZE;
3120                } else if (!strcmp(key, "format")) {
3121                        err = og_json_parse_string(value, &part->format);
3122                        flags |= OG_PARAM_PART_FORMAT;
3123                }
3124
3125                if (err < 0)
3126                        return err;
3127        }
3128
3129        if (flags != (OG_PARAM_PART_NUMBER |
3130                      OG_PARAM_PART_CODE |
3131                      OG_PARAM_PART_FILESYSTEM |
3132                      OG_PARAM_PART_SIZE |
3133                      OG_PARAM_PART_FORMAT))
3134                return -1;
3135
3136        params->flags |= (OG_REST_PARAM_PART_0 << i);
3137
3138        return err;
3139}
3140
3141static int og_json_parse_partition_setup(json_t *element,
3142                                         struct og_msg_params *params)
3143{
3144        unsigned int i;
3145        json_t *k;
3146
3147        if (json_typeof(element) != JSON_ARRAY)
3148                return -1;
3149
3150        for (i = 0; i < json_array_size(element) && i < OG_PARTITION_MAX; ++i) {
3151                k = json_array_get(element, i);
3152
3153                if (json_typeof(k) != JSON_OBJECT)
3154                        return -1;
3155
3156                if (og_json_parse_partition(k, params, i) != 0)
3157                        return -1;
3158        }
3159        return 0;
3160}
3161
3162static int og_cmd_legacy_send(struct og_msg_params *params, const char *cmd,
3163                              const char *state)
3164{
3165        char buf[4096] = {};
3166        int len, err = 0;
3167        TRAMA *msg;
3168
3169        len = snprintf(buf, sizeof(buf), "nfn=%s\r", cmd);
3170
3171        msg = og_msg_alloc(buf, len);
3172        if (!msg)
3173                return -1;
3174
3175        if (!og_send_cmd((char **)params->ips_array, params->ips_array_len,
3176                         state, msg))
3177                err = -1;
3178
3179        og_msg_free(msg);
3180
3181        return err;
3182}
3183
3184static int og_cmd_post_clients(json_t *element, struct og_msg_params *params)
3185{
3186        const char *key;
3187        json_t *value;
3188        int err = 0;
3189
3190        if (json_typeof(element) != JSON_OBJECT)
3191                return -1;
3192
3193        json_object_foreach(element, key, value) {
3194                if (!strcmp(key, "clients"))
3195                        err = og_json_parse_clients(value, params);
3196
3197                if (err < 0)
3198                        break;
3199        }
3200
3201        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
3202                return -1;
3203
3204        return og_cmd_legacy_send(params, "Sondeo", CLIENTE_APAGADO);
3205}
3206
3207struct og_buffer {
3208        char    *data;
3209        int     len;
3210};
3211
3212static int og_json_dump_clients(const char *buffer, size_t size, void *data)
3213{
3214        struct og_buffer *og_buffer = (struct og_buffer *)data;
3215
3216        memcpy(og_buffer->data + og_buffer->len, buffer, size);
3217        og_buffer->len += size;
3218
3219        return 0;
3220}
3221
3222static int og_cmd_get_clients(json_t *element, struct og_msg_params *params,
3223                              char *buffer_reply)
3224{
3225        json_t *root, *array, *addr, *state, *object;
3226        struct og_buffer og_buffer = {
3227                .data   = buffer_reply,
3228        };
3229        int i;
3230
3231        array = json_array();
3232        if (!array)
3233                return -1;
3234
3235        for (i = 0; i < MAXIMOS_CLIENTES; i++) {
3236                if (tbsockets[i].ip[0] == '\0')
3237                        continue;
3238
3239                object = json_object();
3240                if (!object) {
3241                        json_decref(array);
3242                        return -1;
3243                }
3244                addr = json_string(tbsockets[i].ip);
3245                if (!addr) {
3246                        json_decref(object);
3247                        json_decref(array);
3248                        return -1;
3249                }
3250                json_object_set_new(object, "addr", addr);
3251
3252                state = json_string(tbsockets[i].estado);
3253                if (!state) {
3254                        json_decref(object);
3255                        json_decref(array);
3256                        return -1;
3257                }
3258                json_object_set_new(object, "state", state);
3259
3260                json_array_append_new(array, object);
3261        }
3262        root = json_pack("{s:o}", "clients", array);
3263        if (!root) {
3264                json_decref(array);
3265                return -1;
3266        }
3267
3268        json_dump_callback(root, og_json_dump_clients, &og_buffer, 0);
3269        json_decref(root);
3270
3271        return 0;
3272}
3273
3274static int og_json_parse_target(json_t *element, struct og_msg_params *params)
3275{
3276        const char *key;
3277        json_t *value;
3278
3279        if (json_typeof(element) != JSON_OBJECT) {
3280                return -1;
3281        }
3282
3283        json_object_foreach(element, key, value) {
3284                if (!strcmp(key, "addr")) {
3285                        if (json_typeof(value) != JSON_STRING)
3286                                return -1;
3287
3288                        params->ips_array[params->ips_array_len] =
3289                                json_string_value(value);
3290
3291                        params->flags |= OG_REST_PARAM_ADDR;
3292                } else if (!strcmp(key, "mac")) {
3293                        if (json_typeof(value) != JSON_STRING)
3294                                return -1;
3295
3296                        params->mac_array[params->ips_array_len] =
3297                                json_string_value(value);
3298
3299                        params->flags |= OG_REST_PARAM_MAC;
3300                }
3301        }
3302
3303        return 0;
3304}
3305
3306static int og_json_parse_targets(json_t *element, struct og_msg_params *params)
3307{
3308        unsigned int i;
3309        json_t *k;
3310        int err;
3311
3312        if (json_typeof(element) != JSON_ARRAY)
3313                return -1;
3314
3315        for (i = 0; i < json_array_size(element); i++) {
3316                k = json_array_get(element, i);
3317
3318                if (json_typeof(k) != JSON_OBJECT)
3319                        return -1;
3320
3321                err = og_json_parse_target(k, params);
3322                if (err < 0)
3323                        return err;
3324
3325                params->ips_array_len++;
3326        }
3327        return 0;
3328}
3329
3330static int og_json_parse_type(json_t *element, struct og_msg_params *params)
3331{
3332        const char *type;
3333
3334        if (json_typeof(element) != JSON_STRING)
3335                return -1;
3336
3337        params->wol_type = json_string_value(element);
3338
3339        type = json_string_value(element);
3340        if (!strcmp(type, "unicast"))
3341                params->wol_type = "2";
3342        else if (!strcmp(type, "broadcast"))
3343                params->wol_type = "1";
3344
3345        params->flags |= OG_REST_PARAM_WOL_TYPE;
3346
3347        return 0;
3348}
3349
3350static int og_cmd_wol(json_t *element, struct og_msg_params *params)
3351{
3352        char ips_str[(OG_DB_IP_MAXLEN + 1) * OG_CLIENTS_MAX + 1] = {};
3353        int ips_str_len = 0;
3354        const char *msglog;
3355        struct og_dbi *dbi;
3356        int i = 0;
3357        dbi_result result;
3358        const char *key;
3359        json_t *value;
3360        int err = 0;
3361
3362        if (json_typeof(element) != JSON_OBJECT)
3363                return -1;
3364
3365        json_object_foreach(element, key, value) {
3366                if (!strcmp(key, "clients")) {
3367                        err = og_json_parse_targets(value, params);
3368                } else if (!strcmp(key, "type")) {
3369                        err = og_json_parse_type(value, params);
3370                }
3371
3372                if (err < 0)
3373                        break;
3374        }
3375
3376        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
3377                                            OG_REST_PARAM_MAC |
3378                                            OG_REST_PARAM_WOL_TYPE))
3379                return -1;
3380
3381        for (i = 0; i < params->ips_array_len; ++i) {
3382                ips_str_len += snprintf(ips_str + ips_str_len,
3383                                        sizeof(ips_str) - ips_str_len,
3384                                        "'%s',", params->ips_array[i]);
3385        }
3386        ips_str[ips_str_len - 1] = '\0';
3387
3388        dbi = og_dbi_open(&dbi_config);
3389        if (!dbi) {
3390                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
3391                       __func__, __LINE__);
3392                return -1;
3393        }
3394
3395        result = dbi_conn_queryf(dbi->conn,
3396                                 "SELECT ordenadores.ip, ordenadores.mac, "
3397                                        "aulas.netmask "
3398                                 "FROM   ordenadores "
3399                                 "INNER JOIN aulas "
3400                                         "ON ordenadores.idaula = aulas.idaula "
3401                                 "WHERE  ordenadores.ip IN (%s)",
3402                                 ips_str);
3403        if (!result) {
3404                dbi_conn_error(dbi->conn, &msglog);
3405                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3406                       __func__, __LINE__, msglog);
3407                og_dbi_close(dbi);
3408                return -1;
3409        }
3410
3411        for (i = 0; dbi_result_next_row(result); i++) {
3412                params->ips_array[i] = dbi_result_get_string_copy(result, "ip");
3413                params->mac_array[i] = dbi_result_get_string_copy(result, "mac");
3414                params->netmask_array[i] = dbi_result_get_string_copy(result, "netmask");
3415        }
3416
3417        dbi_result_free(result);
3418        og_dbi_close(dbi);
3419
3420        if (!Levanta((char **)params->ips_array, (char **)params->mac_array,
3421                     (char **)params->netmask_array, i,
3422                     (char *)params->wol_type))
3423                return -1;
3424
3425        return 0;
3426}
3427
3428static int og_json_parse_run(json_t *element, struct og_msg_params *params)
3429{
3430        if (json_typeof(element) != JSON_STRING)
3431                return -1;
3432
3433        snprintf(params->run_cmd, sizeof(params->run_cmd), "%s",
3434                 json_string_value(element));
3435
3436        params->flags |= OG_REST_PARAM_RUN_CMD;
3437
3438        return 0;
3439}
3440
3441static int og_cmd_run_post(json_t *element, struct og_msg_params *params)
3442{
3443        char buf[4096] = {}, iph[4096] = {};
3444        int err = 0, len;
3445        const char *key;
3446        unsigned int i;
3447        json_t *value;
3448        TRAMA *msg;
3449
3450        if (json_typeof(element) != JSON_OBJECT)
3451                return -1;
3452
3453        json_object_foreach(element, key, value) {
3454                if (!strcmp(key, "clients"))
3455                        err = og_json_parse_clients(value, params);
3456                else if (!strcmp(key, "run"))
3457                        err = og_json_parse_run(value, params);
3458                else if (!strcmp(key, "echo")) {
3459                        err = og_json_parse_bool(value, &params->echo);
3460                        params->flags |= OG_REST_PARAM_ECHO;
3461                }
3462
3463                if (err < 0)
3464                        break;
3465        }
3466
3467        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
3468                                            OG_REST_PARAM_RUN_CMD |
3469                                            OG_REST_PARAM_ECHO))
3470                return -1;
3471
3472        for (i = 0; i < params->ips_array_len; i++) {
3473                len = snprintf(iph + strlen(iph), sizeof(iph), "%s;",
3474                               params->ips_array[i]);
3475        }
3476
3477        if (params->echo) {
3478                len = snprintf(buf, sizeof(buf),
3479                               "nfn=ConsolaRemota\riph=%s\rscp=%s\r",
3480                               iph, params->run_cmd);
3481        } else {
3482                len = snprintf(buf, sizeof(buf),
3483                               "nfn=EjecutarScript\riph=%s\rscp=%s\r",
3484                               iph, params->run_cmd);
3485        }
3486
3487        msg = og_msg_alloc(buf, len);
3488        if (!msg)
3489                return -1;
3490
3491        if (!og_send_cmd((char **)params->ips_array, params->ips_array_len,
3492                         CLIENTE_OCUPADO, msg))
3493                err = -1;
3494
3495        og_msg_free(msg);
3496
3497        if (err < 0)
3498                return err;
3499
3500        for (i = 0; i < params->ips_array_len; i++) {
3501                char filename[4096];
3502                FILE *f;
3503
3504                sprintf(filename, "/tmp/_Seconsola_%s", params->ips_array[i]);
3505                f = fopen(filename, "wt");
3506                fclose(f);
3507        }
3508
3509        return 0;
3510}
3511
3512static int og_cmd_run_get(json_t *element, struct og_msg_params *params,
3513                          char *buffer_reply)
3514{
3515        struct og_buffer og_buffer = {
3516                .data   = buffer_reply,
3517        };
3518        json_t *root, *value, *array;
3519        const char *key;
3520        unsigned int i;
3521        int err = 0;
3522
3523        if (json_typeof(element) != JSON_OBJECT)
3524                return -1;
3525
3526        json_object_foreach(element, key, value) {
3527                if (!strcmp(key, "clients"))
3528                        err = og_json_parse_clients(value, params);
3529
3530                if (err < 0)
3531                        return err;
3532        }
3533
3534        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
3535                return -1;
3536
3537        array = json_array();
3538        if (!array)
3539                return -1;
3540
3541        for (i = 0; i < params->ips_array_len; i++) {
3542                json_t *object, *output, *addr;
3543                char data[4096] = {};
3544                char filename[4096];
3545                int fd, numbytes;
3546
3547                sprintf(filename, "/tmp/_Seconsola_%s", params->ips_array[i]);
3548
3549                fd = open(filename, O_RDONLY);
3550                if (!fd)
3551                        return -1;
3552
3553                numbytes = read(fd, data, sizeof(data));
3554                if (numbytes < 0) {
3555                        close(fd);
3556                        return -1;
3557                }
3558                data[sizeof(data) - 1] = '\0';
3559                close(fd);
3560
3561                object = json_object();
3562                if (!object) {
3563                        json_decref(array);
3564                        return -1;
3565                }
3566                addr = json_string(params->ips_array[i]);
3567                if (!addr) {
3568                        json_decref(object);
3569                        json_decref(array);
3570                        return -1;
3571                }
3572                json_object_set_new(object, "addr", addr);
3573
3574                output = json_string(data);
3575                if (!output) {
3576                        json_decref(object);
3577                        json_decref(array);
3578                        return -1;
3579                }
3580                json_object_set_new(object, "output", output);
3581
3582                json_array_append_new(array, object);
3583        }
3584
3585        root = json_pack("{s:o}", "clients", array);
3586        if (!root)
3587                return -1;
3588
3589        json_dump_callback(root, og_json_dump_clients, &og_buffer, 0);
3590        json_decref(root);
3591
3592        return 0;
3593}
3594
3595static int og_cmd_session(json_t *element, struct og_msg_params *params)
3596{
3597        char buf[4096], iph[4096];
3598        int err = 0, len;
3599        const char *key;
3600        unsigned int i;
3601        json_t *value;
3602        TRAMA *msg;
3603
3604        if (json_typeof(element) != JSON_OBJECT)
3605                return -1;
3606
3607        json_object_foreach(element, key, value) {
3608                if (!strcmp(key, "clients")) {
3609                        err = og_json_parse_clients(value, params);
3610                } else if (!strcmp(key, "disk")) {
3611                        err = og_json_parse_string(value, &params->disk);
3612                        params->flags |= OG_REST_PARAM_DISK;
3613                } else if (!strcmp(key, "partition")) {
3614                        err = og_json_parse_string(value, &params->partition);
3615                        params->flags |= OG_REST_PARAM_PARTITION;
3616                }
3617
3618                if (err < 0)
3619                        return err;
3620        }
3621
3622        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
3623                                            OG_REST_PARAM_DISK |
3624                                            OG_REST_PARAM_PARTITION))
3625                return -1;
3626
3627        for (i = 0; i < params->ips_array_len; i++) {
3628                snprintf(iph + strlen(iph), sizeof(iph), "%s;",
3629                         params->ips_array[i]);
3630        }
3631        len = snprintf(buf, sizeof(buf),
3632                       "nfn=IniciarSesion\riph=%s\rdsk=%s\rpar=%s\r",
3633                       iph, params->disk, params->partition);
3634
3635        msg = og_msg_alloc(buf, len);
3636        if (!msg)
3637                return -1;
3638
3639        if (!og_send_cmd((char **)params->ips_array, params->ips_array_len,
3640                         CLIENTE_APAGADO, msg))
3641                err = -1;
3642
3643        og_msg_free(msg);
3644
3645        return 0;
3646}
3647
3648static int og_cmd_poweroff(json_t *element, struct og_msg_params *params)
3649{
3650        const char *key;
3651        json_t *value;
3652        int err = 0;
3653
3654        if (json_typeof(element) != JSON_OBJECT)
3655                return -1;
3656
3657        json_object_foreach(element, key, value) {
3658                if (!strcmp(key, "clients"))
3659                        err = og_json_parse_clients(value, params);
3660
3661                if (err < 0)
3662                        break;
3663        }
3664
3665        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
3666                return -1;
3667
3668        return og_cmd_legacy_send(params, "Apagar", CLIENTE_OCUPADO);
3669}
3670
3671static int og_cmd_refresh(json_t *element, struct og_msg_params *params)
3672{
3673        const char *key;
3674        json_t *value;
3675        int err = 0;
3676
3677        if (json_typeof(element) != JSON_OBJECT)
3678                return -1;
3679
3680        json_object_foreach(element, key, value) {
3681                if (!strcmp(key, "clients"))
3682                        err = og_json_parse_clients(value, params);
3683
3684                if (err < 0)
3685                        break;
3686        }
3687
3688        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
3689                return -1;
3690
3691        return og_cmd_legacy_send(params, "Actualizar", CLIENTE_APAGADO);
3692}
3693
3694static int og_cmd_reboot(json_t *element, struct og_msg_params *params)
3695{
3696        const char *key;
3697        json_t *value;
3698        int err = 0;
3699
3700        if (json_typeof(element) != JSON_OBJECT)
3701                return -1;
3702
3703        json_object_foreach(element, key, value) {
3704                if (!strcmp(key, "clients"))
3705                        err = og_json_parse_clients(value, params);
3706
3707                if (err < 0)
3708                        break;
3709        }
3710
3711        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
3712                return -1;
3713
3714        return og_cmd_legacy_send(params, "Reiniciar", CLIENTE_OCUPADO);
3715}
3716
3717static int og_cmd_stop(json_t *element, struct og_msg_params *params)
3718{
3719        const char *key;
3720        json_t *value;
3721        int err = 0;
3722
3723        if (json_typeof(element) != JSON_OBJECT)
3724                return -1;
3725
3726        json_object_foreach(element, key, value) {
3727                if (!strcmp(key, "clients"))
3728                        err = og_json_parse_clients(value, params);
3729
3730                if (err < 0)
3731                        break;
3732        }
3733
3734        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
3735                return -1;
3736
3737        return og_cmd_legacy_send(params, "Purgar", CLIENTE_APAGADO);
3738}
3739
3740static int og_cmd_hardware(json_t *element, struct og_msg_params *params)
3741{
3742        const char *key;
3743        json_t *value;
3744        int err = 0;
3745
3746        if (json_typeof(element) != JSON_OBJECT)
3747                return -1;
3748
3749        json_object_foreach(element, key, value) {
3750                if (!strcmp(key, "clients"))
3751                        err = og_json_parse_clients(value, params);
3752
3753                if (err < 0)
3754                        break;
3755        }
3756
3757        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
3758                return -1;
3759
3760        return og_cmd_legacy_send(params, "InventarioHardware",
3761                                  CLIENTE_OCUPADO);
3762}
3763
3764static int og_cmd_software(json_t *element, struct og_msg_params *params)
3765{
3766        char buf[4096] = {};
3767        int err = 0, len;
3768        const char *key;
3769        json_t *value;
3770        TRAMA *msg;
3771
3772        if (json_typeof(element) != JSON_OBJECT)
3773                return -1;
3774
3775        json_object_foreach(element, key, value) {
3776                if (!strcmp(key, "clients"))
3777                        err = og_json_parse_clients(value, params);
3778                else if (!strcmp(key, "disk")) {
3779                        err = og_json_parse_string(value, &params->disk);
3780                        params->flags |= OG_REST_PARAM_DISK;
3781                }
3782                else if (!strcmp(key, "partition")) {
3783                        err = og_json_parse_string(value, &params->partition);
3784                        params->flags |= OG_REST_PARAM_PARTITION;
3785                }
3786
3787                if (err < 0)
3788                        break;
3789        }
3790
3791        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
3792                                            OG_REST_PARAM_DISK |
3793                                            OG_REST_PARAM_PARTITION))
3794                return -1;
3795
3796        len = snprintf(buf, sizeof(buf),
3797                       "nfn=InventarioSoftware\rdsk=%s\rpar=%s\r",
3798                       params->disk, params->partition);
3799
3800        msg = og_msg_alloc(buf, len);
3801        if (!msg)
3802                return -1;
3803
3804        og_send_cmd((char **)params->ips_array, params->ips_array_len,
3805                    CLIENTE_OCUPADO, msg);
3806
3807        og_msg_free(msg);
3808
3809        return 0;
3810}
3811
3812static int og_cmd_create_image(json_t *element, struct og_msg_params *params)
3813{
3814        char buf[4096] = {};
3815        int err = 0, len;
3816        const char *key;
3817        json_t *value;
3818        TRAMA *msg;
3819
3820        if (json_typeof(element) != JSON_OBJECT)
3821                return -1;
3822
3823        json_object_foreach(element, key, value) {
3824                if (!strcmp(key, "disk")) {
3825                        err = og_json_parse_string(value, &params->disk);
3826                        params->flags |= OG_REST_PARAM_DISK;
3827                } else if (!strcmp(key, "partition")) {
3828                        err = og_json_parse_string(value, &params->partition);
3829                        params->flags |= OG_REST_PARAM_PARTITION;
3830                } else if (!strcmp(key, "name")) {
3831                        err = og_json_parse_string(value, &params->name);
3832                        params->flags |= OG_REST_PARAM_NAME;
3833                } else if (!strcmp(key, "repository")) {
3834                        err = og_json_parse_string(value, &params->repository);
3835                        params->flags |= OG_REST_PARAM_REPO;
3836                } else if (!strcmp(key, "clients")) {
3837                        err = og_json_parse_clients(value, params);
3838                } else if (!strcmp(key, "id")) {
3839                        err = og_json_parse_string(value, &params->id);
3840                        params->flags |= OG_REST_PARAM_ID;
3841                } else if (!strcmp(key, "code")) {
3842                        err = og_json_parse_string(value, &params->code);
3843                        params->flags |= OG_REST_PARAM_CODE;
3844                }
3845
3846                if (err < 0)
3847                        break;
3848        }
3849
3850        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
3851                                            OG_REST_PARAM_DISK |
3852                                            OG_REST_PARAM_PARTITION |
3853                                            OG_REST_PARAM_CODE |
3854                                            OG_REST_PARAM_ID |
3855                                            OG_REST_PARAM_NAME |
3856                                            OG_REST_PARAM_REPO))
3857                return -1;
3858
3859        len = snprintf(buf, sizeof(buf),
3860                        "nfn=CrearImagen\rdsk=%s\rpar=%s\rcpt=%s\ridi=%s\rnci=%s\ripr=%s\r",
3861                        params->disk, params->partition, params->code,
3862                        params->id, params->name, params->repository);
3863
3864        msg = og_msg_alloc(buf, len);
3865        if (!msg)
3866                return -1;
3867
3868        og_send_cmd((char **)params->ips_array, params->ips_array_len,
3869                    CLIENTE_OCUPADO, msg);
3870
3871        og_msg_free(msg);
3872
3873        return 0;
3874}
3875
3876static int og_cmd_restore_image(json_t *element, struct og_msg_params *params)
3877{
3878        char buf[4096] = {};
3879        int err = 0, len;
3880        const char *key;
3881        json_t *value;
3882        TRAMA *msg;
3883
3884        if (json_typeof(element) != JSON_OBJECT)
3885                return -1;
3886
3887        json_object_foreach(element, key, value) {
3888                if (!strcmp(key, "disk")) {
3889                        err = og_json_parse_string(value, &params->disk);
3890                        params->flags |= OG_REST_PARAM_DISK;
3891                } else if (!strcmp(key, "partition")) {
3892                        err = og_json_parse_string(value, &params->partition);
3893                        params->flags |= OG_REST_PARAM_PARTITION;
3894                } else if (!strcmp(key, "name")) {
3895                        err = og_json_parse_string(value, &params->name);
3896                        params->flags |= OG_REST_PARAM_NAME;
3897                } else if (!strcmp(key, "repository")) {
3898                        err = og_json_parse_string(value, &params->repository);
3899                        params->flags |= OG_REST_PARAM_REPO;
3900                } else if (!strcmp(key, "clients")) {
3901                        err = og_json_parse_clients(value, params);
3902                } else if (!strcmp(key, "type")) {
3903                        err = og_json_parse_string(value, &params->type);
3904                        params->flags |= OG_REST_PARAM_TYPE;
3905                } else if (!strcmp(key, "profile")) {
3906                        err = og_json_parse_string(value, &params->profile);
3907                        params->flags |= OG_REST_PARAM_PROFILE;
3908                } else if (!strcmp(key, "id")) {
3909                        err = og_json_parse_string(value, &params->id);
3910                        params->flags |= OG_REST_PARAM_ID;
3911                }
3912
3913                if (err < 0)
3914                        break;
3915        }
3916
3917        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
3918                                            OG_REST_PARAM_DISK |
3919                                            OG_REST_PARAM_PARTITION |
3920                                            OG_REST_PARAM_NAME |
3921                                            OG_REST_PARAM_REPO |
3922                                            OG_REST_PARAM_TYPE |
3923                                            OG_REST_PARAM_PROFILE |
3924                                            OG_REST_PARAM_ID))
3925                return -1;
3926
3927        len = snprintf(buf, sizeof(buf),
3928                       "nfn=RestaurarImagen\ridi=%s\rdsk=%s\rpar=%s\rifs=%s\r"
3929                       "nci=%s\ripr=%s\rptc=%s\r",
3930                       params->id, params->disk, params->partition,
3931                       params->profile, params->name,
3932                       params->repository, params->type);
3933
3934        msg = og_msg_alloc(buf, len);
3935        if (!msg)
3936                return -1;
3937
3938        og_send_cmd((char **)params->ips_array, params->ips_array_len,
3939                    CLIENTE_OCUPADO, msg);
3940
3941        og_msg_free(msg);
3942
3943        return 0;
3944}
3945
3946static int og_cmd_setup(json_t *element, struct og_msg_params *params)
3947{
3948        char buf[4096] = {};
3949        int err = 0, len;
3950        const char *key;
3951        json_t *value;
3952        TRAMA *msg;
3953
3954        if (json_typeof(element) != JSON_OBJECT)
3955                return -1;
3956
3957        json_object_foreach(element, key, value) {
3958                if (!strcmp(key, "clients")) {
3959                        err = og_json_parse_clients(value, params);
3960                } else if (!strcmp(key, "disk")) {
3961                        err = og_json_parse_string(value, &params->disk);
3962                        params->flags |= OG_REST_PARAM_DISK;
3963                } else if (!strcmp(key, "cache")) {
3964                        err = og_json_parse_string(value, &params->cache);
3965                        params->flags |= OG_REST_PARAM_CACHE;
3966                } else if (!strcmp(key, "cache_size")) {
3967                        err = og_json_parse_string(value, &params->cache_size);
3968                        params->flags |= OG_REST_PARAM_CACHE_SIZE;
3969                } else if (!strcmp(key, "partition_setup")) {
3970                        err = og_json_parse_partition_setup(value, params);
3971                }
3972
3973                if (err < 0)
3974                        break;
3975        }
3976
3977        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
3978                                            OG_REST_PARAM_DISK |
3979                                            OG_REST_PARAM_CACHE |
3980                                            OG_REST_PARAM_CACHE_SIZE |
3981                                            OG_REST_PARAM_PART_0 |
3982                                            OG_REST_PARAM_PART_1 |
3983                                            OG_REST_PARAM_PART_2 |
3984                                            OG_REST_PARAM_PART_3))
3985                return -1;
3986
3987        len = snprintf(buf, sizeof(buf),
3988                        "nfn=Configurar\rdsk=%s\rcfg=dis=%s*che=%s*tch=%s!",
3989                        params->disk, params->disk, params->cache, params->cache_size);
3990
3991        for (unsigned int i = 0; i < OG_PARTITION_MAX; ++i) {
3992                const struct og_partition *part = &params->partition_setup[i];
3993
3994                len += snprintf(buf + strlen(buf), sizeof(buf),
3995                        "par=%s*cpt=%s*sfi=%s*tam=%s*ope=%s%%",
3996                        part->number, part->code, part->filesystem, part->size, part->format);
3997        }
3998
3999        msg = og_msg_alloc(buf, len + 1);
4000        if (!msg)
4001                return -1;
4002
4003        og_send_cmd((char **)params->ips_array, params->ips_array_len,
4004                        CLIENTE_OCUPADO, msg);
4005
4006        og_msg_free(msg);
4007
4008        return 0;
4009}
4010
4011static int og_cmd_run_schedule(json_t *element, struct og_msg_params *params)
4012{
4013        const char *key;
4014        json_t *value;
4015        int err = 0;
4016
4017        json_object_foreach(element, key, value) {
4018                if (!strcmp(key, "clients"))
4019                        err = og_json_parse_clients(value, params);
4020
4021                if (err < 0)
4022                        break;
4023        }
4024
4025        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
4026                return -1;
4027
4028        og_cmd_legacy_send(params, "EjecutaComandosPendientes", CLIENTE_OCUPADO);
4029
4030        return 0;
4031}
4032
4033static int og_cmd_create_basic_image(json_t *element, struct og_msg_params *params)
4034{
4035        char buf[4096] = {};
4036        int err = 0, len;
4037        const char *key;
4038        json_t *value;
4039        TRAMA *msg;
4040
4041        if (json_typeof(element) != JSON_OBJECT)
4042                return -1;
4043
4044        json_object_foreach(element, key, value) {
4045                if (!strcmp(key, "clients")) {
4046                        err = og_json_parse_clients(value, params);
4047                } else if (!strcmp(key, "disk")) {
4048                        err = og_json_parse_string(value, &params->disk);
4049                        params->flags |= OG_REST_PARAM_DISK;
4050                } else if (!strcmp(key, "partition")) {
4051                        err = og_json_parse_string(value, &params->partition);
4052                        params->flags |= OG_REST_PARAM_PARTITION;
4053                } else if (!strcmp(key, "code")) {
4054                        err = og_json_parse_string(value, &params->code);
4055                        params->flags |= OG_REST_PARAM_CODE;
4056                } else if (!strcmp(key, "id")) {
4057                        err = og_json_parse_string(value, &params->id);
4058                        params->flags |= OG_REST_PARAM_ID;
4059                } else if (!strcmp(key, "name")) {
4060                        err = og_json_parse_string(value, &params->name);
4061                        params->flags |= OG_REST_PARAM_NAME;
4062                } else if (!strcmp(key, "repository")) {
4063                        err = og_json_parse_string(value, &params->repository);
4064                        params->flags |= OG_REST_PARAM_REPO;
4065                } else if (!strcmp(key, "sync_params")) {
4066                        err = og_json_parse_sync_params(value, params);
4067                }
4068
4069                if (err < 0)
4070                        break;
4071        }
4072
4073        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
4074                                            OG_REST_PARAM_DISK |
4075                                            OG_REST_PARAM_PARTITION |
4076                                            OG_REST_PARAM_CODE |
4077                                            OG_REST_PARAM_ID |
4078                                            OG_REST_PARAM_NAME |
4079                                            OG_REST_PARAM_REPO |
4080                                            OG_REST_PARAM_SYNC_SYNC |
4081                                            OG_REST_PARAM_SYNC_DIFF |
4082                                            OG_REST_PARAM_SYNC_REMOVE |
4083                                            OG_REST_PARAM_SYNC_COMPRESS |
4084                                            OG_REST_PARAM_SYNC_CLEANUP |
4085                                            OG_REST_PARAM_SYNC_CACHE |
4086                                            OG_REST_PARAM_SYNC_CLEANUP_CACHE |
4087                                            OG_REST_PARAM_SYNC_REMOVE_DST))
4088                return -1;
4089
4090        len = snprintf(buf, sizeof(buf),
4091                       "nfn=CrearImagenBasica\rdsk=%s\rpar=%s\rcpt=%s\ridi=%s\r"
4092                       "nci=%s\ripr=%s\rrti=\rmsy=%s\rwhl=%s\reli=%s\rcmp=%s\rbpi=%s\r"
4093                       "cpc=%s\rbpc=%s\rnba=%s\r",
4094                       params->disk, params->partition, params->code, params->id,
4095                       params->name, params->repository, params->sync_setup.sync,
4096                       params->sync_setup.diff, params->sync_setup.remove,
4097                       params->sync_setup.compress, params->sync_setup.cleanup,
4098                       params->sync_setup.cache, params->sync_setup.cleanup_cache,
4099                       params->sync_setup.remove_dst);
4100
4101        msg = og_msg_alloc(buf, len);
4102        if (!msg)
4103                return -1;
4104
4105        og_send_cmd((char **)params->ips_array, params->ips_array_len,
4106                    CLIENTE_OCUPADO, msg);
4107
4108        og_msg_free(msg);
4109
4110        return 0;
4111}
4112
4113static int og_cmd_create_incremental_image(json_t *element, struct og_msg_params *params)
4114{
4115        char buf[4096] = {};
4116        int err = 0, len;
4117        const char *key;
4118        json_t *value;
4119        TRAMA *msg;
4120
4121        if (json_typeof(element) != JSON_OBJECT)
4122                return -1;
4123
4124        json_object_foreach(element, key, value) {
4125                if (!strcmp(key, "clients"))
4126                        err = og_json_parse_clients(value, params);
4127                else if (!strcmp(key, "disk")) {
4128                        err = og_json_parse_string(value, &params->disk);
4129                        params->flags |= OG_REST_PARAM_DISK;
4130                } else if (!strcmp(key, "partition")) {
4131                        err = og_json_parse_string(value, &params->partition);
4132                        params->flags |= OG_REST_PARAM_PARTITION;
4133                } else if (!strcmp(key, "id")) {
4134                        err = og_json_parse_string(value, &params->id);
4135                        params->flags |= OG_REST_PARAM_ID;
4136                } else if (!strcmp(key, "name")) {
4137                        err = og_json_parse_string(value, &params->name);
4138                        params->flags |= OG_REST_PARAM_NAME;
4139                } else if (!strcmp(key, "repository")) {
4140                        err = og_json_parse_string(value, &params->repository);
4141                        params->flags |= OG_REST_PARAM_REPO;
4142                } else if (!strcmp(key, "sync_params")) {
4143                        err = og_json_parse_sync_params(value, params);
4144                }
4145
4146                if (err < 0)
4147                        break;
4148        }
4149
4150        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
4151                                            OG_REST_PARAM_DISK |
4152                                            OG_REST_PARAM_PARTITION |
4153                                            OG_REST_PARAM_ID |
4154                                            OG_REST_PARAM_NAME |
4155                                            OG_REST_PARAM_REPO |
4156                                            OG_REST_PARAM_SYNC_SYNC |
4157                                            OG_REST_PARAM_SYNC_PATH |
4158                                            OG_REST_PARAM_SYNC_DIFF |
4159                                            OG_REST_PARAM_SYNC_DIFF_ID |
4160                                            OG_REST_PARAM_SYNC_DIFF_NAME |
4161                                            OG_REST_PARAM_SYNC_REMOVE |
4162                                            OG_REST_PARAM_SYNC_COMPRESS |
4163                                            OG_REST_PARAM_SYNC_CLEANUP |
4164                                            OG_REST_PARAM_SYNC_CACHE |
4165                                            OG_REST_PARAM_SYNC_CLEANUP_CACHE |
4166                                            OG_REST_PARAM_SYNC_REMOVE_DST))
4167                return -1;
4168
4169        len = snprintf(buf, sizeof(buf),
4170                       "nfn=CrearSoftIncremental\rdsk=%s\rpar=%s\ridi=%s\rnci=%s\r"
4171                       "rti=%s\ripr=%s\ridf=%s\rncf=%s\rmsy=%s\rwhl=%s\reli=%s\rcmp=%s\r"
4172                       "bpi=%s\rcpc=%s\rbpc=%s\rnba=%s\r",
4173                       params->disk, params->partition, params->id, params->name,
4174                       params->sync_setup.path, params->repository, params->sync_setup.diff_id,
4175                       params->sync_setup.diff_name, params->sync_setup.sync,
4176                       params->sync_setup.diff, params->sync_setup.remove_dst,
4177                       params->sync_setup.compress, params->sync_setup.cleanup,
4178                       params->sync_setup.cache, params->sync_setup.cleanup_cache,
4179                       params->sync_setup.remove_dst);
4180
4181        msg = og_msg_alloc(buf, len);
4182        if (!msg)
4183                return -1;
4184
4185        og_send_cmd((char **)params->ips_array, params->ips_array_len,
4186                    CLIENTE_OCUPADO, msg);
4187
4188        og_msg_free(msg);
4189
4190        return 0;
4191}
4192
4193static int og_cmd_restore_basic_image(json_t *element, struct og_msg_params *params)
4194{
4195        char buf[4096] = {};
4196        int err = 0, len;
4197        const char *key;
4198        json_t *value;
4199        TRAMA *msg;
4200
4201        if (json_typeof(element) != JSON_OBJECT)
4202                return -1;
4203
4204        json_object_foreach(element, key, value) {
4205                if (!strcmp(key, "clients")) {
4206                        err = og_json_parse_clients(value, params);
4207                } else if (!strcmp(key, "disk")) {
4208                        err = og_json_parse_string(value, &params->disk);
4209                        params->flags |= OG_REST_PARAM_DISK;
4210                } else if (!strcmp(key, "partition")) {
4211                        err = og_json_parse_string(value, &params->partition);
4212                        params->flags |= OG_REST_PARAM_PARTITION;
4213                } else if (!strcmp(key, "id")) {
4214                        err = og_json_parse_string(value, &params->id);
4215                        params->flags |= OG_REST_PARAM_ID;
4216                } else if (!strcmp(key, "name")) {
4217                        err = og_json_parse_string(value, &params->name);
4218                        params->flags |= OG_REST_PARAM_NAME;
4219                } else if (!strcmp(key, "repository")) {
4220                        err = og_json_parse_string(value, &params->repository);
4221                        params->flags |= OG_REST_PARAM_REPO;
4222                } else if (!strcmp(key, "profile")) {
4223                        err = og_json_parse_string(value, &params->profile);
4224                        params->flags |= OG_REST_PARAM_PROFILE;
4225                } else if (!strcmp(key, "type")) {
4226                        err = og_json_parse_string(value, &params->type);
4227                        params->flags |= OG_REST_PARAM_TYPE;
4228                } else if (!strcmp(key, "sync_params")) {
4229                        err = og_json_parse_sync_params(value, params);
4230                }
4231
4232                if (err < 0)
4233                        break;
4234        }
4235
4236        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
4237                                            OG_REST_PARAM_DISK |
4238                                            OG_REST_PARAM_PARTITION |
4239                                            OG_REST_PARAM_ID |
4240                                            OG_REST_PARAM_NAME |
4241                                            OG_REST_PARAM_REPO |
4242                                            OG_REST_PARAM_PROFILE |
4243                                            OG_REST_PARAM_TYPE |
4244                                            OG_REST_PARAM_SYNC_PATH |
4245                                            OG_REST_PARAM_SYNC_METHOD |
4246                                            OG_REST_PARAM_SYNC_SYNC |
4247                                            OG_REST_PARAM_SYNC_DIFF |
4248                                            OG_REST_PARAM_SYNC_REMOVE |
4249                                            OG_REST_PARAM_SYNC_COMPRESS |
4250                                            OG_REST_PARAM_SYNC_CLEANUP |
4251                                            OG_REST_PARAM_SYNC_CACHE |
4252                                            OG_REST_PARAM_SYNC_CLEANUP_CACHE |
4253                                            OG_REST_PARAM_SYNC_REMOVE_DST))
4254                return -1;
4255
4256        len = snprintf(buf, sizeof(buf),
4257                       "nfn=RestaurarImagenBasica\rdsk=%s\rpar=%s\ridi=%s\rnci=%s\r"
4258                           "ipr=%s\rifs=%s\rrti=%s\rmet=%s\rmsy=%s\rtpt=%s\rwhl=%s\r"
4259                           "eli=%s\rcmp=%s\rbpi=%s\rcpc=%s\rbpc=%s\rnba=%s\r",
4260                       params->disk, params->partition, params->id, params->name,
4261                           params->repository, params->profile, params->sync_setup.path,
4262                           params->sync_setup.method, params->sync_setup.sync, params->type,
4263                           params->sync_setup.diff, params->sync_setup.remove,
4264                       params->sync_setup.compress, params->sync_setup.cleanup,
4265                       params->sync_setup.cache, params->sync_setup.cleanup_cache,
4266                       params->sync_setup.remove_dst);
4267
4268        msg = og_msg_alloc(buf, len);
4269        if (!msg)
4270                return -1;
4271
4272        og_send_cmd((char **)params->ips_array, params->ips_array_len,
4273                    CLIENTE_OCUPADO, msg);
4274
4275        og_msg_free(msg);
4276
4277        return 0;
4278}
4279
4280static int og_cmd_restore_incremental_image(json_t *element, struct og_msg_params *params)
4281{
4282        char buf[4096] = {};
4283        int err = 0, len;
4284        const char *key;
4285        json_t *value;
4286        TRAMA *msg;
4287
4288        if (json_typeof(element) != JSON_OBJECT)
4289                return -1;
4290
4291        json_object_foreach(element, key, value) {
4292                if (!strcmp(key, "clients")) {
4293                        err = og_json_parse_clients(value, params);
4294                } else if (!strcmp(key, "disk")) {
4295                        err = og_json_parse_string(value, &params->disk);
4296                        params->flags |= OG_REST_PARAM_DISK;
4297                } else if (!strcmp(key, "partition")) {
4298                        err = og_json_parse_string(value, &params->partition);
4299                        params->flags |= OG_REST_PARAM_PARTITION;
4300                } else if (!strcmp(key, "id")) {
4301                        err = og_json_parse_string(value, &params->id);
4302                        params->flags |= OG_REST_PARAM_ID;
4303                } else if (!strcmp(key, "name")) {
4304                        err = og_json_parse_string(value, &params->name);
4305                        params->flags |= OG_REST_PARAM_NAME;
4306                } else if (!strcmp(key, "repository")) {
4307                        err = og_json_parse_string(value, &params->repository);
4308                        params->flags |= OG_REST_PARAM_REPO;
4309                } else if (!strcmp(key, "profile")) {
4310                        err = og_json_parse_string(value, &params->profile);
4311                        params->flags |= OG_REST_PARAM_PROFILE;
4312                } else if (!strcmp(key, "type")) {
4313                        err = og_json_parse_string(value, &params->type);
4314                        params->flags |= OG_REST_PARAM_TYPE;
4315                } else if (!strcmp(key, "sync_params")) {
4316                        err = og_json_parse_sync_params(value, params);
4317                }
4318
4319                if (err < 0)
4320                        break;
4321        }
4322
4323        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
4324                                            OG_REST_PARAM_DISK |
4325                                            OG_REST_PARAM_PARTITION |
4326                                            OG_REST_PARAM_ID |
4327                                            OG_REST_PARAM_NAME |
4328                                            OG_REST_PARAM_REPO |
4329                                            OG_REST_PARAM_PROFILE |
4330                                            OG_REST_PARAM_TYPE |
4331                                            OG_REST_PARAM_SYNC_DIFF_ID |
4332                                            OG_REST_PARAM_SYNC_DIFF_NAME |
4333                                            OG_REST_PARAM_SYNC_PATH |
4334                                            OG_REST_PARAM_SYNC_METHOD |
4335                                            OG_REST_PARAM_SYNC_SYNC |
4336                                            OG_REST_PARAM_SYNC_DIFF |
4337                                            OG_REST_PARAM_SYNC_REMOVE |
4338                                            OG_REST_PARAM_SYNC_COMPRESS |
4339                                            OG_REST_PARAM_SYNC_CLEANUP |
4340                                            OG_REST_PARAM_SYNC_CACHE |
4341                                            OG_REST_PARAM_SYNC_CLEANUP_CACHE |
4342                                            OG_REST_PARAM_SYNC_REMOVE_DST))
4343                return -1;
4344
4345        len = snprintf(buf, sizeof(buf),
4346                       "nfn=RestaurarSoftIncremental\rdsk=%s\rpar=%s\ridi=%s\rnci=%s\r"
4347                           "ipr=%s\rifs=%s\ridf=%s\rncf=%s\rrti=%s\rmet=%s\rmsy=%s\r"
4348                           "tpt=%s\rwhl=%s\reli=%s\rcmp=%s\rbpi=%s\rcpc=%s\rbpc=%s\r"
4349                           "nba=%s\r",
4350                       params->disk, params->partition, params->id, params->name,
4351                           params->repository, params->profile, params->sync_setup.diff_id,
4352                           params->sync_setup.diff_name, params->sync_setup.path,
4353                           params->sync_setup.method, params->sync_setup.sync, params->type,
4354                           params->sync_setup.diff, params->sync_setup.remove,
4355                       params->sync_setup.compress, params->sync_setup.cleanup,
4356                       params->sync_setup.cache, params->sync_setup.cleanup_cache,
4357                       params->sync_setup.remove_dst);
4358
4359        msg = og_msg_alloc(buf, len);
4360        if (!msg)
4361                return -1;
4362
4363        og_send_cmd((char **)params->ips_array, params->ips_array_len,
4364                    CLIENTE_OCUPADO, msg);
4365
4366        og_msg_free(msg);
4367
4368        return 0;
4369}
4370
4371static int og_client_method_not_found(struct og_client *cli)
4372{
4373        /* To meet RFC 7231, this function MUST generate an Allow header field
4374         * containing the correct methods. For example: "Allow: POST\r\n"
4375         */
4376        char buf[] = "HTTP/1.1 405 Method Not Allowed\r\n"
4377                     "Content-Length: 0\r\n\r\n";
4378
4379        send(og_client_socket(cli), buf, strlen(buf), 0);
4380
4381        return -1;
4382}
4383
4384static int og_client_bad_request(struct og_client *cli)
4385{
4386        char buf[] = "HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n";
4387
4388        send(og_client_socket(cli), buf, strlen(buf), 0);
4389
4390        return -1;
4391}
4392
4393static int og_client_not_found(struct og_client *cli)
4394{
4395        char buf[] = "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n";
4396
4397        send(og_client_socket(cli), buf, strlen(buf), 0);
4398
4399        return -1;
4400}
4401
4402static int og_client_not_authorized(struct og_client *cli)
4403{
4404        char buf[] = "HTTP/1.1 401 Unauthorized\r\n"
4405                     "WWW-Authenticate: Basic\r\n"
4406                     "Content-Length: 0\r\n\r\n";
4407
4408        send(og_client_socket(cli), buf, strlen(buf), 0);
4409
4410        return -1;
4411}
4412
4413static int og_server_internal_error(struct og_client *cli)
4414{
4415        char buf[] = "HTTP/1.1 500 Internal Server Error\r\n"
4416                     "Content-Length: 0\r\n\r\n";
4417
4418        send(og_client_socket(cli), buf, strlen(buf), 0);
4419
4420        return -1;
4421}
4422
4423static int og_client_payload_too_large(struct og_client *cli)
4424{
4425        char buf[] = "HTTP/1.1 413 Payload Too Large\r\n"
4426                     "Content-Length: 0\r\n\r\n";
4427
4428        send(og_client_socket(cli), buf, strlen(buf), 0);
4429
4430        return -1;
4431}
4432
4433#define OG_MSG_RESPONSE_MAXLEN  65536
4434
4435static int og_client_ok(struct og_client *cli, char *buf_reply)
4436{
4437        char buf[OG_MSG_RESPONSE_MAXLEN] = {};
4438        int err = 0, len;
4439
4440        len = snprintf(buf, sizeof(buf),
4441                       "HTTP/1.1 200 OK\r\nContent-Length: %ld\r\n\r\n%s",
4442                       strlen(buf_reply), buf_reply);
4443        if (len >= (int)sizeof(buf))
4444                err = og_server_internal_error(cli);
4445
4446        send(og_client_socket(cli), buf, strlen(buf), 0);
4447
4448        return err;
4449}
4450
4451enum og_rest_method {
4452        OG_METHOD_GET   = 0,
4453        OG_METHOD_POST,
4454};
4455
4456static int og_client_state_process_payload_rest(struct og_client *cli)
4457{
4458        char buf_reply[OG_MSG_RESPONSE_MAXLEN] = {};
4459        struct og_msg_params params = {};
4460        enum og_rest_method method;
4461        const char *cmd, *body;
4462        json_error_t json_err;
4463        json_t *root = NULL;
4464        int err = 0;
4465
4466        syslog(LOG_DEBUG, "%s:%hu %.32s ...\n",
4467               inet_ntoa(cli->addr.sin_addr),
4468               ntohs(cli->addr.sin_port), cli->buf);
4469
4470        if (!strncmp(cli->buf, "GET", strlen("GET"))) {
4471                method = OG_METHOD_GET;
4472                cmd = cli->buf + strlen("GET") + 2;
4473        } else if (!strncmp(cli->buf, "POST", strlen("POST"))) {
4474                method = OG_METHOD_POST;
4475                cmd = cli->buf + strlen("POST") + 2;
4476        } else
4477                return og_client_method_not_found(cli);
4478
4479        body = strstr(cli->buf, "\r\n\r\n") + 4;
4480
4481        if (strcmp(cli->auth_token, auth_token)) {
4482                syslog(LOG_ERR, "wrong Authentication key\n");
4483                return og_client_not_authorized(cli);
4484        }
4485
4486        if (cli->content_length) {
4487                root = json_loads(body, 0, &json_err);
4488                if (!root) {
4489                        syslog(LOG_ERR, "malformed json line %d: %s\n",
4490                               json_err.line, json_err.text);
4491                        return og_client_not_found(cli);
4492                }
4493        }
4494
4495        if (!strncmp(cmd, "clients", strlen("clients"))) {
4496                if (method != OG_METHOD_POST &&
4497                    method != OG_METHOD_GET)
4498                        return og_client_method_not_found(cli);
4499
4500                if (method == OG_METHOD_POST && !root) {
4501                        syslog(LOG_ERR, "command clients with no payload\n");
4502                        return og_client_bad_request(cli);
4503                }
4504                switch (method) {
4505                case OG_METHOD_POST:
4506                        err = og_cmd_post_clients(root, &params);
4507                        break;
4508                case OG_METHOD_GET:
4509                        err = og_cmd_get_clients(root, &params, buf_reply);
4510                        break;
4511                }
4512        } else if (!strncmp(cmd, "wol", strlen("wol"))) {
4513                if (method != OG_METHOD_POST)
4514                        return og_client_method_not_found(cli);
4515
4516                if (!root) {
4517                        syslog(LOG_ERR, "command wol with no payload\n");
4518                        return og_client_bad_request(cli);
4519                }
4520                err = og_cmd_wol(root, &params);
4521        } else if (!strncmp(cmd, "shell/run", strlen("shell/run"))) {
4522                if (method != OG_METHOD_POST)
4523                        return og_client_method_not_found(cli);
4524
4525                if (!root) {
4526                        syslog(LOG_ERR, "command run with no payload\n");
4527                        return og_client_bad_request(cli);
4528                }
4529                err = og_cmd_run_post(root, &params);
4530        } else if (!strncmp(cmd, "shell/output", strlen("shell/output"))) {
4531                if (method != OG_METHOD_POST)
4532                        return og_client_method_not_found(cli);
4533
4534                if (!root) {
4535                        syslog(LOG_ERR, "command output with no payload\n");
4536                        return og_client_bad_request(cli);
4537                }
4538
4539                err = og_cmd_run_get(root, &params, buf_reply);
4540        } else if (!strncmp(cmd, "session", strlen("session"))) {
4541                if (method != OG_METHOD_POST)
4542                        return og_client_method_not_found(cli);
4543
4544                if (!root) {
4545                        syslog(LOG_ERR, "command session with no payload\n");
4546                        return og_client_bad_request(cli);
4547                }
4548                err = og_cmd_session(root, &params);
4549        } else if (!strncmp(cmd, "poweroff", strlen("poweroff"))) {
4550                if (method != OG_METHOD_POST)
4551                        return og_client_method_not_found(cli);
4552
4553                if (!root) {
4554                        syslog(LOG_ERR, "command poweroff with no payload\n");
4555                        return og_client_bad_request(cli);
4556                }
4557                err = og_cmd_poweroff(root, &params);
4558        } else if (!strncmp(cmd, "reboot", strlen("reboot"))) {
4559                if (method != OG_METHOD_POST)
4560                        return og_client_method_not_found(cli);
4561
4562                if (!root) {
4563                        syslog(LOG_ERR, "command reboot with no payload\n");
4564                        return og_client_bad_request(cli);
4565                }
4566                err = og_cmd_reboot(root, &params);
4567        } else if (!strncmp(cmd, "stop", strlen("stop"))) {
4568                if (method != OG_METHOD_POST)
4569                        return og_client_method_not_found(cli);
4570
4571                if (!root) {
4572                        syslog(LOG_ERR, "command stop with no payload\n");
4573                        return og_client_bad_request(cli);
4574                }
4575                err = og_cmd_stop(root, &params);
4576        } else if (!strncmp(cmd, "refresh", strlen("refresh"))) {
4577                if (method != OG_METHOD_POST)
4578                        return og_client_method_not_found(cli);
4579
4580                if (!root) {
4581                        syslog(LOG_ERR, "command refresh with no payload\n");
4582                        return og_client_bad_request(cli);
4583                }
4584                err = og_cmd_refresh(root, &params);
4585        } else if (!strncmp(cmd, "hardware", strlen("hardware"))) {
4586                if (method != OG_METHOD_POST)
4587                        return og_client_method_not_found(cli);
4588
4589                if (!root) {
4590                        syslog(LOG_ERR, "command hardware with no payload\n");
4591                        return og_client_bad_request(cli);
4592                }
4593                err = og_cmd_hardware(root, &params);
4594        } else if (!strncmp(cmd, "software", strlen("software"))) {
4595                if (method != OG_METHOD_POST)
4596                        return og_client_method_not_found(cli);
4597
4598                if (!root) {
4599                        syslog(LOG_ERR, "command software with no payload\n");
4600                        return og_client_bad_request(cli);
4601                }
4602                err = og_cmd_software(root, &params);
4603        } else if (!strncmp(cmd, "image/create/basic",
4604                            strlen("image/create/basic"))) {
4605                if (method != OG_METHOD_POST)
4606                        return og_client_method_not_found(cli);
4607
4608                if (!root) {
4609                        syslog(LOG_ERR, "command create with no payload\n");
4610                        return og_client_bad_request(cli);
4611                }
4612                err = og_cmd_create_basic_image(root, &params);
4613        } else if (!strncmp(cmd, "image/create/incremental",
4614                            strlen("image/create/incremental"))) {
4615                if (method != OG_METHOD_POST)
4616                        return og_client_method_not_found(cli);
4617
4618                if (!root) {
4619                        syslog(LOG_ERR, "command create with no payload\n");
4620                        return og_client_bad_request(cli);
4621                }
4622                err = og_cmd_create_incremental_image(root, &params);
4623        } else if (!strncmp(cmd, "image/create", strlen("image/create"))) {
4624                if (method != OG_METHOD_POST)
4625                        return og_client_method_not_found(cli);
4626
4627                if (!root) {
4628                        syslog(LOG_ERR, "command create with no payload\n");
4629                        return og_client_bad_request(cli);
4630                }
4631                err = og_cmd_create_image(root, &params);
4632        } else if (!strncmp(cmd, "image/restore/basic",
4633                                strlen("image/restore/basic"))) {
4634                if (method != OG_METHOD_POST)
4635                        return og_client_method_not_found(cli);
4636
4637                if (!root) {
4638                        syslog(LOG_ERR, "command create with no payload\n");
4639                        return og_client_bad_request(cli);
4640                }
4641                err = og_cmd_restore_basic_image(root, &params);
4642        } else if (!strncmp(cmd, "image/restore/incremental",
4643                                strlen("image/restore/incremental"))) {
4644                if (method != OG_METHOD_POST)
4645                        return og_client_method_not_found(cli);
4646
4647                if (!root) {
4648                        syslog(LOG_ERR, "command create with no payload\n");
4649                        return og_client_bad_request(cli);
4650                }
4651                err = og_cmd_restore_incremental_image(root, &params);
4652        } else if (!strncmp(cmd, "image/restore", strlen("image/restore"))) {
4653                if (method != OG_METHOD_POST)
4654                        return og_client_method_not_found(cli);
4655
4656                if (!root) {
4657                        syslog(LOG_ERR, "command create with no payload\n");
4658                        return og_client_bad_request(cli);
4659                }
4660                err = og_cmd_restore_image(root, &params);
4661        } else if (!strncmp(cmd, "setup", strlen("setup"))) {
4662                if (method != OG_METHOD_POST)
4663                        return og_client_method_not_found(cli);
4664
4665                if (!root) {
4666                        syslog(LOG_ERR, "command create with no payload\n");
4667                        return og_client_bad_request(cli);
4668                }
4669                err = og_cmd_setup(root, &params);
4670        } else if (!strncmp(cmd, "run/schedule", strlen("run/schedule"))) {
4671                if (method != OG_METHOD_POST)
4672                        return og_client_method_not_found(cli);
4673
4674                if (!root) {
4675                        syslog(LOG_ERR, "command create with no payload\n");
4676                        return og_client_bad_request(cli);
4677                }
4678
4679                err = og_cmd_run_schedule(root, &params);
4680        } else {
4681                syslog(LOG_ERR, "unknown command: %.32s ...\n", cmd);
4682                err = og_client_not_found(cli);
4683        }
4684
4685        if (root)
4686                json_decref(root);
4687
4688        if (err < 0)
4689                return og_client_bad_request(cli);
4690
4691        err = og_client_ok(cli, buf_reply);
4692        if (err < 0) {
4693                syslog(LOG_ERR, "HTTP response to %s:%hu is too large\n",
4694                       inet_ntoa(cli->addr.sin_addr),
4695                       ntohs(cli->addr.sin_port));
4696        }
4697
4698        return err;
4699}
4700
4701static int og_client_state_recv_hdr_rest(struct og_client *cli)
4702{
4703        char *ptr;
4704
4705        ptr = strstr(cli->buf, "\r\n\r\n");
4706        if (!ptr)
4707                return 0;
4708
4709        cli->msg_len = ptr - cli->buf + 4;
4710
4711        ptr = strstr(cli->buf, "Content-Length: ");
4712        if (ptr) {
4713                sscanf(ptr, "Content-Length: %i[^\r\n]", &cli->content_length);
4714                if (cli->content_length < 0)
4715                        return -1;
4716                cli->msg_len += cli->content_length;
4717        }
4718
4719        ptr = strstr(cli->buf, "Authorization: ");
4720        if (ptr)
4721                sscanf(ptr, "Authorization: %63[^\r\n]", cli->auth_token);
4722
4723        return 1;
4724}
4725
4726static void og_client_read_cb(struct ev_loop *loop, struct ev_io *io, int events)
4727{
4728        struct og_client *cli;
4729        int ret;
4730
4731        cli = container_of(io, struct og_client, io);
4732
4733        if (events & EV_ERROR) {
4734                syslog(LOG_ERR, "unexpected error event from client %s:%hu\n",
4735                               inet_ntoa(cli->addr.sin_addr),
4736                               ntohs(cli->addr.sin_port));
4737                goto close;
4738        }
4739
4740        ret = recv(io->fd, cli->buf + cli->buf_len,
4741                   sizeof(cli->buf) - cli->buf_len, 0);
4742        if (ret <= 0) {
4743                if (ret < 0) {
4744                        syslog(LOG_ERR, "error reading from client %s:%hu (%s)\n",
4745                               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port),
4746                               strerror(errno));
4747                } else {
4748                        syslog(LOG_DEBUG, "closed connection by %s:%hu\n",
4749                               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
4750                }
4751                goto close;
4752        }
4753
4754        if (cli->keepalive_idx >= 0)
4755                return;
4756
4757        ev_timer_again(loop, &cli->timer);
4758
4759        cli->buf_len += ret;
4760        if (cli->buf_len >= sizeof(cli->buf)) {
4761                syslog(LOG_ERR, "client request from %s:%hu is too long\n",
4762                       inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
4763                og_client_payload_too_large(cli);
4764                goto close;
4765        }
4766
4767        switch (cli->state) {
4768        case OG_CLIENT_RECEIVING_HEADER:
4769                if (cli->rest)
4770                        ret = og_client_state_recv_hdr_rest(cli);
4771                else
4772                        ret = og_client_state_recv_hdr(cli);
4773
4774                if (ret < 0)
4775                        goto close;
4776                if (!ret)
4777                        return;
4778
4779                cli->state = OG_CLIENT_RECEIVING_PAYLOAD;
4780                /* Fall through. */
4781        case OG_CLIENT_RECEIVING_PAYLOAD:
4782                /* Still not enough data to process request. */
4783                if (cli->buf_len < cli->msg_len)
4784                        return;
4785
4786                cli->state = OG_CLIENT_PROCESSING_REQUEST;
4787                /* fall through. */
4788        case OG_CLIENT_PROCESSING_REQUEST:
4789                if (cli->rest) {
4790                        ret = og_client_state_process_payload_rest(cli);
4791                        if (ret < 0) {
4792                                syslog(LOG_ERR, "Failed to process HTTP request from %s:%hu\n",
4793                                       inet_ntoa(cli->addr.sin_addr),
4794                                       ntohs(cli->addr.sin_port));
4795                        }
4796                } else {
4797                        ret = og_client_state_process_payload(cli);
4798                }
4799                if (ret < 0)
4800                        goto close;
4801
4802                if (cli->keepalive_idx < 0) {
4803                        syslog(LOG_DEBUG, "server closing connection to %s:%hu\n",
4804                               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
4805                        goto close;
4806                } else {
4807                        syslog(LOG_DEBUG, "leaving client %s:%hu in keepalive mode\n",
4808                               inet_ntoa(cli->addr.sin_addr),
4809                               ntohs(cli->addr.sin_port));
4810                        og_client_keepalive(loop, cli);
4811                        og_client_reset_state(cli);
4812                }
4813                break;
4814        default:
4815                syslog(LOG_ERR, "unknown state, critical internal error\n");
4816                goto close;
4817        }
4818        return;
4819close:
4820        ev_timer_stop(loop, &cli->timer);
4821        og_client_release(loop, cli);
4822}
4823
4824static void og_client_timer_cb(struct ev_loop *loop, ev_timer *timer, int events)
4825{
4826        struct og_client *cli;
4827
4828        cli = container_of(timer, struct og_client, timer);
4829        if (cli->keepalive_idx >= 0) {
4830                ev_timer_again(loop, &cli->timer);
4831                return;
4832        }
4833        syslog(LOG_ERR, "timeout request for client %s:%hu\n",
4834               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
4835
4836        og_client_release(loop, cli);
4837}
4838
4839static int socket_s, socket_rest;
4840
4841static void og_server_accept_cb(struct ev_loop *loop, struct ev_io *io,
4842                                int events)
4843{
4844        struct sockaddr_in client_addr;
4845        socklen_t addrlen = sizeof(client_addr);
4846        struct og_client *cli;
4847        int client_sd;
4848
4849        if (events & EV_ERROR)
4850                return;
4851
4852        client_sd = accept(io->fd, (struct sockaddr *)&client_addr, &addrlen);
4853        if (client_sd < 0) {
4854                syslog(LOG_ERR, "cannot accept client connection\n");
4855                return;
4856        }
4857
4858        cli = (struct og_client *)calloc(1, sizeof(struct og_client));
4859        if (!cli) {
4860                close(client_sd);
4861                return;
4862        }
4863        memcpy(&cli->addr, &client_addr, sizeof(client_addr));
4864        cli->keepalive_idx = -1;
4865
4866        if (io->fd == socket_rest)
4867                cli->rest = true;
4868
4869        syslog(LOG_DEBUG, "connection from client %s:%hu\n",
4870               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
4871
4872        ev_io_init(&cli->io, og_client_read_cb, client_sd, EV_READ);
4873        ev_io_start(loop, &cli->io);
4874        ev_timer_init(&cli->timer, og_client_timer_cb, OG_CLIENT_TIMEOUT, 0.);
4875        ev_timer_start(loop, &cli->timer);
4876}
4877
4878static int og_socket_server_init(const char *port)
4879{
4880        struct sockaddr_in local;
4881        int sd, on = 1;
4882
4883        sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
4884        if (sd < 0) {
4885                syslog(LOG_ERR, "cannot create main socket\n");
4886                return -1;
4887        }
4888        setsockopt(sd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(int));
4889
4890        local.sin_addr.s_addr = htonl(INADDR_ANY);
4891        local.sin_family = AF_INET;
4892        local.sin_port = htons(atoi(port));
4893
4894        if (bind(sd, (struct sockaddr *) &local, sizeof(local)) < 0) {
4895                close(sd);
4896                syslog(LOG_ERR, "cannot bind socket\n");
4897                return -1;
4898        }
4899
4900        listen(sd, 250);
4901
4902        return sd;
4903}
4904
4905int main(int argc, char *argv[])
4906{
4907        struct ev_io ev_io_server, ev_io_server_rest;
4908        struct ev_loop *loop = ev_default_loop(0);
4909        int i;
4910
4911        if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
4912                exit(EXIT_FAILURE);
4913
4914        openlog("ogAdmServer", LOG_PID, LOG_DAEMON);
4915
4916        /*--------------------------------------------------------------------------------------------------------
4917         Validación de parámetros de ejecución y lectura del fichero de configuración del servicio
4918         ---------------------------------------------------------------------------------------------------------*/
4919        if (!validacionParametros(argc, argv, 1)) // Valida parámetros de ejecución
4920                exit(EXIT_FAILURE);
4921
4922        if (!tomaConfiguracion(szPathFileCfg)) { // Toma parametros de configuracion
4923                exit(EXIT_FAILURE);
4924        }
4925
4926        /*--------------------------------------------------------------------------------------------------------
4927         // Inicializa array de información de los clientes
4928         ---------------------------------------------------------------------------------------------------------*/
4929        for (i = 0; i < MAXIMOS_CLIENTES; i++) {
4930                tbsockets[i].ip[0] = '\0';
4931                tbsockets[i].cli = NULL;
4932        }
4933        /*--------------------------------------------------------------------------------------------------------
4934         Creación y configuración del socket del servicio
4935         ---------------------------------------------------------------------------------------------------------*/
4936        socket_s = og_socket_server_init(puerto);
4937        if (socket_s < 0)
4938                exit(EXIT_FAILURE);
4939
4940        ev_io_init(&ev_io_server, og_server_accept_cb, socket_s, EV_READ);
4941        ev_io_start(loop, &ev_io_server);
4942
4943        socket_rest = og_socket_server_init("8888");
4944        if (socket_rest < 0)
4945                exit(EXIT_FAILURE);
4946
4947        ev_io_init(&ev_io_server_rest, og_server_accept_cb, socket_rest, EV_READ);
4948        ev_io_start(loop, &ev_io_server_rest);
4949
4950        infoLog(1); // Inicio de sesión
4951
4952        /* old log file has been deprecated. */
4953        og_log(97, false);
4954
4955        syslog(LOG_INFO, "Waiting for connections\n");
4956
4957        while (1)
4958                ev_loop(loop, 0);
4959
4960        exit(EXIT_SUCCESS);
4961}
Note: See TracBrowser for help on using the repository browser.