source: ogServer-Git/sources/ogAdmServer.cpp @ fbc783c

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

#941 Consolidate RESPUESTA_Reiniciar, RESPUESTA_IniciarSesion and RESPUESTA_Apagar

They are identical, remove duplicated code.

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