        |
Uso de XDR sin la capa RPC
Tabla de contenidos
- Crear un fichero .x
- Compilar el .x a .h y .c
- Usar el fichero XDR
- Decodificar mensajes XDR
- Codificar y mandar mensajes XDR
- 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.
|