source: ogServer-Git/sources/ogAdmServer.cpp @ 46d791a

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

#915 check HTTP Content-Length size

If Content-Length is too large ogAdmServer, close the connection..

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