source: ogServer-Git/sources/ogAdmServer.cpp @ 0fde10b

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

#941 use dbi layer from procesoInclusionCliente()

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