View this PageEdit this PageUploads to this PageVersions of this PageHomeRecent ChangesSearchHelp Guide

Uso de XDR sin la capa RPC

Tabla de contenidos
  1. Crear un fichero .x
  2. Compilar el .x a .h y .c
  3. Usar el fichero XDR
  4. Decodificar mensajes XDR
  5. Codificar y mandar mensajes XDR
  6. Notas

1. Crear un fichero .x


Primero hay que crear un fichero .x con la especificación de los tipos de datos (rfc1014 (old, not in use any more), rfc1832, XDR grammar inconsistencies (external link)).

Actualmente se usa el rfc4506 (obsoletes rfc1832) junto con el apartado "10. RECORD MARKING STANDARD" del rfc1057.

2. Compilar el .x a .h y .c


En el GNU Makefile se haría de la siguiente forma(nota1):
Makefile
%_xdr.c : %.x
        $(RM) $@
        rpcgen -C -N -c -o $@ $<

%.h : %.x
        $(RM) $@
        rpcgen -C -N -h -o $@ $<
        mv $@ $@.verbose
        sed "/#ifdef __cplusplus/,/#elif __STDC__/d;/#else .. Old Style C ../,/#endif .. Old Style C ../d" < $@.verbose > $@
        $(RM) $@.verbose


Si bien es cierto que tan sólo nos interesa el fichero _xdr.c

3. Usar el fichero XDR


En el programa tenemos que incluir el fichero _xdr.c

#include "midesc_xdr.c"

4. Decodificar mensajes XDR


Suponiendo que ya has incluido el fichero _xdr.c, tedrás que hacer código similar a lo siguiente (ejemplo)

//... decodifica ...
{
        MensajeIdentificacion Mensaje;
        XDR ManejadorXDR;
        int Res;
        xdrmem_create(&ManejadorXDR,Buffer,sizeof(Buffer),XDR_DECODE);
        Res=xdr_MensajeIdentificacion(&ManejadorXDR,&Mensaje);
        LogWrite("INFO","Resultado de la decodificacion: %li\n",(long)Res);
        if(Res!=1) {
                LogWrite("INFO","ERROR: No se pudo decodificar.\n");
                xdr_destroy(&ManejadorXDR);
                break;
        }
        xdr_destroy(&ManejadorXDR);
	// ...
	// aquí se utilizaría la estructura
	// ...
	/* Liberamos la memoria que ha cogido el decode */
	xdr_free((xdrproc_t)xdr_MensajeIdentificacion,(char *)&Mensaje);
}


5. Codificar y mandar mensajes XDR



//... codifica ...
{
        char Buffer[1024];
        int Tam,Res,Len;
        XDR ManejadorXDR;
        PeticionIdentificacion Mensaje;
        memset(&Mensaje,0,sizeof(Mensaje));
        Mensaje.tipo=1;
        Mensaje.texto=PtrTextoZeroPadded;
        memset(Buffer,0,sizeof(Buffer));
        xdrmem_create(&ManejadorXDR,Buffer+4,sizeof(Buffer)-4,XDR_ENCODE);
        Res=xdr_PeticionIdentificacion(&ManejadorXDR,&Mensaje);
        if(Res!=1) {
                xdr_destroy(&ManejadorXDR);
                LogWrite("INFO","ERROR: No se pudo codificar.\n");
                break;
        }
        Tam=xdr_getpos(&ManejadorXDR);
        Buffer[0]=((Tam>>24)&0x7F)|0x80;
        Buffer[1]=((Tam>>16)&0xFF);
        Buffer[2]=((Tam>>8)&0xFF);
        Buffer[3]=((Tam)&0xFF);
        write(Sock,Buffer,Tam+4);
        xdr_destroy(&ManejadorXDR);
}


A tener en cuenta que supongo un mensaje pequeño, es decir, que no requiere ser partido. En caso de tener que partirlo, Buffer[0] no tendría el bit alto activado en el primer bloque ni en las continuaciones, pero sí lo tendría en el último bloque (ya que es un marcador de fin-de-bloque).

Notas

Nota1: el makefile completo si se quieren las partes de rpc sería:
Makefile
%_svc.c: %.x %.h
        $(RM) $@
        rpcgen -C -N -m -o $@ $<

%_clnt.c: %.x %.h
        $(RM) $@
        rpcgen -C -N -l -o $@ $<

%_xdr.c : %.x
        $(RM) $@
        rpcgen -C -N -c -o $@ $<

%.h : %.x
        $(RM) $@
        rpcgen -C -N -h -o $@ $<


Tips&tricks


  • Si se usa el xdrrec_*, en la función de lectura es muy iomportante devolver 0 si el read ha hecho EAGAIN. Si hay un error devolver -1 y si ha leido algo, devolver el número de bytes leídos.

  • xdrrec_skiprecord al ppio del todo y hago la lectura y dp. el skiprecord de despues de lectura.

  • si se usa el xdrrec_feof, cuidado porque cuando se hace, hace una cancelación del registro actual, con lo que hay que hacerlo ANTES del skiprecord pero después de la lectura/decodificación del registro.