source: ogServer-Git/sources/ogAdmServer.cpp @ 882fec8

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

#915 trim unknown command syslog error to the initial 32 bytes

Aug 28 17:12:33 server ogAdmServer[10110]: 127.0.0.1:54640 POST /nonexistent HTTP/1.1M Host ...
Aug 28 17:12:33 server ogAdmServer[10110]: unknown command: nonexistent HTTP/1.1
M Host: loca ...

  • 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        unsigned 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[6], *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 (!mandaTrama(&sock, ptrTrama)) {
1145                                syslog(LOG_ERR, "failed to send response to %s:%s\n",
1146                                       ips_array[i], strerror(errno));
1147                                return false;
1148                        }
1149                }
1150        }
1151        return true;
1152}
1153
1154// ________________________________________________________________________________________________________
1155// Función: enviaComando
1156//
1157//      Descripción:
1158//              Envía un comando a los clientes
1159//      Parámetros:
1160//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1161//              - estado: Estado en el se deja al cliente mientras se ejecuta el comando
1162//      Devuelve:
1163//              true: Si el proceso es correcto
1164//              false: En caso de ocurrir algún error
1165// ________________________________________________________________________________________________________
1166bool enviaComando(TRAMA* ptrTrama, const char *estado)
1167{
1168        char *iph, *Ipes, *ptrIpes[MAXIMOS_CLIENTES];
1169        int lon;
1170
1171        iph = copiaParametro("iph",ptrTrama); // Toma dirección/es IP
1172        lon = strlen(iph); // Calcula longitud de la cadena de direccion/es IPE/S
1173        Ipes = (char*) reservaMemoria(lon + 1);
1174        if (Ipes == NULL) {
1175                syslog(LOG_ERR, "%s:%d OOM\n", __FILE__, __LINE__);
1176                return false;
1177        }
1178       
1179        strcpy(Ipes, iph); // Copia cadena de IPES
1180        liberaMemoria(iph);
1181
1182        lon = splitCadena(ptrIpes, Ipes, ';');
1183        FINCADaINTRO(ptrTrama);
1184
1185        if (!og_send_cmd(ptrIpes, lon, estado, ptrTrama))
1186                return false;
1187
1188        liberaMemoria(Ipes);
1189        return true;
1190}
1191//______________________________________________________________________________________________________
1192// Función: respuestaConsola
1193//
1194//      Descripción:
1195//              Envia una respuesta a la consola sobre el resultado de la ejecución de un comando
1196//      Parámetros:
1197//              - socket_c: (Salida) Socket utilizado para el envío
1198//              - res: Resultado del envío del comando
1199//      Devuelve:
1200//              true: Si el proceso es correcto
1201//              false: En caso de ocurrir algún error
1202// ________________________________________________________________________________________________________
1203bool respuestaConsola(int socket_c, TRAMA *ptrTrama, int res)
1204{
1205        initParametros(ptrTrama,0);
1206        sprintf(ptrTrama->parametros, "res=%d\r", res);
1207        if (!mandaTrama(&socket_c, ptrTrama)) {
1208                syslog(LOG_ERR, "%s:%d failed to send response: %s\n",
1209                       __func__, __LINE__, strerror(errno));
1210                return false;
1211        }
1212        return true;
1213}
1214// ________________________________________________________________________________________________________
1215// Función: Levanta
1216//
1217//      Descripción:
1218//              Enciende ordenadores a través de la red cuyas macs se pasan como parámetro
1219//      Parámetros:
1220//              - iph: Cadena de direcciones ip separadas por ";"
1221//              - mac: Cadena de direcciones mac separadas por ";"
1222//              - mar: Método de arranque (1=Broadcast, 2=Unicast)
1223//      Devuelve:
1224//              true: Si el proceso es correcto
1225//              false: En caso de ocurrir algún error
1226// ________________________________________________________________________________________________________
1227
1228bool Levanta(char *ptrIP[], char *ptrMacs[], int lon, char *mar)
1229{
1230        unsigned int on = 1;
1231        sockaddr_in local;
1232        int i, res;
1233        int s;
1234
1235        /* Creación de socket para envío de magig packet */
1236        s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1237        if (s < 0) {
1238                syslog(LOG_ERR, "cannot create socket for magic packet\n");
1239                return false;
1240        }
1241        res = setsockopt(s, SOL_SOCKET, SO_BROADCAST, (unsigned int *) &on,
1242                         sizeof(on));
1243        if (res < 0) {
1244                syslog(LOG_ERR, "cannot set broadcast socket\n");
1245                return false;
1246        }
1247        memset(&local, 0, sizeof(local));
1248        local.sin_family = AF_INET;
1249        local.sin_port = htons(PUERTO_WAKEUP);
1250        local.sin_addr.s_addr = htonl(INADDR_ANY);
1251
1252        for (i = 0; i < lon; i++) {
1253                if (!WakeUp(s, ptrIP[i], ptrMacs[i], mar)) {
1254                        syslog(LOG_ERR, "problem sending magic packet\n");
1255                        close(s);
1256                        return false;
1257                }
1258        }
1259        close(s);
1260        return true;
1261}
1262
1263#define OG_WOL_SEQUENCE         6
1264#define OG_WOL_MACADDR_LEN      6
1265#define OG_WOL_REPEAT           16
1266
1267struct wol_msg {
1268        char secuencia_FF[OG_WOL_SEQUENCE];
1269        char macbin[OG_WOL_REPEAT][OG_WOL_MACADDR_LEN];
1270};
1271
1272static bool wake_up_broadcast(int sd, struct sockaddr_in *client,
1273                              const struct wol_msg *msg)
1274{
1275        struct sockaddr_in *broadcast_addr;
1276        struct ifaddrs *ifaddr, *ifa;
1277        int ret;
1278
1279        if (getifaddrs(&ifaddr) < 0) {
1280                syslog(LOG_ERR, "cannot get list of addresses\n");
1281                return false;
1282        }
1283
1284        client->sin_addr.s_addr = htonl(INADDR_BROADCAST);
1285
1286        for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
1287                if (ifa->ifa_addr == NULL ||
1288                    ifa->ifa_addr->sa_family != AF_INET ||
1289                    strcmp(ifa->ifa_name, interface) != 0)
1290                        continue;
1291
1292                broadcast_addr =
1293                        (struct sockaddr_in *)ifa->ifa_ifu.ifu_broadaddr;
1294                client->sin_addr.s_addr = broadcast_addr->sin_addr.s_addr;
1295                break;
1296        }
1297        freeifaddrs(ifaddr);
1298
1299        ret = sendto(sd, msg, sizeof(*msg), 0,
1300                     (sockaddr *)client, sizeof(*client));
1301        if (ret < 0) {
1302                syslog(LOG_ERR, "failed to send broadcast wol\n");
1303                return false;
1304        }
1305
1306        return true;
1307}
1308
1309static bool wake_up_unicast(int sd, struct sockaddr_in *client,
1310                            const struct wol_msg *msg,
1311                            const struct in_addr *addr)
1312{
1313        int ret;
1314
1315        client->sin_addr.s_addr = addr->s_addr;
1316
1317        ret = sendto(sd, msg, sizeof(*msg), 0,
1318                     (sockaddr *)client, sizeof(*client));
1319        if (ret < 0) {
1320                syslog(LOG_ERR, "failed to send unicast wol\n");
1321                return false;
1322        }
1323
1324        return true;
1325}
1326
1327enum wol_delivery_type {
1328        OG_WOL_BROADCAST = 1,
1329        OG_WOL_UNICAST = 2
1330};
1331
1332//_____________________________________________________________________________________________________________
1333// Función: WakeUp
1334//
1335//       Descripción:
1336//              Enciende el ordenador cuya MAC se pasa como parámetro
1337//      Parámetros:
1338//              - s : Socket para enviar trama magic packet
1339//              - iph : Cadena con la dirección ip
1340//              - mac : Cadena con la dirección mac en formato XXXXXXXXXXXX
1341//              - mar: Método de arranque (1=Broadcast, 2=Unicast)
1342//      Devuelve:
1343//              true: Si el proceso es correcto
1344//              false: En caso de ocurrir algún error
1345//_____________________________________________________________________________________________________________
1346//
1347bool WakeUp(int s, char* iph, char *mac, char *mar)
1348{
1349        unsigned int macaddr[OG_WOL_MACADDR_LEN];
1350        char HDaddress_bin[OG_WOL_MACADDR_LEN];
1351        struct sockaddr_in WakeUpCliente;
1352        struct wol_msg Trama_WakeUp;
1353        struct in_addr addr;
1354        bool ret;
1355        int i;
1356
1357        for (i = 0; i < 6; i++) // Primera secuencia de la trama Wake Up (0xFFFFFFFFFFFF)
1358                Trama_WakeUp.secuencia_FF[i] = 0xFF;
1359
1360        sscanf(mac, "%02x%02x%02x%02x%02x%02x",
1361               &macaddr[0], &macaddr[1], &macaddr[2],
1362               &macaddr[3], &macaddr[4], &macaddr[5]);
1363
1364        for (i = 0; i < 6; i++)
1365                HDaddress_bin[i] = (uint8_t)macaddr[i];
1366
1367        for (i = 0; i < 16; i++) // Segunda secuencia de la trama Wake Up , repetir 16 veces su la MAC
1368                memcpy(&Trama_WakeUp.macbin[i][0], &HDaddress_bin, 6);
1369
1370        /* Creación de socket del cliente que recibe la trama magic packet */
1371        WakeUpCliente.sin_family = AF_INET;
1372        WakeUpCliente.sin_port = htons((short) PUERTO_WAKEUP);
1373
1374        switch (atoi(mar)) {
1375        case OG_WOL_BROADCAST:
1376                ret = wake_up_broadcast(s, &WakeUpCliente, &Trama_WakeUp);
1377                break;
1378        case OG_WOL_UNICAST:
1379                if (inet_aton(iph, &addr) < 0) {
1380                        syslog(LOG_ERR, "bad IP address for unicast wol\n");
1381                        ret = false;
1382                        break;
1383                }
1384                ret = wake_up_unicast(s, &WakeUpCliente, &Trama_WakeUp, &addr);
1385                break;
1386        default:
1387                syslog(LOG_ERR, "unknown wol type\n");
1388                ret = false;
1389                break;
1390        }
1391        return ret;
1392}
1393// ________________________________________________________________________________________________________
1394// Función: RESPUESTA_Arrancar
1395//
1396//      Descripción:
1397//              Respuesta del cliente al comando Arrancar
1398//      Parámetros:
1399//              - socket_c: Socket del cliente que envió el mensaje
1400//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1401//      Devuelve:
1402//              true: Si el proceso es correcto
1403//              false: En caso de ocurrir algún error
1404// ________________________________________________________________________________________________________
1405static bool RESPUESTA_Arrancar(TRAMA* ptrTrama, struct og_client *cli)
1406{
1407        char msglog[LONSTD];
1408        Database db;
1409        Table tbl;
1410        int i;
1411        char *iph, *ido;
1412        char *tpc;
1413
1414        if (!db.Open(usuario, pasguor, datasource, catalog)) {
1415                db.GetErrorErrStr(msglog);
1416                syslog(LOG_ERR, "cannot open connection database (%s:%d) %s\n",
1417                       __func__, __LINE__, msglog);
1418                return false;
1419        }
1420
1421        iph = copiaParametro("iph",ptrTrama); // Toma dirección ip
1422        ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
1423
1424        if (!respuestaEstandar(ptrTrama, iph, ido, db, tbl)) {
1425                liberaMemoria(iph);
1426                liberaMemoria(ido);
1427                syslog(LOG_ERR, "failed to register notification\n");
1428                return false;
1429        }
1430
1431        tpc = copiaParametro("tpc",ptrTrama); // Tipo de cliente (Plataforma y S.O.)
1432        if (clienteExistente(iph, &i)) // Actualiza estado
1433                strcpy(tbsockets[i].estado, tpc);
1434               
1435        liberaMemoria(iph);
1436        liberaMemoria(ido);
1437        liberaMemoria(tpc);
1438       
1439        db.Close(); // Cierra conexión
1440        return true;
1441}
1442// ________________________________________________________________________________________________________
1443// Función: Apagar
1444//
1445//      Descripción:
1446//              Procesa el comando Apagar
1447//      Parámetros:
1448//              - socket_c: Socket de la consola al envió el mensaje
1449//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1450//      Devuelve:
1451//              true: Si el proceso es correcto
1452//              false: En caso de ocurrir algún error
1453// ________________________________________________________________________________________________________
1454static bool Apagar(TRAMA* ptrTrama, struct og_client *cli)
1455{
1456        if (!enviaComando(ptrTrama, CLIENTE_OCUPADO)) {
1457                respuestaConsola(og_client_socket(cli), ptrTrama, false);
1458                return false;
1459        }
1460        respuestaConsola(og_client_socket(cli), ptrTrama, true);
1461        return true;
1462}
1463// ________________________________________________________________________________________________________
1464// Función: RESPUESTA_Apagar
1465//
1466//      Descripción:
1467//              Respuesta del cliente al comando Apagar
1468//      Parámetros:
1469//              - socket_c: Socket del cliente que envió el mensaje
1470//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1471//      Devuelve:
1472//              true: Si el proceso es correcto
1473//              false: En caso de ocurrir algún error
1474// ________________________________________________________________________________________________________
1475static bool RESPUESTA_Apagar(TRAMA* ptrTrama, struct og_client *cli)
1476{
1477        char msglog[LONSTD];
1478        Database db;
1479        Table tbl;
1480        int i;
1481        char *iph, *ido;
1482
1483        if (!db.Open(usuario, pasguor, datasource, catalog)) {
1484                db.GetErrorErrStr(msglog);
1485                syslog(LOG_ERR, "cannot open connection database (%s:%d) %s\n",
1486                       __func__, __LINE__, msglog);
1487                return false;
1488        }
1489
1490        iph = copiaParametro("iph",ptrTrama); // Toma dirección ip
1491        ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
1492
1493        if (!respuestaEstandar(ptrTrama, iph, ido, db, tbl)) {
1494                liberaMemoria(iph);
1495                liberaMemoria(ido);
1496                syslog(LOG_ERR, "failed to register notification\n");
1497                return false; // Error al registrar notificacion
1498        }
1499
1500        if (clienteExistente(iph, &i)) // Actualiza estado
1501                strcpy(tbsockets[i].estado, CLIENTE_APAGADO);
1502       
1503        liberaMemoria(iph);
1504        liberaMemoria(ido);
1505       
1506        db.Close(); // Cierra conexión
1507        return true;
1508}
1509// ________________________________________________________________________________________________________
1510// Función: RESPUESTA_Reiniciar
1511//
1512//      Descripción:
1513//              Respuesta del cliente al comando Reiniciar
1514//      Parámetros:
1515//              - socket_c: Socket del cliente que envió el mensaje
1516//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1517//      Devuelve:
1518//              true: Si el proceso es correcto
1519//              false: En caso de ocurrir algún error
1520// ________________________________________________________________________________________________________
1521static bool RESPUESTA_Reiniciar(TRAMA* ptrTrama, struct og_client *cli)
1522{
1523        char msglog[LONSTD];
1524        Database db;
1525        Table tbl;
1526        int i;
1527        char *iph, *ido;
1528
1529        if (!db.Open(usuario, pasguor, datasource, catalog)) {
1530                db.GetErrorErrStr(msglog);
1531                syslog(LOG_ERR, "cannot open connection database (%s:%d) %s\n",
1532                       __func__, __LINE__, msglog);
1533                return false;
1534        }
1535
1536        iph = copiaParametro("iph",ptrTrama); // Toma dirección ip
1537        ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
1538
1539        if (!respuestaEstandar(ptrTrama, iph, ido, db, tbl)) {
1540                liberaMemoria(iph);
1541                liberaMemoria(ido);
1542                syslog(LOG_ERR, "failed to register notification\n");
1543                return false; // Error al registrar notificacion
1544        }
1545
1546        if (clienteExistente(iph, &i)) // Actualiza estado
1547                strcpy(tbsockets[i].estado, CLIENTE_APAGADO);
1548       
1549        liberaMemoria(iph);
1550        liberaMemoria(ido);
1551
1552        db.Close(); // Cierra conexión
1553        return true;
1554}
1555// ________________________________________________________________________________________________________
1556// Función: RESPUESTA_IniciarSesion
1557//
1558//      Descripción:
1559//              Respuesta del cliente al comando Iniciar Sesión
1560//      Parámetros:
1561//              - socket_c: Socket del cliente que envió el mensaje
1562//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1563//      Devuelve:
1564//              true: Si el proceso es correcto
1565//              false: En caso de ocurrir algún error
1566// ________________________________________________________________________________________________________
1567static bool RESPUESTA_IniciarSesion(TRAMA* ptrTrama, struct og_client *cli)
1568{
1569        char msglog[LONSTD];
1570        Database db;
1571        Table tbl;
1572        int i;
1573        char *iph, *ido;
1574
1575        if (!db.Open(usuario, pasguor, datasource, catalog)) {
1576                db.GetErrorErrStr(msglog);
1577                syslog(LOG_ERR, "cannot open connection database (%s:%d) %s\n",
1578                       __func__, __LINE__, msglog);
1579                return false;
1580        }
1581
1582        iph = copiaParametro("iph",ptrTrama); // Toma dirección ip
1583        ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
1584
1585        if (!respuestaEstandar(ptrTrama, iph, ido, db, tbl)) {
1586                liberaMemoria(iph);
1587                liberaMemoria(ido);
1588                syslog(LOG_ERR, "failed to register notification\n");
1589                return false; // Error al registrar notificacion
1590        }
1591
1592        if (clienteExistente(iph, &i)) // Actualiza estado
1593                strcpy(tbsockets[i].estado, CLIENTE_APAGADO);
1594               
1595        liberaMemoria(iph);
1596        liberaMemoria(ido);
1597               
1598        db.Close(); // Cierra conexión
1599        return true;
1600}
1601// ________________________________________________________________________________________________________
1602// Función: CrearImagen
1603//
1604//      Descripción:
1605//              Crea una imagen de una partición de un disco y la guarda o bien en un repositorio
1606//      Parámetros:
1607//              - socket_c: Socket de la consola al envió el mensaje
1608//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1609//      Devuelve:
1610//              true: Si el proceso es correcto
1611//              false: En caso de ocurrir algún error
1612// ________________________________________________________________________________________________________
1613static bool CrearImagen(TRAMA* ptrTrama, struct og_client *cli)
1614{
1615        if (!enviaComando(ptrTrama, CLIENTE_OCUPADO)) {
1616                respuestaConsola(og_client_socket(cli), ptrTrama, false);
1617                return false;
1618        }
1619        respuestaConsola(og_client_socket(cli), ptrTrama, true);
1620        return true;
1621}
1622// ________________________________________________________________________________________________________
1623// Función: RESPUESTA_CrearImagen
1624//
1625//      Descripción:
1626//              Respuesta del cliente al comando CrearImagen
1627//      Parámetros:
1628//              - socket_c: Socket del cliente que envió el mensaje
1629//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1630//      Devuelve:
1631//              true: Si el proceso es correcto
1632//              false: En caso de ocurrir algún error
1633// ________________________________________________________________________________________________________
1634static bool RESPUESTA_CrearImagen(TRAMA* ptrTrama, struct og_client *cli)
1635{
1636        char msglog[LONSTD];
1637        Database db;
1638        Table tbl;
1639        char *iph, *dsk, *par, *cpt, *ipr, *ido;
1640        char *idi;
1641        bool res;
1642
1643        if (!db.Open(usuario, pasguor, datasource, catalog)) {
1644                db.GetErrorErrStr(msglog);
1645                syslog(LOG_ERR, "cannot open connection database (%s:%d) %s\n",
1646                       __func__, __LINE__, msglog);
1647                return false;
1648        }
1649
1650        iph = copiaParametro("iph",ptrTrama); // Toma dirección ip
1651        ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
1652
1653        if (!respuestaEstandar(ptrTrama, iph, ido, db, tbl)) {
1654                liberaMemoria(iph);
1655                liberaMemoria(ido);
1656                syslog(LOG_ERR, "failed to register notification\n");
1657                return false; // Error al registrar notificacion
1658        }
1659
1660        // Acciones posteriores
1661        idi = copiaParametro("idi",ptrTrama);
1662        dsk = copiaParametro("dsk",ptrTrama);
1663        par = copiaParametro("par",ptrTrama);
1664        cpt = copiaParametro("cpt",ptrTrama);
1665        ipr = copiaParametro("ipr",ptrTrama);
1666
1667        res=actualizaCreacionImagen(db, tbl, idi, dsk, par, cpt, ipr, ido);
1668
1669        liberaMemoria(idi);
1670        liberaMemoria(par);
1671        liberaMemoria(cpt);
1672        liberaMemoria(ipr);
1673
1674        if(!res){
1675                syslog(LOG_ERR, "Problem processing update\n");
1676                db.Close();
1677                return false;
1678        }
1679
1680        db.Close(); // Cierra conexión
1681        return true;
1682}
1683// ________________________________________________________________________________________________________
1684// Función: actualizaCreacionImagen
1685//
1686//      Descripción:
1687//              Esta función actualiza la base de datos con el resultado de la creación de una imagen
1688//      Parámetros:
1689//              - db: Objeto base de datos (ya operativo)
1690//              - tbl: Objeto tabla
1691//              - idi: Identificador de la imagen
1692//              - dsk: Disco de donde se creó
1693//              - par: Partición de donde se creó
1694//              - cpt: Código de partición
1695//              - ipr: Ip del repositorio
1696//              - ido: Identificador del ordenador modelo
1697//      Devuelve:
1698//              true: Si el proceso es correcto
1699//              false: En caso de ocurrir algún error
1700// ________________________________________________________________________________________________________
1701bool actualizaCreacionImagen(Database db, Table tbl, char *idi, char *dsk,
1702                             char *par, char *cpt, char *ipr, char *ido)
1703{
1704        char msglog[LONSTD], sqlstr[LONSQL];
1705        int idr,ifs;
1706
1707        /* Toma identificador del repositorio correspondiente al ordenador modelo */
1708        snprintf(sqlstr, LONSQL,
1709                        "SELECT repositorios.idrepositorio"
1710                        "  FROM repositorios"
1711                        "  LEFT JOIN ordenadores USING (idrepositorio)"
1712                        " WHERE repositorios.ip='%s' AND ordenadores.idordenador=%s", ipr, ido);
1713
1714        if (!db.Execute(sqlstr, tbl)) {
1715                db.GetErrorErrStr(msglog);
1716                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1717                       __func__, __LINE__, msglog);
1718                return false;
1719        }
1720        if (!tbl.Get("idrepositorio", idr)) { // Toma dato
1721                tbl.GetErrorErrStr(msglog); // Error al acceder al registro
1722                og_info(msglog);
1723                return false;
1724        }
1725
1726        /* Toma identificador del perfilsoftware */
1727        snprintf(sqlstr, LONSQL,
1728                        "SELECT idperfilsoft"
1729                        "  FROM ordenadores_particiones"
1730                        " WHERE idordenador=%s AND numdisk=%s AND numpar=%s", ido, dsk, par);
1731
1732        if (!db.Execute(sqlstr, tbl)) {
1733                db.GetErrorErrStr(msglog);
1734                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1735                       __func__, __LINE__, msglog);
1736                return false;
1737        }
1738        if (!tbl.Get("idperfilsoft", ifs)) { // Toma dato
1739                tbl.GetErrorErrStr(msglog); // Error al acceder al registro
1740                og_info(msglog);
1741                return false;
1742        }
1743
1744        /* Actualizar los datos de la imagen */
1745        snprintf(sqlstr, LONSQL,
1746                "UPDATE imagenes"
1747                "   SET idordenador=%s, numdisk=%s, numpar=%s, codpar=%s,"
1748                "       idperfilsoft=%d, idrepositorio=%d,"
1749                "       fechacreacion=NOW(), revision=revision+1"
1750                " WHERE idimagen=%s", ido, dsk, par, cpt, ifs, idr, idi);
1751
1752        if (!db.Execute(sqlstr, tbl)) {
1753                db.GetErrorErrStr(msglog);
1754                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1755                       __func__, __LINE__, msglog);
1756                return false;
1757        }
1758        /* Actualizar los datos en el cliente */
1759        snprintf(sqlstr, LONSQL,
1760                "UPDATE ordenadores_particiones"
1761                "   SET idimagen=%s, revision=(SELECT revision FROM imagenes WHERE idimagen=%s),"
1762                "       fechadespliegue=NOW()"
1763                " WHERE idordenador=%s AND numdisk=%s AND numpar=%s",
1764                idi, idi, ido, dsk, par);
1765        if (!db.Execute(sqlstr, tbl)) {
1766                db.GetErrorErrStr(msglog);
1767                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1768                       __func__, __LINE__, msglog);
1769                return false;
1770        }
1771        return true;
1772}
1773// ________________________________________________________________________________________________________
1774// Función: CrearImagenBasica
1775//
1776//      Descripción:
1777//              Crea una imagen basica usando sincronización
1778//      Parámetros:
1779//              - socket_c: Socket de la consola al envió el mensaje
1780//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1781//      Devuelve:
1782//              true: Si el proceso es correcto
1783//              false: En caso de ocurrir algún error
1784// ________________________________________________________________________________________________________
1785static bool CrearImagenBasica(TRAMA* ptrTrama, struct og_client *cli)
1786{
1787        if (!enviaComando(ptrTrama, CLIENTE_OCUPADO)) {
1788                respuestaConsola(og_client_socket(cli), ptrTrama, false);
1789                return false;
1790        }
1791        respuestaConsola(og_client_socket(cli), ptrTrama, true);
1792        return true;
1793}
1794// ________________________________________________________________________________________________________
1795// Función: RESPUESTA_CrearImagenBasica
1796//
1797//      Descripción:
1798//              Respuesta del cliente al comando CrearImagenBasica
1799//      Parámetros:
1800//              - socket_c: Socket del cliente que envió el mensaje
1801//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1802//      Devuelve:
1803//              true: Si el proceso es correcto
1804//              false: En caso de ocurrir algún error
1805// ________________________________________________________________________________________________________
1806static bool RESPUESTA_CrearImagenBasica(TRAMA* ptrTrama, struct og_client *cli)
1807{
1808        // La misma respuesta que la creación de imagen monolítica
1809        return RESPUESTA_CrearImagen(ptrTrama, cli);
1810}
1811// ________________________________________________________________________________________________________
1812// Función: CrearSoftIncremental
1813//
1814//      Descripción:
1815//              Crea una imagen incremental entre una partición de un disco y una imagen ya creada guardandola en el
1816//              mismo repositorio y en la misma carpeta donde está la imagen básica
1817//      Parámetros:
1818//              - socket_c: Socket de la consola al envió el mensaje
1819//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1820//      Devuelve:
1821//              true: Si el proceso es correcto
1822//              false: En caso de ocurrir algún error
1823// ________________________________________________________________________________________________________
1824static bool CrearSoftIncremental(TRAMA* ptrTrama, struct og_client *cli)
1825{
1826        if (!enviaComando(ptrTrama, CLIENTE_OCUPADO)) {
1827                respuestaConsola(og_client_socket(cli), ptrTrama, false);
1828                return false;
1829        }
1830        respuestaConsola(og_client_socket(cli), ptrTrama, true);
1831        return true;
1832}
1833// ________________________________________________________________________________________________________
1834// Función: RESPUESTA_CrearSoftIncremental
1835//
1836//      Descripción:
1837//              Respuesta del cliente al comando crearImagenDiferencial
1838//      Parámetros:
1839//              - socket_c: Socket del cliente que envió el mensaje
1840//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1841//      Devuelve:
1842//              true: Si el proceso es correcto
1843//              false: En caso de ocurrir algún error
1844// ________________________________________________________________________________________________________
1845static bool RESPUESTA_CrearSoftIncremental(TRAMA* ptrTrama, struct og_client *cli)
1846{
1847        Database db;
1848        Table tbl;
1849        char *iph,*par,*ido,*idf;
1850        int ifs;
1851        char msglog[LONSTD],sqlstr[LONSQL];
1852
1853        if (!db.Open(usuario, pasguor, datasource, catalog)) {
1854                db.GetErrorErrStr(msglog);
1855                syslog(LOG_ERR, "cannot open connection database (%s:%d) %s\n",
1856                       __func__, __LINE__, msglog);
1857                return false;
1858        }
1859
1860        iph = copiaParametro("iph",ptrTrama); // Toma dirección ip
1861        ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
1862
1863        if (!respuestaEstandar(ptrTrama, iph, ido, db, tbl)) {
1864                liberaMemoria(iph);
1865                liberaMemoria(ido);
1866                syslog(LOG_ERR, "failed to register notification\n");
1867                return false;
1868        }
1869
1870        par = copiaParametro("par",ptrTrama);
1871
1872        /* Toma identificador del perfilsoftware creado por el inventario de software */
1873        sprintf(sqlstr,"SELECT idperfilsoft FROM ordenadores_particiones WHERE idordenador=%s AND numpar=%s",ido,par);
1874       
1875        liberaMemoria(iph);
1876        liberaMemoria(ido);     
1877        liberaMemoria(par);     
1878
1879        if (!db.Execute(sqlstr, tbl)) {
1880                db.GetErrorErrStr(msglog);
1881                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1882                       __func__, __LINE__, msglog);
1883                return false;
1884        }
1885        if (!tbl.Get("idperfilsoft", ifs)) { // Toma dato
1886                tbl.GetErrorErrStr(msglog); // Error al acceder al registro
1887                og_info(msglog);
1888                return false;
1889        }
1890
1891        /* Actualizar los datos de la imagen */
1892        idf = copiaParametro("idf",ptrTrama);
1893        sprintf(sqlstr,"UPDATE imagenes SET idperfilsoft=%d WHERE idimagen=%s",ifs,idf);
1894        liberaMemoria(idf);     
1895
1896        if (!db.Execute(sqlstr, tbl)) {
1897                db.GetErrorErrStr(msglog);
1898                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1899                       __func__, __LINE__, msglog);
1900                return false;
1901        }
1902        db.Close(); // Cierra conexión
1903        return true;
1904}
1905// ________________________________________________________________________________________________________
1906// Función: RestaurarImagen
1907//
1908//      Descripción:
1909//              Restaura una imagen en una partición
1910//      Parámetros:
1911//              - socket_c: Socket de la consola al envió el mensaje
1912//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1913//      Devuelve:
1914//              true: Si el proceso es correcto
1915//              false: En caso de ocurrir algún error
1916// ________________________________________________________________________________________________________
1917static bool RestaurarImagen(TRAMA* ptrTrama, struct og_client *cli)
1918{
1919        if (!enviaComando(ptrTrama, CLIENTE_OCUPADO)) {
1920                respuestaConsola(og_client_socket(cli), ptrTrama, false);
1921                return false;
1922        }
1923        respuestaConsola(og_client_socket(cli), ptrTrama, true);
1924        return true;
1925}
1926// ________________________________________________________________________________________________________
1927// Función: RestaurarImagenBasica
1928//
1929//      Descripción:
1930//              Restaura una imagen básica en una partición
1931//      Parámetros:
1932//              - socket_c: Socket de la consola al envió el mensaje
1933//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1934//      Devuelve:
1935//              true: Si el proceso es correcto
1936//              false: En caso de ocurrir algún error
1937// ________________________________________________________________________________________________________
1938static bool RestaurarImagenBasica(TRAMA* ptrTrama, struct og_client *cli)
1939{
1940        if (!enviaComando(ptrTrama, CLIENTE_OCUPADO)) {
1941                respuestaConsola(og_client_socket(cli), ptrTrama, false);
1942                return false;
1943        }
1944        respuestaConsola(og_client_socket(cli), ptrTrama, true);
1945        return true;
1946}
1947// ________________________________________________________________________________________________________
1948// Función: RestaurarSoftIncremental
1949//
1950//      Descripción:
1951//              Restaura una imagen básica junto con software incremental en una partición
1952//      Parámetros:
1953//              - socket_c: Socket de la consola al envió el mensaje
1954//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1955//      Devuelve:
1956//              true: Si el proceso es correcto
1957//              false: En caso de ocurrir algún error
1958// ________________________________________________________________________________________________________
1959static bool RestaurarSoftIncremental(TRAMA* ptrTrama, struct og_client *cli)
1960{
1961        if (!enviaComando(ptrTrama, CLIENTE_OCUPADO)) {
1962                respuestaConsola(og_client_socket(cli), ptrTrama, false);
1963                return false;
1964        }
1965        respuestaConsola(og_client_socket(cli), ptrTrama, true);
1966        return true;
1967}
1968// ________________________________________________________________________________________________________
1969// Función: RESPUESTA_RestaurarImagen
1970//
1971//      Descripción:
1972//              Respuesta del cliente al comando RestaurarImagen
1973//      Parámetros:
1974//              - socket_c: Socket del cliente que envió el mensaje
1975//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
1976//      Devuelve:
1977//              true: Si el proceso es correcto
1978//              false: En caso de ocurrir algún error
1979// ________________________________________________________________________________________________________
1980//
1981static bool RESPUESTA_RestaurarImagen(TRAMA* ptrTrama, struct og_client *cli)
1982{
1983        char msglog[LONSTD];
1984        Database db;
1985        Table tbl;
1986        bool res;
1987        char *iph, *ido, *idi, *dsk, *par, *ifs, *cfg;
1988
1989        if (!db.Open(usuario, pasguor, datasource, catalog)) {
1990                db.GetErrorErrStr(msglog);
1991                syslog(LOG_ERR, "cannot open connection database (%s:%d) %s\n",
1992                       __func__, __LINE__, msglog);
1993                return false;
1994        }
1995
1996        iph = copiaParametro("iph",ptrTrama); // Toma dirección ip
1997        ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
1998
1999        if (!respuestaEstandar(ptrTrama, iph, ido, db, tbl)) {
2000                liberaMemoria(iph);
2001                liberaMemoria(ido);
2002                syslog(LOG_ERR, "failed to register notification\n");
2003                return false;
2004        }
2005
2006        // Acciones posteriores
2007        idi = copiaParametro("idi",ptrTrama); // Toma identificador de la imagen
2008        dsk = copiaParametro("dsk",ptrTrama); // Número de disco
2009        par = copiaParametro("par",ptrTrama); // Número de partición
2010        ifs = copiaParametro("ifs",ptrTrama); // Identificador del perfil software contenido
2011        cfg = copiaParametro("cfg",ptrTrama); // Configuración de discos
2012        if(cfg){
2013                actualizaConfiguracion(db, tbl, cfg, atoi(ido)); // Actualiza la configuración del ordenador
2014                liberaMemoria(cfg);     
2015        }
2016        res=actualizaRestauracionImagen(db, tbl, idi, dsk, par, ido, ifs);
2017       
2018        liberaMemoria(iph);
2019        liberaMemoria(ido);
2020        liberaMemoria(idi);
2021        liberaMemoria(par);
2022        liberaMemoria(ifs);
2023
2024        if(!res){
2025                syslog(LOG_ERR, "Problem after restoring image\n");
2026                db.Close();
2027                return false;
2028        }
2029
2030        db.Close(); // Cierra conexión
2031        return true;
2032}
2033// ________________________________________________________________________________________________________
2034//
2035// Función: RESPUESTA_RestaurarImagenBasica
2036//
2037//      Descripción:
2038//              Respuesta del cliente al comando RestaurarImagen
2039//      Parámetros:
2040//              - socket_c: Socket del cliente que envió el mensaje
2041//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
2042//      Devuelve:
2043//              true: Si el proceso es correcto
2044//              false: En caso de ocurrir algún error
2045// ________________________________________________________________________________________________________
2046//
2047static bool RESPUESTA_RestaurarImagenBasica(TRAMA* ptrTrama, struct og_client *cli)
2048{
2049        return RESPUESTA_RestaurarImagen(ptrTrama, cli);
2050}
2051// ________________________________________________________________________________________________________
2052// Función: RESPUESTA_RestaurarSoftIncremental
2053//
2054//      Descripción:
2055//              Respuesta del cliente al comando RestaurarSoftIncremental
2056//      Parámetros:
2057//              - socket_c: Socket del cliente que envió el mensaje
2058//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
2059//      Devuelve:
2060//              true: Si el proceso es correcto
2061//              false: En caso de ocurrir algún error
2062// ________________________________________________________________________________________________________
2063static bool RESPUESTA_RestaurarSoftIncremental(TRAMA* ptrTrama, struct og_client *cli)
2064{
2065        return RESPUESTA_RestaurarImagen(ptrTrama, cli);
2066}
2067// ________________________________________________________________________________________________________
2068// Función: actualizaRestauracionImagen
2069//
2070//      Descripción:
2071//              Esta función actualiza la base de datos con el resultado de la restauración de una imagen
2072//      Parámetros:
2073//              - db: Objeto base de datos (ya operativo)
2074//              - tbl: Objeto tabla
2075//              - idi: Identificador de la imagen
2076//              - dsk: Disco de donde se restauró
2077//              - par: Partición de donde se restauró
2078//              - ido: Identificador del cliente donde se restauró
2079//              - ifs: Identificador del perfil software contenido      en la imagen
2080//      Devuelve:
2081//              true: Si el proceso es correcto
2082//              false: En caso de ocurrir algún error
2083// ________________________________________________________________________________________________________
2084bool actualizaRestauracionImagen(Database db, Table tbl, char *idi,
2085                                 char *dsk, char *par, char *ido, char *ifs)
2086{
2087        char msglog[LONSTD], sqlstr[LONSQL];
2088
2089        /* Actualizar los datos de la imagen */
2090        snprintf(sqlstr, LONSQL,
2091                        "UPDATE ordenadores_particiones"
2092                        "   SET idimagen=%s, idperfilsoft=%s, fechadespliegue=NOW(),"
2093                        "       revision=(SELECT revision FROM imagenes WHERE idimagen=%s),"
2094                        "       idnombreso=IFNULL((SELECT idnombreso FROM perfilessoft WHERE idperfilsoft=%s),0)"
2095                        " WHERE idordenador=%s AND numdisk=%s AND numpar=%s", idi, ifs, idi, ifs, ido, dsk, par);
2096
2097        if (!db.Execute(sqlstr, tbl)) {
2098                db.GetErrorErrStr(msglog);
2099                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2100                       __func__, __LINE__, msglog);
2101                return false;
2102        }
2103        return true;
2104}
2105// ________________________________________________________________________________________________________
2106// Función: Configurar
2107//
2108//      Descripción:
2109//              Configura la tabla de particiones
2110//      Parámetros:
2111//              - socket_c: Socket de la consola al envió el mensaje
2112//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
2113//      Devuelve:
2114//              true: Si el proceso es correcto
2115//              false: En caso de ocurrir algún error
2116// ________________________________________________________________________________________________________
2117static bool Configurar(TRAMA* ptrTrama, struct og_client *cli)
2118{
2119        if (!enviaComando(ptrTrama, CLIENTE_OCUPADO)) {
2120                respuestaConsola(og_client_socket(cli), ptrTrama, false);
2121                return false;
2122        }
2123        respuestaConsola(og_client_socket(cli), ptrTrama, true);
2124        return true;
2125}
2126// ________________________________________________________________________________________________________
2127// Función: RESPUESTA_Configurar
2128//
2129//      Descripción:
2130//              Respuesta del cliente al comando Configurar
2131//      Parámetros:
2132//              - socket_c: Socket del cliente que envió el mensaje
2133//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
2134//      Devuelve:
2135//              true: Si el proceso es correcto
2136//              false: En caso de ocurrir algún error
2137// ________________________________________________________________________________________________________
2138//
2139static bool RESPUESTA_Configurar(TRAMA* ptrTrama, struct og_client *ci)
2140{
2141        char msglog[LONSTD];
2142        Database db;
2143        Table tbl;
2144        bool res;
2145        char *iph, *ido,*cfg;
2146
2147        if (!db.Open(usuario, pasguor, datasource, catalog)) {
2148                db.GetErrorErrStr(msglog);
2149                syslog(LOG_ERR, "cannot open connection database (%s:%d) %s\n",
2150                       __func__, __LINE__, msglog);
2151                return false;
2152        }
2153
2154        iph = copiaParametro("iph",ptrTrama); // Toma dirección ip
2155        ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
2156
2157        if (!respuestaEstandar(ptrTrama, iph, ido, db, tbl)) {
2158                liberaMemoria(iph);
2159                liberaMemoria(ido);
2160                syslog(LOG_ERR, "failed to register notification\n");
2161                return false;
2162        }
2163
2164        cfg = copiaParametro("cfg",ptrTrama); // Toma configuración de particiones
2165        res=actualizaConfiguracion(db, tbl, cfg, atoi(ido)); // Actualiza la configuración del ordenador
2166       
2167        liberaMemoria(iph);
2168        liberaMemoria(ido);     
2169        liberaMemoria(cfg);     
2170
2171        if(!res){
2172                syslog(LOG_ERR, "Problem updating client configuration\n");
2173                return false;
2174        }
2175
2176        db.Close(); // Cierra conexión
2177        return true;
2178}
2179// ________________________________________________________________________________________________________
2180// Función: EjecutarScript
2181//
2182//      Descripción:
2183//              Ejecuta un script de código
2184//      Parámetros:
2185//              - socket_c: Socket de la consola al envió el mensaje
2186//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
2187//      Devuelve:
2188//              true: Si el proceso es correcto
2189//              false: En caso de ocurrir algún error
2190// ________________________________________________________________________________________________________
2191static bool EjecutarScript(TRAMA* ptrTrama, struct og_client *cli)
2192{
2193        if (!enviaComando(ptrTrama, CLIENTE_OCUPADO)) {
2194                respuestaConsola(og_client_socket(cli), ptrTrama, false);
2195                return false;
2196        }
2197        respuestaConsola(og_client_socket(cli), ptrTrama, true);
2198        return true;
2199}
2200// ________________________________________________________________________________________________________
2201// Función: RESPUESTA_EjecutarScript
2202//
2203//      Descripción:
2204//              Respuesta del cliente al comando EjecutarScript
2205//      Parámetros:
2206//              - socket_c: Socket del cliente que envió el mensaje
2207//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
2208//      Devuelve:
2209//              true: Si el proceso es correcto
2210//              false: En caso de ocurrir algún error
2211// ________________________________________________________________________________________________________
2212static bool RESPUESTA_EjecutarScript(TRAMA* ptrTrama, struct og_client *cli)
2213{
2214        char msglog[LONSTD];
2215        Database db;
2216        Table tbl;
2217        char *iph, *ido,*cfg;
2218
2219        if (!db.Open(usuario, pasguor, datasource, catalog)) {
2220                db.GetErrorErrStr(msglog);
2221                syslog(LOG_ERR, "cannot open connection database (%s:%d) %s\n",
2222                       __func__, __LINE__, msglog);
2223                return false;
2224        }
2225
2226        iph = copiaParametro("iph",ptrTrama); // Toma dirección ip
2227        ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
2228
2229        if (!respuestaEstandar(ptrTrama, iph, ido, db, tbl)) {
2230                liberaMemoria(iph);
2231                liberaMemoria(ido);
2232                syslog(LOG_ERR, "failed to register notification\n");
2233                return false;
2234        }
2235       
2236        cfg = copiaParametro("cfg",ptrTrama); // Toma configuración de particiones
2237        if(cfg){
2238                actualizaConfiguracion(db, tbl, cfg, atoi(ido)); // Actualiza la configuración del ordenador
2239                liberaMemoria(cfg);     
2240        }
2241
2242        liberaMemoria(iph);
2243        liberaMemoria(ido);
2244
2245       
2246        db.Close(); // Cierra conexión
2247        return true;
2248}
2249// ________________________________________________________________________________________________________
2250// Función: InventarioHardware
2251//
2252//      Descripción:
2253//              Solicita al cliente un inventario de su hardware
2254//      Parámetros:
2255//              - socket_c: Socket de la consola al envió el mensaje
2256//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
2257//      Devuelve:
2258//              true: Si el proceso es correcto
2259//              false: En caso de ocurrir algún error
2260// ________________________________________________________________________________________________________
2261static bool InventarioHardware(TRAMA* ptrTrama, struct og_client *cli)
2262{
2263        if (!enviaComando(ptrTrama, CLIENTE_OCUPADO)) {
2264                respuestaConsola(og_client_socket(cli), ptrTrama, false);
2265                return false;
2266        }
2267        respuestaConsola(og_client_socket(cli), ptrTrama, true);
2268        return true;
2269}
2270// ________________________________________________________________________________________________________
2271// Función: RESPUESTA_InventarioHardware
2272//
2273//      Descripción:
2274//              Respuesta del cliente al comando InventarioHardware
2275//      Parámetros:
2276//              - socket_c: Socket del cliente que envió el mensaje
2277//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
2278//      Devuelve:
2279//              true: Si el proceso es correcto
2280//              false: En caso de ocurrir algún error
2281// ________________________________________________________________________________________________________
2282static bool RESPUESTA_InventarioHardware(TRAMA* ptrTrama, struct og_client *cli)
2283{
2284        char msglog[LONSTD];
2285        Database db;
2286        Table tbl;
2287        bool res;
2288        char *iph, *ido, *idc, *npc, *hrd, *buffer;
2289
2290        if (!db.Open(usuario, pasguor, datasource, catalog)) {
2291                db.GetErrorErrStr(msglog);
2292                syslog(LOG_ERR, "cannot open connection database (%s:%d) %s\n",
2293                       __func__, __LINE__, msglog);
2294                return false;
2295        }
2296
2297        iph = copiaParametro("iph",ptrTrama); // Toma dirección ip del cliente
2298        ido = copiaParametro("ido",ptrTrama); // Toma identificador del cliente
2299
2300        if (!respuestaEstandar(ptrTrama, iph, ido, db, tbl)) {
2301                liberaMemoria(iph);
2302                liberaMemoria(ido);
2303                syslog(LOG_ERR, "failed to register notification\n");
2304                return false;
2305        }
2306        // Lee archivo de inventario enviado anteriormente
2307        hrd = copiaParametro("hrd",ptrTrama);
2308        buffer = rTrim(leeArchivo(hrd));
2309       
2310        npc = copiaParametro("npc",ptrTrama); 
2311        idc = copiaParametro("idc",ptrTrama); // Toma identificador del Centro
2312       
2313        if (buffer) 
2314                res=actualizaHardware(db, tbl, buffer, ido, npc, idc);
2315       
2316        liberaMemoria(iph);
2317        liberaMemoria(ido);                     
2318        liberaMemoria(npc);                     
2319        liberaMemoria(idc);             
2320        liberaMemoria(buffer);         
2321       
2322        if(!res){
2323                syslog(LOG_ERR, "Problem updating client configuration\n");
2324                return false;
2325        }
2326               
2327        db.Close(); // Cierra conexión
2328        return true;
2329}
2330// ________________________________________________________________________________________________________
2331// Función: actualizaHardware
2332//
2333//              Descripción:
2334//                      Actualiza la base de datos con la configuracion hardware del cliente
2335//              Parámetros:
2336//                      - db: Objeto base de datos (ya operativo)
2337//                      - tbl: Objeto tabla
2338//                      - hrd: cadena con el inventario hardware
2339//                      - ido: Identificador del ordenador
2340//                      - npc: Nombre del ordenador
2341//                      - idc: Identificador del centro o Unidad organizativa
2342// ________________________________________________________________________________________________________
2343//
2344bool actualizaHardware(Database db, Table tbl, char *hrd, char *ido, char *npc,
2345                       char *idc)
2346{
2347        char msglog[LONSTD], sqlstr[LONSQL];
2348        int idtipohardware, idperfilhard;
2349        int lon, i, j, aux;
2350        bool retval;
2351        char *whard;
2352        int tbidhardware[MAXHARDWARE];
2353        char *tbHardware[MAXHARDWARE],*dualHardware[2], descripcion[250], strInt[LONINT], *idhardwares;
2354
2355        /* Toma Centro (Unidad Organizativa) */
2356        sprintf(sqlstr, "SELECT * FROM ordenadores WHERE idordenador=%s", ido);
2357
2358        if (!db.Execute(sqlstr, tbl)) {
2359                db.GetErrorErrStr(msglog);
2360                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2361                       __func__, __LINE__, msglog);
2362                return false;
2363        }
2364        if (!tbl.Get("idperfilhard", idperfilhard)) { // Toma dato
2365                tbl.GetErrorErrStr(msglog); // Error al acceder al registro
2366                og_info(msglog);
2367                return false;
2368        }
2369        whard=escaparCadena(hrd); // Codificar comillas simples
2370        if(!whard)
2371                return false;
2372        /* Recorre componentes hardware*/
2373        lon = splitCadena(tbHardware, whard, '\n');
2374        if (lon > MAXHARDWARE)
2375                lon = MAXHARDWARE; // Limita el número de componentes hardware
2376        /*
2377         for (i=0;i<lon;i++){
2378         sprintf(msglog,"Linea de inventario: %s",tbHardware[i]);
2379         RegistraLog(msglog,false);
2380         }
2381         */
2382        for (i = 0; i < lon; i++) {
2383                splitCadena(dualHardware, rTrim(tbHardware[i]), '=');
2384                //sprintf(msglog,"nemonico: %s",dualHardware[0]);
2385                //RegistraLog(msglog,false);
2386                //sprintf(msglog,"valor: %s",dualHardware[1]);
2387                //RegistraLog(msglog,false);
2388                sprintf(sqlstr, "SELECT idtipohardware,descripcion FROM tipohardwares "
2389                        " WHERE nemonico='%s'", dualHardware[0]);
2390                if (!db.Execute(sqlstr, tbl)) {
2391                        db.GetErrorErrStr(msglog);
2392                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2393                               __func__, __LINE__, msglog);
2394                        return false;
2395                }
2396                if (tbl.ISEOF()) { //  Tipo de Hardware NO existente
2397                        sprintf(msglog, "%s: %s)", tbErrores[54], dualHardware[0]);
2398                        og_info(msglog);
2399                        return false;
2400                } else { //  Tipo de Hardware Existe
2401                        if (!tbl.Get("idtipohardware", idtipohardware)) { // Toma dato
2402                                tbl.GetErrorErrStr(msglog); // Error al acceder al registro
2403                                og_info(msglog);
2404                                return false;
2405                        }
2406                        if (!tbl.Get("descripcion", descripcion)) { // Toma dato
2407                                tbl.GetErrorErrStr(msglog); // Error al acceder al registro
2408                                og_info(msglog);
2409                                return false;
2410                        }
2411
2412                        sprintf(sqlstr, "SELECT idhardware FROM hardwares "
2413                                " WHERE idtipohardware=%d AND descripcion='%s'",
2414                                        idtipohardware, dualHardware[1]);
2415
2416                        if (!db.Execute(sqlstr, tbl)) {
2417                                db.GetErrorErrStr(msglog);
2418                                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2419                                       __func__, __LINE__, msglog);
2420                                return false;
2421                        }
2422
2423                        if (tbl.ISEOF()) { //  Hardware NO existente
2424                                sprintf(sqlstr, "INSERT hardwares (idtipohardware,descripcion,idcentro,grupoid) "
2425                                                        " VALUES(%d,'%s',%s,0)", idtipohardware,
2426                                                dualHardware[1], idc);
2427                                if (!db.Execute(sqlstr, tbl)) { // Error al insertar
2428                                        db.GetErrorErrStr(msglog); // Error al acceder al registro
2429                                        og_info(msglog);
2430                                        return false;
2431                                }
2432                                // Recupera el identificador del hardware
2433                                sprintf(sqlstr, "SELECT LAST_INSERT_ID() as identificador");
2434                                if (!db.Execute(sqlstr, tbl)) {
2435                                        db.GetErrorErrStr(msglog);
2436                                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2437                                               __func__, __LINE__, msglog);
2438                                        return false;
2439                                }
2440                                if (!tbl.ISEOF()) { // Si existe registro
2441                                        if (!tbl.Get("identificador", tbidhardware[i])) {
2442                                                tbl.GetErrorErrStr(msglog); // Error al acceder al registro
2443                                                og_info(msglog);
2444                                                return false;
2445                                        }
2446                                }
2447                        } else {
2448                                if (!tbl.Get("idhardware", tbidhardware[i])) { // Toma dato
2449                                        tbl.GetErrorErrStr(msglog); // Error al acceder al registro
2450                                        og_info(msglog);
2451                                        return false;
2452                                }
2453                        }
2454                }
2455        }
2456        // Ordena tabla de identificadores para cosultar si existe un pefil con esas especificaciones
2457
2458        for (i = 0; i < lon - 1; i++) {
2459                for (j = i + 1; j < lon; j++) {
2460                        if (tbidhardware[i] > tbidhardware[j]) {
2461                                aux = tbidhardware[i];
2462                                tbidhardware[i] = tbidhardware[j];
2463                                tbidhardware[j] = aux;
2464                        }
2465                }
2466        }
2467        /* Crea cadena de identificadores de componentes hardware separados por coma */
2468        sprintf(strInt, "%d", tbidhardware[lon - 1]); // Pasa a cadena el último identificador que es de mayor longitud
2469        aux = strlen(strInt); // Calcula longitud de cadena para reservar espacio a todos los perfiles
2470        idhardwares = reservaMemoria(sizeof(aux) * lon + lon);
2471        if (idhardwares == NULL) {
2472                syslog(LOG_ERR, "%s:%d OOM\n", __FILE__, __LINE__);
2473                return false;
2474        }
2475        aux = sprintf(idhardwares, "%d", tbidhardware[0]);
2476        for (i = 1; i < lon; i++)
2477                aux += sprintf(idhardwares + aux, ",%d", tbidhardware[i]);
2478
2479        if (!cuestionPerfilHardware(db, tbl, idc, ido, idperfilhard, idhardwares,
2480                        npc, tbidhardware, lon)) {
2481                syslog(LOG_ERR, "Problem updating client hardware\n");
2482                retval=false;
2483        }
2484        else {
2485                retval=true;
2486        }
2487        liberaMemoria(whard);
2488        liberaMemoria(idhardwares);
2489        return (retval);
2490}
2491// ________________________________________________________________________________________________________
2492// Función: cuestionPerfilHardware
2493//
2494//              Descripción:
2495//                      Comprueba existencia de perfil hardware y actualización de éste para el ordenador
2496//              Parámetros:
2497//                      - db: Objeto base de datos (ya operativo)
2498//                      - tbl: Objeto tabla
2499//                      - idc: Identificador de la Unidad organizativa donde se encuentra el cliente
2500//                      - ido: Identificador del ordenador
2501//                      - tbidhardware: Identificador del tipo de hardware
2502//                      - con: Número de componentes detectados para configurar un el perfil hardware
2503//                      - npc: Nombre del cliente
2504// ________________________________________________________________________________________________________
2505bool cuestionPerfilHardware(Database db, Table tbl, char *idc, char *ido,
2506                int idperfilhardware, char *idhardwares, char *npc, int *tbidhardware,
2507                int lon)
2508{
2509        char msglog[LONSTD], *sqlstr;
2510        int i;
2511        int nwidperfilhard;
2512
2513        sqlstr = reservaMemoria(strlen(idhardwares)+LONSQL); // Reserva para escribir sentencia SQL
2514        if (sqlstr == NULL) {
2515                syslog(LOG_ERR, "%s:%d OOM\n", __FILE__, __LINE__);
2516                return false;
2517        }
2518        // Busca perfil hard del ordenador que contenga todos los componentes hardware encontrados
2519        sprintf(sqlstr, "SELECT idperfilhard FROM"
2520                " (SELECT perfileshard_hardwares.idperfilhard as idperfilhard,"
2521                "       group_concat(cast(perfileshard_hardwares.idhardware AS char( 11) )"
2522                "       ORDER BY perfileshard_hardwares.idhardware SEPARATOR ',' ) AS idhardwares"
2523                " FROM  perfileshard_hardwares"
2524                " GROUP BY perfileshard_hardwares.idperfilhard) AS temp"
2525                " WHERE idhardwares LIKE '%s'", idhardwares);
2526
2527        if (!db.Execute(sqlstr, tbl)) {
2528                db.GetErrorErrStr(msglog);
2529                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2530                       __func__, __LINE__, msglog);
2531                liberaMemoria(sqlstr);
2532                return false;
2533        }
2534        if (tbl.ISEOF()) { // No existe un perfil hardware con esos componentes de componentes hardware, lo crea
2535                sprintf(sqlstr, "INSERT perfileshard  (descripcion,idcentro,grupoid)"
2536                                " VALUES('Perfil hardware (%s) ',%s,0)", npc, idc);
2537                if (!db.Execute(sqlstr, tbl)) { // Error al insertar
2538                        db.GetErrorErrStr(msglog);
2539                        og_info(msglog);
2540                        liberaMemoria(sqlstr);
2541                        return false;
2542                }
2543                // Recupera el identificador del nuevo perfil hardware
2544                sprintf(sqlstr, "SELECT LAST_INSERT_ID() as identificador");
2545                if (!db.Execute(sqlstr, tbl)) { // Error al leer
2546                        db.GetErrorErrStr(msglog);
2547                        og_info(msglog);
2548                        liberaMemoria(sqlstr);
2549                        return false;
2550                }
2551                if (!tbl.ISEOF()) { // Si existe registro
2552                        if (!tbl.Get("identificador", nwidperfilhard)) {
2553                                tbl.GetErrorErrStr(msglog);
2554                                og_info(msglog);
2555                                liberaMemoria(sqlstr);
2556                                return false;
2557                        }
2558                }
2559                // Crea la relación entre perfiles y componenetes hardware
2560                for (i = 0; i < lon; i++) {
2561                        sprintf(sqlstr, "INSERT perfileshard_hardwares  (idperfilhard,idhardware)"
2562                                                " VALUES(%d,%d)", nwidperfilhard, tbidhardware[i]);
2563                        if (!db.Execute(sqlstr, tbl)) { // Error al insertar
2564                                db.GetErrorErrStr(msglog);
2565                                og_info(msglog);
2566                                liberaMemoria(sqlstr);
2567                                return false;
2568                        }
2569                }
2570        } else { // Existe un perfil con todos esos componentes
2571                if (!tbl.Get("idperfilhard", nwidperfilhard)) {
2572                        tbl.GetErrorErrStr(msglog);
2573                        og_info(msglog);
2574                        liberaMemoria(sqlstr);
2575                        return false;
2576                }
2577        }
2578        if (idperfilhardware != nwidperfilhard) { // No coinciden los perfiles
2579                // Actualiza el identificador del perfil hardware del ordenador
2580                sprintf(sqlstr, "UPDATE ordenadores SET idperfilhard=%d"
2581                        " WHERE idordenador=%s", nwidperfilhard, ido);
2582                if (!db.Execute(sqlstr, tbl)) { // Error al insertar
2583                        db.GetErrorErrStr(msglog);
2584                        og_info(msglog);
2585                        liberaMemoria(sqlstr);
2586                        return false;
2587                }
2588        }
2589        /* Eliminar Relación de hardwares con Perfiles hardware que quedan húerfanos */
2590        sprintf(sqlstr, "DELETE FROM perfileshard_hardwares WHERE idperfilhard IN "
2591                " (SELECT idperfilhard FROM perfileshard WHERE idperfilhard NOT IN"
2592                " (SELECT DISTINCT idperfilhard from ordenadores))");
2593        if (!db.Execute(sqlstr, tbl)) { // Error al insertar
2594                db.GetErrorErrStr(msglog);
2595                og_info(msglog);
2596                liberaMemoria(sqlstr);
2597                return false;
2598        }
2599
2600        /* Eliminar Perfiles hardware que quedan húerfanos */
2601        sprintf(sqlstr, "DELETE FROM perfileshard WHERE idperfilhard NOT IN"
2602                        " (SELECT DISTINCT idperfilhard FROM ordenadores)");
2603        if (!db.Execute(sqlstr, tbl)) { // Error al insertar
2604                db.GetErrorErrStr(msglog);
2605                og_info(msglog);
2606                liberaMemoria(sqlstr);
2607                return false;
2608        }
2609        /* Eliminar Relación de hardwares con Perfiles hardware que quedan húerfanos */
2610        sprintf(sqlstr, "DELETE FROM perfileshard_hardwares WHERE idperfilhard NOT IN"
2611                        " (SELECT idperfilhard FROM perfileshard)");
2612        if (!db.Execute(sqlstr, tbl)) { // Error al insertar
2613                db.GetErrorErrStr(msglog);
2614                og_info(msglog);
2615                liberaMemoria(sqlstr);
2616                return false;
2617        }
2618        liberaMemoria(sqlstr);
2619        return true;
2620}
2621// ________________________________________________________________________________________________________
2622// Función: InventarioSoftware
2623//
2624//      Descripción:
2625//              Solicita al cliente un inventario de su software
2626//      Parámetros:
2627//              - socket_c: Socket de la consola al envió el mensaje
2628//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
2629//      Devuelve:
2630//              true: Si el proceso es correcto
2631//              false: En caso de ocurrir algún error
2632// ________________________________________________________________________________________________________
2633static bool InventarioSoftware(TRAMA* ptrTrama, struct og_client *cli)
2634{
2635        if (!enviaComando(ptrTrama, CLIENTE_OCUPADO)) {
2636                respuestaConsola(og_client_socket(cli), ptrTrama, false);
2637                return false;
2638        }
2639        respuestaConsola(og_client_socket(cli), ptrTrama, true);
2640        return true;
2641}
2642// ________________________________________________________________________________________________________
2643// Función: RESPUESTA_InventarioSoftware
2644//
2645//      Descripción:
2646//              Respuesta del cliente al comando InventarioSoftware
2647//      Parámetros:
2648//              - socket_c: Socket del cliente que envió el mensaje
2649//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
2650//      Devuelve:
2651//              true: Si el proceso es correcto
2652//              false: En caso de ocurrir algún error
2653// ________________________________________________________________________________________________________
2654static bool RESPUESTA_InventarioSoftware(TRAMA* ptrTrama, struct og_client *cli)
2655{
2656        char msglog[LONSTD];
2657        Database db;
2658        Table tbl;
2659        bool res;
2660        char *iph, *ido, *npc, *idc, *par, *sft, *buffer;
2661
2662        if (!db.Open(usuario, pasguor, datasource, catalog)) {
2663                db.GetErrorErrStr(msglog);
2664                syslog(LOG_ERR, "cannot open connection database (%s:%d) %s\n",
2665                       __func__, __LINE__, msglog);
2666                return false;
2667        }
2668
2669        iph = copiaParametro("iph",ptrTrama); // Toma dirección ip
2670        ido = copiaParametro("ido",ptrTrama); // Toma identificador del ordenador
2671
2672        if (!respuestaEstandar(ptrTrama, iph, ido, db, tbl)) {
2673                liberaMemoria(iph);
2674                liberaMemoria(ido);
2675                syslog(LOG_ERR, "failed to register notification\n");
2676                return false;
2677        }
2678
2679        npc = copiaParametro("npc",ptrTrama); 
2680        idc = copiaParametro("idc",ptrTrama); // Toma identificador del Centro 
2681        par = copiaParametro("par",ptrTrama);
2682        sft = copiaParametro("sft",ptrTrama);
2683
2684        buffer = rTrim(leeArchivo(sft));
2685        if (buffer)
2686                res=actualizaSoftware(db, tbl, buffer, par, ido, npc, idc);
2687
2688        liberaMemoria(iph);
2689        liberaMemoria(ido);     
2690        liberaMemoria(npc);     
2691        liberaMemoria(idc);     
2692        liberaMemoria(par);     
2693        liberaMemoria(sft);     
2694
2695        if(!res){
2696                syslog(LOG_ERR, "cannot update software\n");
2697                return false;
2698        }
2699
2700        db.Close(); // Cierra conexión
2701        return true;
2702}
2703// ________________________________________________________________________________________________________
2704// Función: actualizaSoftware
2705//
2706//      Descripción:
2707//              Actualiza la base de datos con la configuración software del cliente
2708//      Parámetros:
2709//              - db: Objeto base de datos (ya operativo)
2710//              - tbl: Objeto tabla
2711//              - sft: cadena con el inventario software
2712//              - par: Número de la partición
2713//              - ido: Identificador del ordenador del cliente en la tabla
2714//              - npc: Nombre del ordenador
2715//              - idc: Identificador del centro o Unidad organizativa
2716//      Devuelve:
2717//              true: Si el proceso es correcto
2718//              false: En caso de ocurrir algún error
2719//
2720//      Versión 1.1.0: Se incluye el sistema operativo. Autora: Irina Gómez - ETSII Universidad Sevilla
2721// ________________________________________________________________________________________________________
2722bool actualizaSoftware(Database db, Table tbl, char *sft, char *par,char *ido,
2723                       char *npc, char *idc)
2724{
2725        int i, j, lon, aux, idperfilsoft, idnombreso;
2726        bool retval;
2727        char *wsft;
2728        int tbidsoftware[MAXSOFTWARE];
2729        char *tbSoftware[MAXSOFTWARE],msglog[LONSTD], sqlstr[LONSQL], strInt[LONINT], *idsoftwares;
2730
2731        /* Toma Centro (Unidad Organizativa) y perfil software */
2732        sprintf(sqlstr, "SELECT idperfilsoft,numpar"
2733                " FROM ordenadores_particiones"
2734                " WHERE idordenador=%s", ido);
2735
2736        if (!db.Execute(sqlstr, tbl)) {
2737                db.GetErrorErrStr(msglog);
2738                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2739                       __func__, __LINE__, msglog);
2740                return false;
2741        }
2742        idperfilsoft = 0; // Por defecto se supone que el ordenador no tiene aún detectado el perfil software
2743        while (!tbl.ISEOF()) { // Recorre particiones
2744                if (!tbl.Get("numpar", aux)) {
2745                        tbl.GetErrorErrStr(msglog);
2746                        og_info(msglog);
2747                        return false;
2748                }
2749                if (aux == atoi(par)) { // Se encuentra la partición
2750                        if (!tbl.Get("idperfilsoft", idperfilsoft)) {
2751                                tbl.GetErrorErrStr(msglog);
2752                                og_info(msglog);
2753                                return false;
2754                        }
2755                        break;
2756                }
2757                tbl.MoveNext();
2758        }
2759        wsft=escaparCadena(sft); // Codificar comillas simples
2760        if(!wsft)
2761                return false;
2762
2763        /* Recorre componentes software*/
2764        lon = splitCadena(tbSoftware, wsft, '\n');
2765
2766        if (lon == 0)
2767                return true; // No hay lineas que procesar
2768        if (lon > MAXSOFTWARE)
2769                lon = MAXSOFTWARE; // Limita el número de componentes software
2770
2771        for (i = 0; i < lon; i++) {
2772                // Primera línea es el sistema operativo: se obtiene identificador
2773                if (i == 0) {
2774                        idnombreso = checkDato(db, tbl, rTrim(tbSoftware[i]), "nombresos", "nombreso", "idnombreso");
2775                        continue;
2776                }
2777
2778                sprintf(sqlstr,
2779                                "SELECT idsoftware FROM softwares WHERE descripcion ='%s'",
2780                                rTrim(tbSoftware[i]));
2781
2782                if (!db.Execute(sqlstr, tbl)) {
2783                        db.GetErrorErrStr(msglog);
2784                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2785                               __func__, __LINE__, msglog);
2786                        return false;
2787                }
2788
2789                if (tbl.ISEOF()) { //  Software NO existente
2790                        sprintf(sqlstr, "INSERT INTO softwares (idtiposoftware,descripcion,idcentro,grupoid)"
2791                                                " VALUES(2,'%s',%s,0)", tbSoftware[i], idc);
2792
2793                        if (!db.Execute(sqlstr, tbl)) { // Error al insertar
2794                                db.GetErrorErrStr(msglog); // Error al acceder al registro
2795                                og_info(msglog);
2796                                return false;
2797                        }
2798                        // Recupera el identificador del software
2799                        sprintf(sqlstr, "SELECT LAST_INSERT_ID() as identificador");
2800                        if (!db.Execute(sqlstr, tbl)) { // Error al leer
2801                                db.GetErrorErrStr(msglog); // Error al acceder al registro
2802                                og_info(msglog);
2803                                return false;
2804                        }
2805                        if (!tbl.ISEOF()) { // Si existe registro
2806                                if (!tbl.Get("identificador", tbidsoftware[i])) {
2807                                        tbl.GetErrorErrStr(msglog); // Error al acceder al registro
2808                                        og_info(msglog);
2809                                        return false;
2810                                }
2811                        }
2812                } else {
2813                        if (!tbl.Get("idsoftware", tbidsoftware[i])) { // Toma dato
2814                                tbl.GetErrorErrStr(msglog); // Error al acceder al registro
2815                                og_info(msglog);
2816                                return false;
2817                        }
2818                }
2819        }
2820
2821        // Ordena tabla de identificadores para cosultar si existe un pefil con esas especificaciones
2822
2823        for (i = 0; i < lon - 1; i++) {
2824                for (j = i + 1; j < lon; j++) {
2825                        if (tbidsoftware[i] > tbidsoftware[j]) {
2826                                aux = tbidsoftware[i];
2827                                tbidsoftware[i] = tbidsoftware[j];
2828                                tbidsoftware[j] = aux;
2829                        }
2830                }
2831        }
2832        /* Crea cadena de identificadores de componentes software separados por coma */
2833        sprintf(strInt, "%d", tbidsoftware[lon - 1]); // Pasa a cadena el último identificador que es de mayor longitud
2834        aux = strlen(strInt); // Calcula longitud de cadena para reservar espacio a todos los perfiles
2835        idsoftwares = reservaMemoria((sizeof(aux)+1) * lon + lon);
2836        if (idsoftwares == NULL) {
2837                syslog(LOG_ERR, "%s:%d OOM\n", __FILE__, __LINE__);
2838                return false;
2839        }
2840        aux = sprintf(idsoftwares, "%d", tbidsoftware[0]);
2841        for (i = 1; i < lon; i++)
2842                aux += sprintf(idsoftwares + aux, ",%d", tbidsoftware[i]);
2843
2844        // Comprueba existencia de perfil software y actualización de éste para el ordenador
2845        if (!cuestionPerfilSoftware(db, tbl, idc, ido, idperfilsoft, idnombreso, idsoftwares, 
2846                        npc, par, tbidsoftware, lon)) {
2847                syslog(LOG_ERR, "cannot update software\n");
2848                og_info(msglog);
2849                retval=false;
2850        }
2851        else {
2852                retval=true;
2853        }
2854        liberaMemoria(wsft);
2855        liberaMemoria(idsoftwares);
2856        return (retval);
2857}
2858// ________________________________________________________________________________________________________
2859// Función: CuestionPerfilSoftware
2860//
2861//      Parámetros:
2862//              - db: Objeto base de datos (ya operativo)
2863//              - tbl: Objeto tabla
2864//              - idcentro: Identificador del centro en la tabla
2865//              - ido: Identificador del ordenador del cliente en la tabla
2866//              - idnombreso: Identificador del sistema operativo
2867//              - idsoftwares: Cadena con los identificadores de componentes software separados por comas
2868//              - npc: Nombre del ordenador del cliente
2869//              - particion: Número de la partición
2870//              - tbidsoftware: Array con los identificadores de componentes software
2871//              - lon: Número de componentes
2872//      Devuelve:
2873//              true: Si el proceso es correcto
2874//              false: En caso de ocurrir algún error
2875//
2876//      Versión 1.1.0: Se incluye el sistema operativo. Autora: Irina Gómez - ETSII Universidad Sevilla
2877//_________________________________________________________________________________________________________
2878bool cuestionPerfilSoftware(Database db, Table tbl, char *idc, char *ido,
2879                            int idperfilsoftware, int idnombreso,
2880                            char *idsoftwares, char *npc, char *par,
2881                            int *tbidsoftware, int lon)
2882{
2883        char *sqlstr, msglog[LONSTD];
2884        int i, nwidperfilsoft;
2885
2886        sqlstr = reservaMemoria(strlen(idsoftwares)+LONSQL); // Reserva para escribir sentencia SQL
2887        if (sqlstr == NULL) {
2888                syslog(LOG_ERR, "%s:%d OOM\n", __FILE__, __LINE__);
2889                return false;
2890        }
2891        // Busca perfil soft del ordenador que contenga todos los componentes software encontrados
2892        sprintf(sqlstr, "SELECT idperfilsoft FROM"
2893                " (SELECT perfilessoft_softwares.idperfilsoft as idperfilsoft,"
2894                "       group_concat(cast(perfilessoft_softwares.idsoftware AS char( 11) )"
2895                "       ORDER BY perfilessoft_softwares.idsoftware SEPARATOR ',' ) AS idsoftwares"
2896                " FROM  perfilessoft_softwares"
2897                " GROUP BY perfilessoft_softwares.idperfilsoft) AS temp"
2898                " WHERE idsoftwares LIKE '%s'", idsoftwares);
2899
2900        if (!db.Execute(sqlstr, tbl)) {
2901                db.GetErrorErrStr(msglog);
2902                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2903                       __func__, __LINE__, msglog);
2904                liberaMemoria(sqlstr);
2905                return false;
2906        }
2907        if (tbl.ISEOF()) { // No existe un perfil software con esos componentes de componentes software, lo crea
2908                sprintf(sqlstr, "INSERT perfilessoft  (descripcion, idcentro, grupoid, idnombreso)"
2909                                " VALUES('Perfil Software (%s, Part:%s) ',%s,0,%i)", npc, par, idc,idnombreso);
2910                if (!db.Execute(sqlstr, tbl)) { // Error al insertar
2911                        db.GetErrorErrStr(msglog);
2912                        og_info(msglog);
2913                        return false;
2914                }
2915                // Recupera el identificador del nuevo perfil software
2916                sprintf(sqlstr, "SELECT LAST_INSERT_ID() as identificador");
2917                if (!db.Execute(sqlstr, tbl)) { // Error al leer
2918                        tbl.GetErrorErrStr(msglog);
2919                        og_info(msglog);
2920                        liberaMemoria(sqlstr);
2921                        return false;
2922                }
2923                if (!tbl.ISEOF()) { // Si existe registro
2924                        if (!tbl.Get("identificador", nwidperfilsoft)) {
2925                                tbl.GetErrorErrStr(msglog);
2926                                og_info(msglog);
2927                                liberaMemoria(sqlstr);
2928                                return false;
2929                        }
2930                }
2931                // Crea la relación entre perfiles y componenetes software
2932                for (i = 0; i < lon; i++) {
2933                        sprintf(sqlstr, "INSERT perfilessoft_softwares (idperfilsoft,idsoftware)"
2934                                                " VALUES(%d,%d)", nwidperfilsoft, tbidsoftware[i]);
2935                        if (!db.Execute(sqlstr, tbl)) { // Error al insertar
2936                                db.GetErrorErrStr(msglog);
2937                                og_info(msglog);
2938                                liberaMemoria(sqlstr);
2939                                return false;
2940                        }
2941                }
2942        } else { // Existe un perfil con todos esos componentes
2943                if (!tbl.Get("idperfilsoft", nwidperfilsoft)) {
2944                        tbl.GetErrorErrStr(msglog);
2945                        og_info(msglog);
2946                        liberaMemoria(sqlstr);
2947                        return false;
2948                }
2949        }
2950
2951        if (idperfilsoftware != nwidperfilsoft) { // No coinciden los perfiles
2952                // Actualiza el identificador del perfil software del ordenador
2953                sprintf(sqlstr, "UPDATE ordenadores_particiones SET idperfilsoft=%d,idimagen=0"
2954                                " WHERE idordenador=%s AND numpar=%s", nwidperfilsoft, ido, par);
2955                if (!db.Execute(sqlstr, tbl)) { // Error al insertar
2956                        db.GetErrorErrStr(msglog);
2957                        og_info(msglog);
2958                        liberaMemoria(sqlstr);
2959                        return false;
2960                }
2961        }
2962
2963        /* DEPURACIÓN DE PERFILES SOFTWARE */
2964
2965         /* Eliminar Relación de softwares con Perfiles software que quedan húerfanos */
2966        sprintf(sqlstr, "DELETE FROM perfilessoft_softwares WHERE idperfilsoft IN "\
2967                " (SELECT idperfilsoft FROM perfilessoft WHERE idperfilsoft NOT IN"\
2968                " (SELECT DISTINCT idperfilsoft from ordenadores_particiones) AND idperfilsoft NOT IN"\
2969                " (SELECT DISTINCT idperfilsoft from imagenes))");
2970        if (!db.Execute(sqlstr, tbl)) { // Error al insertar
2971                db.GetErrorErrStr(msglog);
2972                og_info(msglog);
2973                liberaMemoria(sqlstr);
2974                return false;
2975        }
2976        /* Eliminar Perfiles software que quedan húerfanos */
2977        sprintf(sqlstr, "DELETE FROM perfilessoft WHERE idperfilsoft NOT IN"
2978                " (SELECT DISTINCT idperfilsoft from ordenadores_particiones)"\
2979                " AND  idperfilsoft NOT IN"\
2980                " (SELECT DISTINCT idperfilsoft from imagenes)");
2981        if (!db.Execute(sqlstr, tbl)) { // Error al insertar
2982                db.GetErrorErrStr(msglog);
2983                og_info(msglog);
2984                liberaMemoria(sqlstr);
2985                return false;
2986        }
2987        /* Eliminar Relación de softwares con Perfiles software que quedan húerfanos */
2988        sprintf(sqlstr, "DELETE FROM perfilessoft_softwares WHERE idperfilsoft NOT IN"
2989                        " (SELECT idperfilsoft from perfilessoft)");
2990        if (!db.Execute(sqlstr, tbl)) { // Error al insertar
2991                db.GetErrorErrStr(msglog);
2992                og_info(msglog);
2993                liberaMemoria(sqlstr);
2994                return false;
2995        }
2996        liberaMemoria(sqlstr);
2997        return true;
2998}
2999// ________________________________________________________________________________________________________
3000// Función: enviaArchivo
3001//
3002//      Descripción:
3003//              Envia un archivo por la red, por bloques
3004//      Parámetros:
3005//              - socket_c: Socket del cliente que envió el mensaje
3006//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
3007//      Devuelve:
3008//              true: Si el proceso es correcto
3009//              false: En caso de ocurrir algún error
3010// ________________________________________________________________________________________________________
3011static bool enviaArchivo(TRAMA *ptrTrama, struct og_client *cli)
3012{
3013        int socket_c = og_client_socket(cli);
3014        char *nfl;
3015
3016        // Toma parámetros
3017        nfl = copiaParametro("nfl",ptrTrama); // Toma nombre completo del archivo
3018        if (!sendArchivo(&socket_c, nfl)) {
3019                liberaMemoria(nfl);
3020                syslog(LOG_ERR, "Problem sending file\n");
3021                return false;
3022        }
3023        liberaMemoria(nfl);
3024        return true;
3025}
3026// ________________________________________________________________________________________________________
3027// Función: enviaArchivo
3028//
3029//      Descripción:
3030//              Envia un archivo por la red, por bloques
3031//      Parámetros:
3032//              - socket_c: Socket del cliente que envió el mensaje
3033//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
3034//      Devuelve:
3035//              true: Si el proceso es correcto
3036//              false: En caso de ocurrir algún error
3037// ________________________________________________________________________________________________________
3038static bool recibeArchivo(TRAMA *ptrTrama, struct og_client *cli)
3039{
3040        int socket_c = og_client_socket(cli);
3041        char *nfl;
3042
3043        // Toma parámetros
3044        nfl = copiaParametro("nfl",ptrTrama); // Toma nombre completo del archivo
3045        ptrTrama->tipo = MSG_NOTIFICACION;
3046        enviaFlag(&socket_c, ptrTrama);
3047        if (!recArchivo(&socket_c, nfl)) {
3048                liberaMemoria(nfl);
3049                syslog(LOG_ERR, "Problem receiving file\n");
3050                return false;
3051        }
3052        liberaMemoria(nfl);
3053        return true;
3054}
3055// ________________________________________________________________________________________________________
3056// Función: envioProgramacion
3057//
3058//      Descripción:
3059//              Envia un comando de actualización a todos los ordenadores que han sido programados con
3060//              alguna acción para que entren en el bucle de comandos pendientes y las ejecuten
3061//      Parámetros:
3062//              - socket_c: Socket del cliente que envió el mensaje
3063//              - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros
3064//      Devuelve:
3065//              true: Si el proceso es correcto
3066//              false: En caso de ocurrir algún error
3067// ________________________________________________________________________________________________________
3068static bool envioProgramacion(TRAMA *ptrTrama, struct og_client *cli)
3069{
3070        char *ptrIP[MAXIMOS_CLIENTES],*ptrMacs[MAXIMOS_CLIENTES];
3071        char sqlstr[LONSQL], msglog[LONSTD];
3072        char *idp,iph[LONIP],mac[LONMAC];
3073        Database db;
3074        Table tbl;
3075        int idx,idcomando,lon;
3076
3077        if (!db.Open(usuario, pasguor, datasource, catalog)) {
3078                db.GetErrorErrStr(msglog);
3079                syslog(LOG_ERR, "cannot open connection database (%s:%d) %s\n",
3080                       __func__, __LINE__, msglog);
3081                return false;
3082        }
3083
3084        idp = copiaParametro("idp",ptrTrama); // Toma identificador de la programación de la tabla acciones
3085
3086        sprintf(sqlstr, "SELECT ordenadores.ip,ordenadores.mac,acciones.idcomando FROM acciones "\
3087                        " INNER JOIN ordenadores ON ordenadores.ip=acciones.ip"\
3088                        " WHERE acciones.idprogramacion=%s",idp);
3089       
3090        liberaMemoria(idp);
3091
3092        if (!db.Execute(sqlstr, tbl)) {
3093                db.GetErrorErrStr(msglog);
3094                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3095                       __func__, __LINE__, msglog);
3096                return false;
3097        }
3098        db.Close();
3099        if(tbl.ISEOF())
3100                return true; // No existen registros
3101
3102        /* Prepara la trama de actualizacion */
3103
3104        initParametros(ptrTrama,0);
3105        ptrTrama->tipo=MSG_COMANDO;
3106        sprintf(ptrTrama->parametros, "nfn=Actualizar\r");
3107
3108        while (!tbl.ISEOF()) { // Recorre particiones
3109                if (!tbl.Get("ip", iph)) {
3110                        tbl.GetErrorErrStr(msglog);
3111                        syslog(LOG_ERR, "cannot find ip column in table: %s\n",
3112                               msglog);
3113                        return false;
3114                }
3115                if (!tbl.Get("idcomando", idcomando)) {
3116                        tbl.GetErrorErrStr(msglog);
3117                        syslog(LOG_ERR, "cannot find idcomando column in table: %s\n",
3118                               msglog);
3119                        return false;
3120                }
3121                if(idcomando==1){ // Arrancar
3122                        if (!tbl.Get("mac", mac)) {
3123                                tbl.GetErrorErrStr(msglog);
3124                                syslog(LOG_ERR, "cannot find mac column in table: %s\n",
3125                                       msglog);
3126                                return false;
3127                        }
3128
3129                        lon = splitCadena(ptrIP, iph, ';');
3130                        lon = splitCadena(ptrMacs, mac, ';');
3131
3132                        // Se manda por broadcast y por unicast
3133                        if (!Levanta(ptrIP, ptrMacs, lon, (char*)"1"))
3134                                return false;
3135
3136                        if (!Levanta(ptrIP, ptrMacs, lon, (char*)"2"))
3137                                return false;
3138
3139                }
3140                if (clienteDisponible(iph, &idx)) { // Si el cliente puede recibir comandos
3141                        int sock = tbsockets[idx].cli ? tbsockets[idx].cli->io.fd : -1;
3142
3143                        strcpy(tbsockets[idx].estado, CLIENTE_OCUPADO); // Actualiza el estado del cliente
3144                        if (!mandaTrama(&sock, ptrTrama)) {
3145                                syslog(LOG_ERR, "failed to send response: %s\n",
3146                                       strerror(errno));
3147                                return false;
3148                        }
3149                        //close(tbsockets[idx].sock); // Cierra el socket del cliente hasta nueva disponibilidad
3150                }
3151                tbl.MoveNext();
3152        }
3153        return true; // No existen registros
3154}
3155
3156// This object stores function handler for messages
3157static struct {
3158        const char *nf; // Nombre de la función
3159        bool (*fcn)(TRAMA *, struct og_client *cli);
3160} tbfuncionesServer[] = {
3161        { "InclusionCliente",                   InclusionCliente,       },
3162        { "InclusionClienteWinLnx",             InclusionClienteWinLnx, },
3163        { "AutoexecCliente",                    AutoexecCliente,        },
3164        { "ComandosPendientes",                 ComandosPendientes,     },
3165        { "DisponibilidadComandos",             DisponibilidadComandos, },
3166        { "RESPUESTA_Arrancar",                 RESPUESTA_Arrancar,     },
3167        { "Apagar",                             Apagar,                 },
3168        { "RESPUESTA_Apagar",                   RESPUESTA_Apagar,       },
3169        { "RESPUESTA_Reiniciar",                RESPUESTA_Reiniciar,    },
3170        { "RESPUESTA_IniciarSesion",            RESPUESTA_IniciarSesion, },
3171        { "CrearImagen",                        CrearImagen,            },
3172        { "RESPUESTA_CrearImagen",              RESPUESTA_CrearImagen,  },
3173        { "CrearImagenBasica",                  CrearImagenBasica,      },
3174        { "RESPUESTA_CrearImagenBasica",        RESPUESTA_CrearImagenBasica, },
3175        { "CrearSoftIncremental",               CrearSoftIncremental,   },
3176        { "RESPUESTA_CrearSoftIncremental",     RESPUESTA_CrearSoftIncremental, },
3177        { "RestaurarImagen",                    RestaurarImagen,        },
3178        { "RESPUESTA_RestaurarImagen",          RESPUESTA_RestaurarImagen },
3179        { "RestaurarImagenBasica",              RestaurarImagenBasica, },
3180        { "RESPUESTA_RestaurarImagenBasica",    RESPUESTA_RestaurarImagenBasica, },
3181        { "RestaurarSoftIncremental",           RestaurarSoftIncremental, },
3182        { "RESPUESTA_RestaurarSoftIncremental", RESPUESTA_RestaurarSoftIncremental, },
3183        { "Configurar",                         Configurar,             },
3184        { "RESPUESTA_Configurar",               RESPUESTA_Configurar,   },
3185        { "EjecutarScript",                     EjecutarScript,         },
3186        { "RESPUESTA_EjecutarScript",           RESPUESTA_EjecutarScript, },
3187        { "InventarioHardware",                 InventarioHardware,     },
3188        { "RESPUESTA_InventarioHardware",       RESPUESTA_InventarioHardware, },
3189        { "InventarioSoftware",                 InventarioSoftware      },
3190        { "RESPUESTA_InventarioSoftware",       RESPUESTA_InventarioSoftware, },
3191        { "enviaArchivo",                       enviaArchivo,           },
3192        { "recibeArchivo",                      recibeArchivo,          },
3193        { "envioProgramacion",                  envioProgramacion,      },
3194        { NULL,                                 NULL,                   },
3195};
3196
3197// ________________________________________________________________________________________________________
3198// Función: gestionaTrama
3199//
3200//              Descripción:
3201//                      Procesa las tramas recibidas .
3202//              Parametros:
3203//                      - s : Socket usado para comunicaciones
3204//      Devuelve:
3205//              true: Si el proceso es correcto
3206//              false: En caso de ocurrir algún error
3207// ________________________________________________________________________________________________________
3208static void gestionaTrama(TRAMA *ptrTrama, struct og_client *cli)
3209{
3210        int i, res;
3211        char *nfn;
3212
3213        if (ptrTrama){
3214                INTROaFINCAD(ptrTrama);
3215                nfn = copiaParametro("nfn",ptrTrama); // Toma nombre de la función
3216
3217                for (i = 0; tbfuncionesServer[i].fcn; i++) {
3218                        if (!strncmp(tbfuncionesServer[i].nf, nfn,
3219                                     strlen(tbfuncionesServer[i].nf))) {
3220                                res = tbfuncionesServer[i].fcn(ptrTrama, cli);
3221                                if (!res) {
3222                                        syslog(LOG_ERR, "Failed handling of %s for client %s:%hu\n",
3223                                               tbfuncionesServer[i].nf,
3224                                               inet_ntoa(cli->addr.sin_addr),
3225                                               ntohs(cli->addr.sin_port));
3226                                } else {
3227                                        syslog(LOG_DEBUG, "Successful handling of %s for client %s:%hu\n",
3228                                               tbfuncionesServer[i].nf,
3229                                               inet_ntoa(cli->addr.sin_addr),
3230                                               ntohs(cli->addr.sin_port));
3231                                }
3232                                break;
3233                        }
3234                }
3235                if (!tbfuncionesServer[i].fcn)
3236                        syslog(LOG_ERR, "unknown request %s from client %s:%hu\n",
3237                               nfn, inet_ntoa(cli->addr.sin_addr),
3238                               ntohs(cli->addr.sin_port));
3239
3240                liberaMemoria(nfn);
3241        }
3242}
3243
3244static void og_client_release(struct ev_loop *loop, struct og_client *cli)
3245{
3246        if (cli->keepalive_idx >= 0) {
3247                syslog(LOG_DEBUG, "closing keepalive connection for %s:%hu in slot %d\n",
3248                       inet_ntoa(cli->addr.sin_addr),
3249                       ntohs(cli->addr.sin_port), cli->keepalive_idx);
3250                tbsockets[cli->keepalive_idx].cli = NULL;
3251        }
3252
3253        ev_io_stop(loop, &cli->io);
3254        close(cli->io.fd);
3255        free(cli);
3256}
3257
3258static void og_client_keepalive(struct ev_loop *loop, struct og_client *cli)
3259{
3260        struct og_client *old_cli;
3261
3262        old_cli = tbsockets[cli->keepalive_idx].cli;
3263        if (old_cli && old_cli != cli) {
3264                syslog(LOG_DEBUG, "closing old keepalive connection for %s:%hu\n",
3265                       inet_ntoa(old_cli->addr.sin_addr),
3266                       ntohs(old_cli->addr.sin_port));
3267
3268                og_client_release(loop, old_cli);
3269        }
3270        tbsockets[cli->keepalive_idx].cli = cli;
3271}
3272
3273static void og_client_reset_state(struct og_client *cli)
3274{
3275        cli->state = OG_CLIENT_RECEIVING_HEADER;
3276        cli->buf_len = 0;
3277}
3278
3279static int og_client_state_recv_hdr(struct og_client *cli)
3280{
3281        char hdrlen[LONHEXPRM];
3282
3283        /* Still too short to validate protocol fingerprint and message
3284         * length.
3285         */
3286        if (cli->buf_len < 15 + LONHEXPRM)
3287                return 0;
3288
3289        if (strncmp(cli->buf, "@JMMLCAMDJ_MCDJ", 15)) {
3290                syslog(LOG_ERR, "bad fingerprint from client %s:%hu, closing\n",
3291                       inet_ntoa(cli->addr.sin_addr),
3292                       ntohs(cli->addr.sin_port));
3293                return -1;
3294        }
3295
3296        memcpy(hdrlen, &cli->buf[LONGITUD_CABECERATRAMA], LONHEXPRM);
3297        cli->msg_len = strtol(hdrlen, NULL, 16);
3298
3299        /* Header announces more that we can fit into buffer. */
3300        if (cli->msg_len >= sizeof(cli->buf)) {
3301                syslog(LOG_ERR, "too large message %u bytes from %s:%hu\n",
3302                       cli->msg_len, inet_ntoa(cli->addr.sin_addr),
3303                       ntohs(cli->addr.sin_port));
3304                return -1;
3305        }
3306
3307        return 1;
3308}
3309
3310static TRAMA *og_msg_alloc(char *data, unsigned int len)
3311{
3312        TRAMA *ptrTrama;
3313
3314        ptrTrama = (TRAMA *)reservaMemoria(sizeof(TRAMA));
3315        if (!ptrTrama) {
3316                syslog(LOG_ERR, "OOM\n");
3317                return NULL;
3318        }
3319
3320        initParametros(ptrTrama, len);
3321        memcpy(ptrTrama, "@JMMLCAMDJ_MCDJ", LONGITUD_CABECERATRAMA);
3322        memcpy(ptrTrama->parametros, data, len);
3323        ptrTrama->lonprm = len;
3324
3325        return ptrTrama;
3326}
3327
3328static void og_msg_free(TRAMA *ptrTrama)
3329{
3330        liberaMemoria(ptrTrama->parametros);
3331        liberaMemoria(ptrTrama);
3332}
3333
3334static int og_client_state_process_payload(struct og_client *cli)
3335{
3336        TRAMA *ptrTrama;
3337        char *data;
3338        int len;
3339
3340        len = cli->msg_len - (LONGITUD_CABECERATRAMA + LONHEXPRM);
3341        data = &cli->buf[LONGITUD_CABECERATRAMA + LONHEXPRM];
3342
3343        ptrTrama = og_msg_alloc(data, len);
3344        if (!ptrTrama)
3345                return -1;
3346
3347        gestionaTrama(ptrTrama, cli);
3348
3349        og_msg_free(ptrTrama);
3350
3351        return 1;
3352}
3353
3354#define OG_CLIENTS_MAX  4096
3355
3356struct og_msg_params {
3357        const char      *ips_array[OG_CLIENTS_MAX];
3358        const char      *mac_array[OG_CLIENTS_MAX];
3359        unsigned int    ips_array_len;
3360        const char      *wol_type;
3361        char            run_cmd[4096];
3362        const char      *disk;
3363        const char      *partition;
3364};
3365
3366static int og_json_parse_clients(json_t *element, struct og_msg_params *params)
3367{
3368        unsigned int i;
3369        json_t *k;
3370
3371        if (json_typeof(element) != JSON_ARRAY)
3372                return -1;
3373
3374        for (i = 0; i < json_array_size(element); i++) {
3375                k = json_array_get(element, i);
3376                if (json_typeof(k) != JSON_STRING)
3377                        return -1;
3378
3379                params->ips_array[params->ips_array_len++] =
3380                        json_string_value(k);
3381        }
3382        return 0;
3383}
3384
3385static int og_cmd_legacy_send(struct og_msg_params *params, const char *cmd,
3386                              const char *state)
3387{
3388        char buf[4096] = {};
3389        int len, err = 0;
3390        TRAMA *msg;
3391
3392        len = snprintf(buf, sizeof(buf), "nfn=%s\r", cmd);
3393
3394        msg = og_msg_alloc(buf, len);
3395        if (!msg)
3396                return -1;
3397
3398        if (!og_send_cmd((char **)params->ips_array, params->ips_array_len,
3399                         state, msg))
3400                err = -1;
3401
3402        og_msg_free(msg);
3403
3404        return err;
3405}
3406
3407static int og_cmd_post_clients(json_t *element, struct og_msg_params *params)
3408{
3409        const char *key;
3410        json_t *value;
3411        int err = 0;
3412
3413        if (json_typeof(element) != JSON_OBJECT)
3414                return -1;
3415
3416        json_object_foreach(element, key, value) {
3417                if (!strcmp(key, "clients"))
3418                        err = og_json_parse_clients(value, params);
3419
3420                if (err < 0)
3421                        break;
3422        }
3423
3424        return og_cmd_legacy_send(params, "Sondeo", CLIENTE_APAGADO);
3425}
3426
3427struct og_buffer {
3428        char    *data;
3429        int     len;
3430};
3431
3432static int og_json_dump_clients(const char *buffer, size_t size, void *data)
3433{
3434        struct og_buffer *og_buffer = (struct og_buffer *)data;
3435
3436        memcpy(og_buffer->data + og_buffer->len, buffer, size);
3437        og_buffer->len += size;
3438
3439        return 0;
3440}
3441
3442static int og_cmd_get_clients(json_t *element, struct og_msg_params *params,
3443                              char *buffer_reply)
3444{
3445        json_t *root, *array, *addr, *state, *object;
3446        struct og_buffer og_buffer = {
3447                .data   = buffer_reply,
3448        };
3449        int i;
3450
3451        array = json_array();
3452        if (!array)
3453                return -1;
3454
3455        for (i = 0; i < MAXIMOS_CLIENTES; i++) {
3456                if (tbsockets[i].ip[0] == '\0')
3457                        continue;
3458
3459                object = json_object();
3460                if (!object) {
3461                        json_decref(array);
3462                        return -1;
3463                }
3464                addr = json_string(tbsockets[i].ip);
3465                if (!addr) {
3466                        json_decref(object);
3467                        json_decref(array);
3468                        return -1;
3469                }
3470                json_object_set_new(object, "addr", addr);
3471
3472                state = json_string(tbsockets[i].estado);
3473                if (!state) {
3474                        json_decref(object);
3475                        json_decref(array);
3476                        return -1;
3477                }
3478                json_object_set_new(object, "state", state);
3479
3480                json_array_append_new(array, object);
3481        }
3482        root = json_pack("{s:o}", "clients", array);
3483        if (!root) {
3484                json_decref(array);
3485                return -1;
3486        }
3487
3488        json_dump_callback(root, og_json_dump_clients, &og_buffer, 0);
3489        json_decref(root);
3490
3491        return 0;
3492}
3493
3494static int og_json_parse_target(json_t *element, struct og_msg_params *params)
3495{
3496        const char *key;
3497        json_t *value;
3498
3499        if (json_typeof(element) != JSON_OBJECT) {
3500                return -1;
3501        }
3502
3503        json_object_foreach(element, key, value) {
3504                if (!strcmp(key, "addr")) {
3505                        if (json_typeof(value) != JSON_STRING)
3506                                return -1;
3507
3508                        params->ips_array[params->ips_array_len] =
3509                                json_string_value(value);
3510                } else if (!strcmp(key, "mac")) {
3511                        if (json_typeof(value) != JSON_STRING)
3512                                return -1;
3513
3514                        params->mac_array[params->ips_array_len] =
3515                                json_string_value(value);
3516                }
3517        }
3518
3519        return 0;
3520}
3521
3522static int og_json_parse_targets(json_t *element, struct og_msg_params *params)
3523{
3524        unsigned int i;
3525        json_t *k;
3526        int err;
3527
3528        if (json_typeof(element) != JSON_ARRAY)
3529                return -1;
3530
3531        for (i = 0; i < json_array_size(element); i++) {
3532                k = json_array_get(element, i);
3533
3534                if (json_typeof(k) != JSON_OBJECT)
3535                        return -1;
3536
3537                err = og_json_parse_target(k, params);
3538                if (err < 0)
3539                        return err;
3540
3541                params->ips_array_len++;
3542        }
3543        return 0;
3544}
3545
3546static int og_json_parse_type(json_t *element, struct og_msg_params *params)
3547{
3548        const char *type;
3549
3550        if (json_typeof(element) != JSON_STRING)
3551                return -1;
3552
3553        params->wol_type = json_string_value(element);
3554
3555        type = json_string_value(element);
3556        if (!strcmp(type, "unicast"))
3557                params->wol_type = "2";
3558        else if (!strcmp(type, "broadcast"))
3559                params->wol_type = "1";
3560
3561        return 0;
3562}
3563
3564static int og_cmd_wol(json_t *element, struct og_msg_params *params)
3565{
3566        const char *key;
3567        json_t *value;
3568        int err = 0;
3569
3570        if (json_typeof(element) != JSON_OBJECT)
3571                return -1;
3572
3573        json_object_foreach(element, key, value) {
3574                if (!strcmp(key, "clients")) {
3575                        err = og_json_parse_targets(value, params);
3576                } else if (!strcmp(key, "type")) {
3577                        err = og_json_parse_type(value, params);
3578                }
3579
3580                if (err < 0)
3581                        break;
3582        }
3583
3584        if (!Levanta((char **)params->ips_array, (char **)params->mac_array,
3585                     params->ips_array_len, (char *)params->wol_type))
3586                return -1;
3587
3588        return 0;
3589}
3590
3591static int og_json_parse_run(json_t *element, struct og_msg_params *params)
3592{
3593        if (json_typeof(element) != JSON_STRING)
3594                return -1;
3595
3596        snprintf(params->run_cmd, sizeof(params->run_cmd), "%s",
3597                 json_string_value(element));
3598
3599        return 0;
3600}
3601
3602static int og_cmd_run_post(json_t *element, struct og_msg_params *params)
3603{
3604        char buf[4096] = {}, iph[4096] = {};
3605        int err = 0, len;
3606        const char *key;
3607        unsigned int i;
3608        json_t *value;
3609        TRAMA *msg;
3610
3611        if (json_typeof(element) != JSON_OBJECT)
3612                return -1;
3613
3614        json_object_foreach(element, key, value) {
3615                if (!strcmp(key, "clients"))
3616                        err = og_json_parse_clients(value, params);
3617                if (!strcmp(key, "run"))
3618                        err = og_json_parse_run(value, params);
3619
3620                if (err < 0)
3621                        break;
3622        }
3623
3624        for (i = 0; i < params->ips_array_len; i++) {
3625                len = snprintf(iph + strlen(iph), sizeof(iph), "%s;",
3626                               params->ips_array[i]);
3627        }
3628        len = snprintf(buf, sizeof(buf), "nfn=ConsolaRemota\riph=%s\rscp=%s\r",
3629                       iph, params->run_cmd);
3630
3631        msg = og_msg_alloc(buf, len);
3632        if (!msg)
3633                return -1;
3634
3635        if (!og_send_cmd((char **)params->ips_array, params->ips_array_len,
3636                         CLIENTE_OCUPADO, msg))
3637                err = -1;
3638
3639        og_msg_free(msg);
3640
3641        if (err < 0)
3642                return err;
3643
3644        for (i = 0; i < params->ips_array_len; i++) {
3645                char filename[4096];
3646                FILE *f;
3647
3648                sprintf(filename, "/tmp/_Seconsola_%s", params->ips_array[i]);
3649                f = fopen(filename, "wt");
3650                fclose(f);
3651        }
3652
3653        return 0;
3654}
3655
3656static int og_cmd_run_get(json_t *element, struct og_msg_params *params,
3657                          char *buffer_reply)
3658{
3659        struct og_buffer og_buffer = {
3660                .data   = buffer_reply,
3661        };
3662        json_t *root, *value, *array;
3663        const char *key;
3664        unsigned int i;
3665        int err = 0;
3666
3667        if (json_typeof(element) != JSON_OBJECT)
3668                return -1;
3669
3670        json_object_foreach(element, key, value) {
3671                if (!strcmp(key, "clients"))
3672                        err = og_json_parse_clients(value, params);
3673
3674                if (err < 0)
3675                        return err;
3676        }
3677
3678        array = json_array();
3679        if (!array)
3680                return -1;
3681
3682        for (i = 0; i < params->ips_array_len; i++) {
3683                json_t *object, *output, *addr;
3684                char data[4096] = {};
3685                char filename[4096];
3686                int fd, numbytes;
3687
3688                sprintf(filename, "/tmp/_Seconsola_%s", params->ips_array[i]);
3689
3690                fd = open(filename, O_RDONLY);
3691                if (!fd)
3692                        return -1;
3693
3694                numbytes = read(fd, data, sizeof(data));
3695                if (numbytes < 0) {
3696                        close(fd);
3697                        return -1;
3698                }
3699                data[sizeof(data) - 1] = '\0';
3700                close(fd);
3701
3702                object = json_object();
3703                if (!object) {
3704                        json_decref(array);
3705                        return -1;
3706                }
3707                addr = json_string(params->ips_array[i]);
3708                if (!addr) {
3709                        json_decref(object);
3710                        json_decref(array);
3711                        return -1;
3712                }
3713                json_object_set_new(object, "addr", addr);
3714
3715                output = json_string(data);
3716                if (!output) {
3717                        json_decref(object);
3718                        json_decref(array);
3719                        return -1;
3720                }
3721                json_object_set_new(object, "output", output);
3722
3723                json_array_append_new(array, object);
3724        }
3725
3726        root = json_pack("{s:o}", "clients", array);
3727        if (!root)
3728                return -1;
3729
3730        json_dump_callback(root, og_json_dump_clients, &og_buffer, 0);
3731        json_decref(root);
3732
3733        return 0;
3734}
3735
3736static int og_json_parse_disk(json_t *element, struct og_msg_params *params)
3737{
3738        if (json_typeof(element) != JSON_STRING)
3739                return -1;
3740
3741        params->disk = json_string_value(element);
3742
3743        return 0;
3744}
3745
3746static int og_json_parse_partition(json_t *element,
3747                                   struct og_msg_params *params)
3748{
3749        if (json_typeof(element) != JSON_STRING)
3750                return -1;
3751
3752        params->partition = json_string_value(element);
3753
3754        return 0;
3755}
3756
3757static int og_cmd_session(json_t *element, struct og_msg_params *params)
3758{
3759        char buf[4096], iph[4096];
3760        int err = 0, len;
3761        const char *key;
3762        unsigned int i;
3763        json_t *value;
3764        TRAMA *msg;
3765
3766        if (json_typeof(element) != JSON_OBJECT)
3767                return -1;
3768
3769        json_object_foreach(element, key, value) {
3770                if (!strcmp(key, "clients")) {
3771                        err = og_json_parse_clients(value, params);
3772                } else if (!strcmp(key, "disk")) {
3773                        err = og_json_parse_disk(value, params);
3774                } else if (!strcmp(key, "partition")) {
3775                        err = og_json_parse_partition(value, params);
3776                }
3777
3778                if (err < 0)
3779                        return err;
3780        }
3781
3782        for (i = 0; i < params->ips_array_len; i++) {
3783                snprintf(iph + strlen(iph), sizeof(iph), "%s;",
3784                         params->ips_array[i]);
3785        }
3786        len = snprintf(buf, sizeof(buf),
3787                       "nfn=IniciarSesion\riph=%s\rdsk=%s\rpar=%s\r",
3788                       iph, params->disk, params->partition);
3789
3790        msg = og_msg_alloc(buf, len);
3791        if (!msg)
3792                return -1;
3793
3794        if (!og_send_cmd((char **)params->ips_array, params->ips_array_len,
3795                         CLIENTE_APAGADO, msg))
3796                err = -1;
3797
3798        og_msg_free(msg);
3799
3800        return 0;
3801}
3802
3803static int og_cmd_poweroff(json_t *element, struct og_msg_params *params)
3804{
3805        const char *key;
3806        json_t *value;
3807        int err = 0;
3808
3809        if (json_typeof(element) != JSON_OBJECT)
3810                return -1;
3811
3812        json_object_foreach(element, key, value) {
3813                if (!strcmp(key, "clients"))
3814                        err = og_json_parse_clients(value, params);
3815
3816                if (err < 0)
3817                        break;
3818        }
3819
3820        return og_cmd_legacy_send(params, "Apagar", CLIENTE_OCUPADO);
3821}
3822
3823static int og_cmd_refresh(json_t *element, struct og_msg_params *params)
3824{
3825        const char *key;
3826        json_t *value;
3827        int err = 0;
3828
3829        if (json_typeof(element) != JSON_OBJECT)
3830                return -1;
3831
3832        json_object_foreach(element, key, value) {
3833                if (!strcmp(key, "clients"))
3834                        err = og_json_parse_clients(value, params);
3835
3836                if (err < 0)
3837                        break;
3838        }
3839
3840        return og_cmd_legacy_send(params, "Actualizar", CLIENTE_APAGADO);
3841}
3842
3843static int og_cmd_reboot(json_t *element, struct og_msg_params *params)
3844{
3845        const char *key;
3846        json_t *value;
3847        int err = 0;
3848
3849        if (json_typeof(element) != JSON_OBJECT)
3850                return -1;
3851
3852        json_object_foreach(element, key, value) {
3853                if (!strcmp(key, "clients"))
3854                        err = og_json_parse_clients(value, params);
3855
3856                if (err < 0)
3857                        break;
3858        }
3859
3860        return og_cmd_legacy_send(params, "Reiniciar", CLIENTE_OCUPADO);
3861}
3862
3863static int og_cmd_stop(json_t *element, struct og_msg_params *params)
3864{
3865        const char *key;
3866        json_t *value;
3867        int err = 0;
3868
3869        if (json_typeof(element) != JSON_OBJECT)
3870                return -1;
3871
3872        json_object_foreach(element, key, value) {
3873                if (!strcmp(key, "clients"))
3874                        err = og_json_parse_clients(value, params);
3875
3876                if (err < 0)
3877                        break;
3878        }
3879
3880        return og_cmd_legacy_send(params, "Purgar", CLIENTE_APAGADO);
3881}
3882
3883static int og_cmd_hardware(json_t *element, struct og_msg_params *params)
3884{
3885        const char *key;
3886        json_t *value;
3887        int err = 0;
3888
3889        if (json_typeof(element) != JSON_OBJECT)
3890                return -1;
3891
3892        json_object_foreach(element, key, value) {
3893                if (!strcmp(key, "clients"))
3894                        err = og_json_parse_clients(value, params);
3895
3896                if (err < 0)
3897                        break;
3898        }
3899
3900        return og_cmd_legacy_send(params, "InventarioHardware",
3901                                  CLIENTE_OCUPADO);
3902}
3903
3904static int og_cmd_software(json_t *element, struct og_msg_params *params)
3905{
3906        const char *key;
3907        json_t *value;
3908        int err = 0;
3909
3910        if (json_typeof(element) != JSON_OBJECT)
3911                return -1;
3912
3913        json_object_foreach(element, key, value) {
3914                if (!strcmp(key, "clients"))
3915                        err = og_json_parse_clients(value, params);
3916
3917                if (err < 0)
3918                        break;
3919        }
3920
3921        return og_cmd_legacy_send(params, "InventarioSoftware",
3922                                  CLIENTE_OCUPADO);
3923}
3924
3925static int og_client_method_not_found(struct og_client *cli)
3926{
3927        /* To meet RFC 7231, this function MUST generate an Allow header field
3928         * containing the correct methods. For example: "Allow: POST\r\n"
3929         */
3930        char buf[] = "HTTP/1.1 405 Method Not Allowed\r\n"
3931                     "Content-Length: 0\r\n\r\n";
3932
3933        send(og_client_socket(cli), buf, strlen(buf), 0);
3934
3935        return -1;
3936}
3937
3938static int og_client_not_found(struct og_client *cli)
3939{
3940        char buf[] = "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n";
3941
3942        send(og_client_socket(cli), buf, strlen(buf), 0);
3943
3944        return -1;
3945}
3946
3947static int og_client_not_authorized(struct og_client *cli)
3948{
3949        char buf[] = "HTTP/1.1 401 Unauthorized\r\n"
3950                     "WWW-Authenticate: Basic\r\n"
3951                     "Content-Length: 0\r\n\r\n";
3952
3953        send(og_client_socket(cli), buf, strlen(buf), 0);
3954
3955        return -1;
3956}
3957
3958static int og_server_internal_error(struct og_client *cli)
3959{
3960        char buf[] = "HTTP/1.1 500 Internal Server Error\r\n"
3961                     "Content-Length: 0\r\n\r\n";
3962
3963        send(og_client_socket(cli), buf, strlen(buf), 0);
3964
3965        return -1;
3966}
3967
3968#define OG_MSG_RESPONSE_MAXLEN  65536
3969
3970static int og_client_ok(struct og_client *cli, char *buf_reply)
3971{
3972        char buf[OG_MSG_RESPONSE_MAXLEN] = {};
3973        int err = 0, len;
3974
3975        len = snprintf(buf, sizeof(buf),
3976                       "HTTP/1.1 200 OK\r\nContent-Length: %ld\r\n\r\n%s",
3977                       strlen(buf_reply), buf_reply);
3978        if (len >= (int)sizeof(buf))
3979                err = og_server_internal_error(cli);
3980
3981        send(og_client_socket(cli), buf, strlen(buf), 0);
3982
3983        return err;
3984}
3985
3986enum og_rest_method {
3987        OG_METHOD_GET   = 0,
3988        OG_METHOD_POST,
3989};
3990
3991static int og_client_state_process_payload_rest(struct og_client *cli)
3992{
3993        char buf_reply[OG_MSG_RESPONSE_MAXLEN] = {};
3994        struct og_msg_params params = {};
3995        enum og_rest_method method;
3996        const char *cmd, *body;
3997        json_error_t json_err;
3998        json_t *root = NULL;
3999        int err = 0;
4000
4001        syslog(LOG_DEBUG, "%s:%hu %.32s ...\n",
4002               inet_ntoa(cli->addr.sin_addr),
4003               ntohs(cli->addr.sin_port), cli->buf);
4004
4005        if (!strncmp(cli->buf, "GET", strlen("GET"))) {
4006                method = OG_METHOD_GET;
4007                cmd = cli->buf + strlen("GET") + 2;
4008        } else if (!strncmp(cli->buf, "POST", strlen("POST"))) {
4009                method = OG_METHOD_POST;
4010                cmd = cli->buf + strlen("POST") + 2;
4011        } else
4012                return og_client_method_not_found(cli);
4013
4014        body = strstr(cli->buf, "\r\n\r\n") + 4;
4015
4016        if (strcmp(cli->auth_token, auth_token)) {
4017                syslog(LOG_ERR, "wrong Authentication key\n");
4018                return og_client_not_authorized(cli);
4019        }
4020
4021        if (cli->content_length) {
4022                root = json_loads(body, 0, &json_err);
4023                if (!root) {
4024                        syslog(LOG_ERR, "malformed json line %d: %s\n",
4025                               json_err.line, json_err.text);
4026                        return og_client_not_found(cli);
4027                }
4028        }
4029
4030        if (!strncmp(cmd, "clients", strlen("clients"))) {
4031                if (method != OG_METHOD_POST &&
4032                    method != OG_METHOD_GET)
4033                        return og_client_method_not_found(cli);
4034
4035                if (method == OG_METHOD_POST && !root) {
4036                        syslog(LOG_ERR, "command clients with no payload\n");
4037                        return og_client_not_found(cli);
4038                }
4039                switch (method) {
4040                case OG_METHOD_POST:
4041                        err = og_cmd_post_clients(root, &params);
4042                        break;
4043                case OG_METHOD_GET:
4044                        err = og_cmd_get_clients(root, &params, buf_reply);
4045                        break;
4046                }
4047        } else if (!strncmp(cmd, "wol", strlen("wol"))) {
4048                if (method != OG_METHOD_POST)
4049                        return og_client_method_not_found(cli);
4050
4051                if (!root) {
4052                        syslog(LOG_ERR, "command wol with no payload\n");
4053                        return og_client_not_found(cli);
4054                }
4055                err = og_cmd_wol(root, &params);
4056        } else if (!strncmp(cmd, "shell/run", strlen("shell/run"))) {
4057                if (method != OG_METHOD_POST)
4058                        return og_client_method_not_found(cli);
4059
4060                if (!root) {
4061                        syslog(LOG_ERR, "command run with no payload\n");
4062                        return og_client_not_found(cli);
4063                }
4064                err = og_cmd_run_post(root, &params);
4065        } else if (!strncmp(cmd, "shell/output", strlen("shell/output"))) {
4066                if (method != OG_METHOD_POST)
4067                        return og_client_method_not_found(cli);
4068
4069                if (!root) {
4070                        syslog(LOG_ERR, "command output with no payload\n");
4071                        return og_client_not_found(cli);
4072                }
4073
4074                err = og_cmd_run_get(root, &params, buf_reply);
4075        } else if (!strncmp(cmd, "session", strlen("session"))) {
4076                if (method != OG_METHOD_POST)
4077                        return og_client_method_not_found(cli);
4078
4079                if (!root) {
4080                        syslog(LOG_ERR, "command session with no payload\n");
4081                        return og_client_not_found(cli);
4082                }
4083                err = og_cmd_session(root, &params);
4084        } else if (!strncmp(cmd, "poweroff", strlen("poweroff"))) {
4085                if (method != OG_METHOD_POST)
4086                        return og_client_method_not_found(cli);
4087
4088                if (!root) {
4089                        syslog(LOG_ERR, "command poweroff with no payload\n");
4090                        return og_client_not_found(cli);
4091                }
4092                err = og_cmd_poweroff(root, &params);
4093        } else if (!strncmp(cmd, "reboot", strlen("reboot"))) {
4094                if (method != OG_METHOD_POST)
4095                        return og_client_method_not_found(cli);
4096
4097                if (!root) {
4098                        syslog(LOG_ERR, "command reboot with no payload\n");
4099                        return og_client_not_found(cli);
4100                }
4101                err = og_cmd_reboot(root, &params);
4102        } else if (!strncmp(cmd, "stop", strlen("stop"))) {
4103                if (method != OG_METHOD_POST)
4104                        return og_client_method_not_found(cli);
4105
4106                if (!root) {
4107                        syslog(LOG_ERR, "command stop with no payload\n");
4108                        return og_client_not_found(cli);
4109                }
4110                err = og_cmd_stop(root, &params);
4111        } else if (!strncmp(cmd, "refresh", strlen("refresh"))) {
4112                if (method != OG_METHOD_POST)
4113                        return og_client_method_not_found(cli);
4114
4115                if (!root) {
4116                        syslog(LOG_ERR, "command refresh with no payload\n");
4117                        return og_client_not_found(cli);
4118                }
4119                err = og_cmd_refresh(root, &params);
4120        } else if (!strncmp(cmd, "hardware", strlen("hardware"))) {
4121                if (method != OG_METHOD_POST)
4122                        return og_client_method_not_found(cli);
4123
4124                if (!root) {
4125                        syslog(LOG_ERR, "command hardware with no payload\n");
4126                        return og_client_not_found(cli);
4127                }
4128                err = og_cmd_hardware(root, &params);
4129        } else if (!strncmp(cmd, "software", strlen("software"))) {
4130                if (method != OG_METHOD_POST)
4131                        return og_client_method_not_found(cli);
4132
4133                if (!root) {
4134                        syslog(LOG_ERR, "command software with no payload\n");
4135                        return og_client_not_found(cli);
4136                }
4137                err = og_cmd_software(root, &params);
4138        } else {
4139                syslog(LOG_ERR, "unknown command: %.32s ...\n", cmd);
4140                err = og_client_not_found(cli);
4141        }
4142
4143        if (root)
4144                json_decref(root);
4145
4146        if (err < 0)
4147                return err;
4148
4149        err = og_client_ok(cli, buf_reply);
4150        if (err < 0) {
4151                syslog(LOG_ERR, "HTTP response to %s:%hu is too large\n",
4152                       inet_ntoa(cli->addr.sin_addr),
4153                       ntohs(cli->addr.sin_port));
4154        }
4155
4156        return err;
4157}
4158
4159static int og_client_state_recv_hdr_rest(struct og_client *cli)
4160{
4161        char *ptr;
4162
4163        ptr = strstr(cli->buf, "\r\n\r\n");
4164        if (!ptr)
4165                return 0;
4166
4167        cli->msg_len = ptr - cli->buf + 4;
4168
4169        ptr = strstr(cli->buf, "Content-Length: ");
4170        if (ptr) {
4171                sscanf(ptr, "Content-Length: %i[^\r\n]", &cli->content_length);
4172                cli->msg_len += cli->content_length;
4173        }
4174
4175        ptr = strstr(cli->buf, "Authorization: ");
4176        if (ptr)
4177                sscanf(ptr, "Authorization: %64[^\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.