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

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

#941 Consolidate CrearSoftIncremental?, RestaurarImagenBasica?, RestaurarSoftIncremental?, Configurar and EjecutarScript?

These functions are identical, remove duplicated code.

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