source: ogServer-Git/sources/ogAdmServer.cpp @ 1d801be

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

#941 use dbi layer from respuestaEstandar()

And update all callers.

Some of the db.Open() calls cannot be removed yet, since there are still
more function dependencies that need to be converted too.

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