source: ogServer-Git/sources/ogAdmServer.cpp @ 7b6fcdb

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

#915 add clients command to REST API in ogAdmServer

Request for existing clients:

curl -X GET http://127.0.0.1:8888/clients

Request:

GET /clients

Reply:

200 OK
{"clients": [ { "addr" : "192.168.2.1", "state" : "OPG" }, { "addr" : "192.168.2.2", "state" : "OFF" }]}

  • Property mode set to 100644
File size: 131.2 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
3686struct og_buffer {
3687        char    *data;
3688        int     len;
3689};
3690
3691static int og_json_dump_clients(const char *buffer, size_t size, void *data)
3692{
3693        struct og_buffer *og_buffer = (struct og_buffer *)data;
3694
3695        memcpy(og_buffer->data + og_buffer->len, buffer, size);
3696        og_buffer->len += size;
3697
3698        return 0;
3699}
3700
3701static int og_cmd_get_clients(json_t *element, struct og_msg_params *params,
3702                              char *buffer_reply)
3703{
3704        json_t *root, *array, *addr, *state, *object;
3705        struct og_buffer og_buffer = {
3706                .data   = buffer_reply,
3707        };
3708        int i;
3709
3710        array = json_array();
3711        if (!array)
3712                return -1;
3713
3714        for (i = 0; i < MAXIMOS_CLIENTES; i++) {
3715                if (tbsockets[i].ip[0] == '\0')
3716                        continue;
3717
3718                object = json_object();
3719                if (!object) {
3720                        json_decref(array);
3721                        return -1;
3722                }
3723                addr = json_string(tbsockets[i].ip);
3724                if (!addr) {
3725                        json_decref(object);
3726                        json_decref(array);
3727                        return -1;
3728                }
3729                json_object_set_new(object, "addr", addr);
3730
3731                state = json_string(tbsockets[i].estado);
3732                if (!state) {
3733                        json_decref(object);
3734                        json_decref(array);
3735                        return -1;
3736                }
3737                json_object_set_new(object, "state", state);
3738
3739                json_array_append_new(array, object);
3740        }
3741        root = json_pack("{s:o}", "clients", array);
3742        if (!root) {
3743                json_decref(array);
3744                return -1;
3745        }
3746
3747        json_dump_callback(root, og_json_dump_clients, &og_buffer, 4096);
3748        json_decref(root);
3749
3750        return 0;
3751}
3752
3753static int og_client_not_found(struct og_client *cli)
3754{
3755        char buf[] = "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n";
3756
3757        send(og_client_socket(cli), buf, strlen(buf), 0);
3758
3759        return -1;
3760}
3761
3762static int og_client_ok(struct og_client *cli, char *buf_reply)
3763{
3764        char buf[4096] = {};
3765
3766        sprintf(buf, "HTTP/1.1 200 OK\r\nContent-Length: %ld\r\n\r\n%s",
3767                strlen(buf_reply), buf_reply);
3768
3769        send(og_client_socket(cli), buf, strlen(buf), 0);
3770
3771        return 0;
3772}
3773
3774enum og_rest_method {
3775        OG_METHOD_GET   = 0,
3776        OG_METHOD_POST,
3777};
3778
3779static int og_client_state_process_payload_rest(struct og_client *cli)
3780{
3781        struct og_msg_params params = {};
3782        const char *cmd, *body, *ptr;
3783        enum og_rest_method method;
3784        char buf_reply[4096] = {};
3785        int content_length = 0;
3786        json_error_t json_err;
3787        json_t *root = NULL;
3788        int err = 0;
3789
3790        if (!strncmp(cli->buf, "GET", strlen("GET"))) {
3791                method = OG_METHOD_GET;
3792                cmd = cli->buf + strlen("GET") + 2;
3793        } else if (!strncmp(cli->buf, "POST", strlen("POST"))) {
3794                method = OG_METHOD_POST;
3795                cmd = cli->buf + strlen("POST") + 2;
3796        } else
3797                return -1;
3798
3799        body = strstr(cli->buf, "\r\n\r\n") + 4;
3800
3801        ptr = strstr(cli->buf, "Content-Length: ");
3802        if (ptr)
3803                sscanf(ptr, "Content-Length: %i[^\r\n]", &content_length);
3804
3805        if (content_length) {
3806                root = json_loads(body, 0, &json_err);
3807                if (!root) {
3808                        syslog(LOG_ERR, "malformed json line %d: %s\n",
3809                               json_err.line, json_err.text);
3810                        return og_client_not_found(cli);
3811                }
3812        }
3813
3814        if (!strncmp(cmd, "clients", strlen("clients"))) {
3815                if (method != OG_METHOD_POST &&
3816                    method != OG_METHOD_GET)
3817                        return -1;
3818
3819                if (method == OG_METHOD_POST && !root) {
3820                        syslog(LOG_ERR, "command clients with no payload\n");
3821                        return og_client_not_found(cli);
3822                }
3823                switch (method) {
3824                case OG_METHOD_POST:
3825                        err = og_cmd_post_clients(root, &params);
3826                        break;
3827                case OG_METHOD_GET:
3828                        err = og_cmd_get_clients(root, &params, buf_reply);
3829                        break;
3830                }
3831        } else {
3832                syslog(LOG_ERR, "unknown command %s\n", cmd);
3833                err = og_client_not_found(cli);
3834        }
3835
3836        if (root)
3837                json_decref(root);
3838
3839        if (!err)
3840                og_client_ok(cli, buf_reply);
3841
3842        return err;
3843}
3844
3845static int og_client_state_recv_hdr_rest(struct og_client *cli)
3846{
3847        char *trailer;
3848
3849        trailer = strstr(cli->buf, "\r\n\r\n");
3850        if (!trailer)
3851                return 0;
3852
3853        return 1;
3854}
3855
3856static void og_client_read_cb(struct ev_loop *loop, struct ev_io *io, int events)
3857{
3858        struct og_client *cli;
3859        int ret;
3860
3861        cli = container_of(io, struct og_client, io);
3862
3863        if (events & EV_ERROR) {
3864                syslog(LOG_ERR, "unexpected error event from client %s:%hu\n",
3865                               inet_ntoa(cli->addr.sin_addr),
3866                               ntohs(cli->addr.sin_port));
3867                goto close;
3868        }
3869
3870        ret = recv(io->fd, cli->buf + cli->buf_len,
3871                   sizeof(cli->buf) - cli->buf_len, 0);
3872        if (ret <= 0) {
3873                if (ret < 0) {
3874                        syslog(LOG_ERR, "error reading from client %s:%hu (%s)\n",
3875                               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port),
3876                               strerror(errno));
3877                } else {
3878                        syslog(LOG_DEBUG, "closed connection by %s:%hu\n",
3879                               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
3880                }
3881                goto close;
3882        }
3883
3884        if (cli->keepalive_idx >= 0)
3885                return;
3886
3887        ev_timer_again(loop, &cli->timer);
3888
3889        cli->buf_len += ret;
3890
3891        switch (cli->state) {
3892        case OG_CLIENT_RECEIVING_HEADER:
3893                if (cli->rest)
3894                        ret = og_client_state_recv_hdr_rest(cli);
3895                else
3896                        ret = og_client_state_recv_hdr(cli);
3897
3898                if (ret < 0)
3899                        goto close;
3900                if (!ret)
3901                        return;
3902
3903                cli->state = OG_CLIENT_RECEIVING_PAYLOAD;
3904                /* Fall through. */
3905        case OG_CLIENT_RECEIVING_PAYLOAD:
3906                /* Still not enough data to process request. */
3907                if (cli->buf_len < cli->msg_len)
3908                        return;
3909
3910                cli->state = OG_CLIENT_PROCESSING_REQUEST;
3911                /* fall through. */
3912        case OG_CLIENT_PROCESSING_REQUEST:
3913                syslog(LOG_DEBUG, "processing request from %s:%hu\n",
3914                       inet_ntoa(cli->addr.sin_addr),
3915                       ntohs(cli->addr.sin_port));
3916
3917                if (cli->rest)
3918                        ret = og_client_state_process_payload_rest(cli);
3919                else
3920                        ret = og_client_state_process_payload(cli);
3921                if (ret < 0)
3922                        goto close;
3923
3924                if (cli->keepalive_idx < 0) {
3925                        syslog(LOG_DEBUG, "server closing connection to %s:%hu\n",
3926                               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
3927                        goto close;
3928                } else {
3929                        syslog(LOG_DEBUG, "leaving client %s:%hu in keepalive mode\n",
3930                               inet_ntoa(cli->addr.sin_addr),
3931                               ntohs(cli->addr.sin_port));
3932                        og_client_keepalive(loop, cli);
3933                        og_client_reset_state(cli);
3934                }
3935                break;
3936        default:
3937                syslog(LOG_ERR, "unknown state, critical internal error\n");
3938                goto close;
3939        }
3940        return;
3941close:
3942        ev_timer_stop(loop, &cli->timer);
3943        og_client_release(loop, cli);
3944}
3945
3946static void og_client_timer_cb(struct ev_loop *loop, ev_timer *timer, int events)
3947{
3948        struct og_client *cli;
3949
3950        cli = container_of(timer, struct og_client, timer);
3951        if (cli->keepalive_idx >= 0) {
3952                ev_timer_again(loop, &cli->timer);
3953                return;
3954        }
3955        syslog(LOG_ERR, "timeout request for client %s:%hu\n",
3956               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
3957
3958        og_client_release(loop, cli);
3959}
3960
3961static int socket_s, socket_rest;
3962
3963static void og_server_accept_cb(struct ev_loop *loop, struct ev_io *io,
3964                                int events)
3965{
3966        struct sockaddr_in client_addr;
3967        socklen_t addrlen = sizeof(client_addr);
3968        struct og_client *cli;
3969        int client_sd;
3970
3971        if (events & EV_ERROR)
3972                return;
3973
3974        client_sd = accept(io->fd, (struct sockaddr *)&client_addr, &addrlen);
3975        if (client_sd < 0) {
3976                syslog(LOG_ERR, "cannot accept client connection\n");
3977                return;
3978        }
3979
3980        cli = (struct og_client *)calloc(1, sizeof(struct og_client));
3981        if (!cli) {
3982                close(client_sd);
3983                return;
3984        }
3985        memcpy(&cli->addr, &client_addr, sizeof(client_addr));
3986        cli->keepalive_idx = -1;
3987
3988        if (io->fd == socket_rest)
3989                cli->rest = true;
3990
3991        syslog(LOG_DEBUG, "connection from client %s:%hu\n",
3992               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
3993
3994        ev_io_init(&cli->io, og_client_read_cb, client_sd, EV_READ);
3995        ev_io_start(loop, &cli->io);
3996        ev_timer_init(&cli->timer, og_client_timer_cb, OG_CLIENT_TIMEOUT, 0.);
3997        ev_timer_start(loop, &cli->timer);
3998}
3999
4000static int og_socket_server_init(const char *port)
4001{
4002        struct sockaddr_in local;
4003        int sd, on = 1;
4004
4005        sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
4006        if (sd < 0) {
4007                syslog(LOG_ERR, "cannot create main socket\n");
4008                return -1;
4009        }
4010        setsockopt(sd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(int));
4011
4012        local.sin_addr.s_addr = htonl(INADDR_ANY);
4013        local.sin_family = AF_INET;
4014        local.sin_port = htons(atoi(port));
4015
4016        if (bind(sd, (struct sockaddr *) &local, sizeof(local)) < 0) {
4017                syslog(LOG_ERR, "cannot bind socket\n");
4018                return -1;
4019        }
4020
4021        listen(sd, 250);
4022
4023        return sd;
4024}
4025
4026int main(int argc, char *argv[])
4027{
4028        struct ev_io ev_io_server, ev_io_server_rest;
4029        struct ev_loop *loop = ev_default_loop(0);
4030        int i;
4031
4032        if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
4033                exit(EXIT_FAILURE);
4034
4035        openlog("ogAdmServer", LOG_PID, LOG_DAEMON);
4036
4037        /*--------------------------------------------------------------------------------------------------------
4038         Validación de parámetros de ejecución y lectura del fichero de configuración del servicio
4039         ---------------------------------------------------------------------------------------------------------*/
4040        if (!validacionParametros(argc, argv, 1)) // Valida parámetros de ejecución
4041                exit(EXIT_FAILURE);
4042
4043        if (!tomaConfiguracion(szPathFileCfg)) { // Toma parametros de configuracion
4044                exit(EXIT_FAILURE);
4045        }
4046
4047        /*--------------------------------------------------------------------------------------------------------
4048         // Inicializa array de información de los clientes
4049         ---------------------------------------------------------------------------------------------------------*/
4050        for (i = 0; i < MAXIMOS_CLIENTES; i++) {
4051                tbsockets[i].ip[0] = '\0';
4052                tbsockets[i].cli = NULL;
4053        }
4054        /*--------------------------------------------------------------------------------------------------------
4055         Creación y configuración del socket del servicio
4056         ---------------------------------------------------------------------------------------------------------*/
4057        socket_s = og_socket_server_init(puerto);
4058        if (socket_s < 0)
4059                exit(EXIT_FAILURE);
4060
4061        ev_io_init(&ev_io_server, og_server_accept_cb, socket_s, EV_READ);
4062        ev_io_start(loop, &ev_io_server);
4063
4064        socket_rest = og_socket_server_init("8888");
4065        if (socket_rest < 0)
4066                exit(EXIT_FAILURE);
4067
4068        ev_io_init(&ev_io_server_rest, og_server_accept_cb, socket_rest, EV_READ);
4069        ev_io_start(loop, &ev_io_server_rest);
4070
4071        infoLog(1); // Inicio de sesión
4072
4073        /* old log file has been deprecated. */
4074        og_log(97, false);
4075
4076        syslog(LOG_INFO, "Waiting for connections\n");
4077
4078        while (1)
4079                ev_loop(loop, 0);
4080
4081        exit(EXIT_SUCCESS);
4082}
Note: See TracBrowser for help on using the repository browser.