source: ogServer-Git/sources/ogAdmServer.cpp @ 95e6520

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

#915 add initial REST API for ogAdmServer

Add REST API for ogAdmServer, this API is exposed through port 8888 on
the system that runs the ogAdmServer. The body of the HTTP message is
expressed in JSON format.

This patch implements the command "clients" that maps to the existing
legacy "Sondeo" command, that is used by the web interface to poll
refresh the client state.

This patch also includes an initial test infrastructure using 'curl' to
send commands to the new REST API.

Request:

POST /clients
{"clients" : [ "192.168.2.1", "192.168.2.2" ]}

Reply:

200 OK

This allows to refresh the status of the list of clients.

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