Back to index

openldap  2.4.31
nslcd-prot.h
Go to the documentation of this file.
00001 /*
00002    nslcd-prot.h - helper macros for reading and writing in protocol streams
00003 
00004    Copyright (C) 2006 West Consulting
00005    Copyright (C) 2006, 2007, 2009 Arthur de Jong
00006 
00007    This library is free software; you can redistribute it and/or
00008    modify it under the terms of the GNU Lesser General Public
00009    License as published by the Free Software Foundation; either
00010    version 2.1 of the License, or (at your option) any later version.
00011 
00012    This library is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015    Lesser General Public License for more details.
00016 
00017    You should have received a copy of the GNU Lesser General Public
00018    License along with this library; if not, write to the Free Software
00019    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00020    02110-1301 USA
00021 */
00022 
00023 #ifndef _NSLCD_PROT_H
00024 #define _NSLCD_PROT_H 1
00025 
00026 #include "tio.h"
00027 
00028 /* If you use these macros you should define the following macros to
00029    handle error conditions (these marcos should clean up and return from the
00030    function):
00031      ERROR_OUT_WRITEERROR(fp)
00032      ERROR_OUT_READERROR(fp)
00033      ERROR_OUT_BUFERROR(fp)
00034      ERROR_OUT_NOSUCCESS(fp) */
00035 
00036 
00037 /* Debugging marcos that can be used to enable detailed protocol logging,
00038    pass -DDEBUG_PROT to do overall protocol debugging, and -DDEBUG_PROT_DUMP
00039    to dump the actual bytestream. */
00040 
00041 #ifdef DEBUG_PROT
00042 /* define a debugging macro to output logging */
00043 #include <string.h>
00044 #include <errno.h>
00045 #define DEBUG_PRINT(fmt,arg) \
00046   fprintf(stderr,"%s:%d:%s: " fmt "\n",__FILE__,__LINE__,__PRETTY_FUNCTION__,arg);
00047 #else /* DEBUG_PROT */
00048 /* define an empty debug macro to disable logging */
00049 #define DEBUG_PRINT(fmt,arg)
00050 #endif /* not DEBUG_PROT */
00051 
00052 #ifdef DEBUG_PROT_DUMP
00053 /* define a debugging macro to output detailed logging */
00054 #ifdef HAVE_STDINT_H
00055 #include <stdint.h>
00056 #endif /* HAVE_STDINT_H */
00057 static void debug_dump(const void *ptr,size_t size)
00058 {
00059   int i;
00060   for (i=0;i<size;i++)
00061     fprintf(stderr," %02x",((const uint8_t *)ptr)[i]);
00062   fprintf(stderr,"\n");
00063 }
00064 #define DEBUG_DUMP(ptr,size) \
00065   fprintf(stderr,"%s:%d:%s:",__FILE__,__LINE__,__PRETTY_FUNCTION__); \
00066   debug_dump(ptr,size);
00067 #else /* DEBUG_PROT_DUMP */
00068 /* define an empty debug macro to disable logging */
00069 #define DEBUG_DUMP(ptr,size)
00070 #endif /* not DEBUG_PROT_DUMP */
00071 
00072 
00073 /* WRITE marcos, used for writing data, on write error they will
00074    call the ERROR_OUT_WRITEERROR macro
00075    these macros may require the availability of the following
00076    variables:
00077    int32_t tmpint32; - temporary variable
00078    */
00079 
00080 #define WRITE(fp,ptr,size) \
00081   DEBUG_PRINT("WRITE       : var="__STRING(ptr)" size=%d",(int)size); \
00082   DEBUG_DUMP(ptr,size); \
00083   if (tio_write(fp,ptr,(size_t)size)) \
00084   { \
00085     DEBUG_PRINT("WRITE       : var="__STRING(ptr)" error: %s",strerror(errno)); \
00086     ERROR_OUT_WRITEERROR(fp); \
00087   }
00088 
00089 #define WRITE_TYPE(fp,field,type) \
00090   WRITE(fp,&(field),sizeof(type))
00091 
00092 #define WRITE_INT32(fp,i) \
00093   DEBUG_PRINT("WRITE_INT32 : var="__STRING(i)" int32=%d",(int)i); \
00094   tmpint32=(int32_t)(i); \
00095   WRITE_TYPE(fp,tmpint32,int32_t)
00096 
00097 #define WRITE_STRING(fp,str) \
00098   DEBUG_PRINT("WRITE_STRING: var="__STRING(str)" string=\"%s\"",(str)); \
00099   if ((str)==NULL) \
00100   { \
00101     WRITE_INT32(fp,0); \
00102   } \
00103   else \
00104   { \
00105     WRITE_INT32(fp,strlen(str)); \
00106     if (tmpint32>0) \
00107       { WRITE(fp,(str),tmpint32); } \
00108   }
00109 
00110 #define WRITE_STRINGLIST(fp,arr) \
00111   if ((arr)==NULL) \
00112   { \
00113     DEBUG_PRINT("WRITE_STRLST: var="__STRING(arr)" num=%d",0); \
00114     WRITE_INT32(fp,0); \
00115   } \
00116   else \
00117   { \
00118     /* first determin length of array */ \
00119     for (tmp3int32=0;(arr)[tmp3int32]!=NULL;tmp3int32++) \
00120       /*noting*/ ; \
00121     /* write number of strings */ \
00122     DEBUG_PRINT("WRITE_STRLST: var="__STRING(arr)" num=%d",(int)tmp3int32); \
00123     WRITE_TYPE(fp,tmp3int32,int32_t); \
00124     /* write strings */ \
00125     for (tmp2int32=0;tmp2int32<tmp3int32;tmp2int32++) \
00126     { \
00127       WRITE_STRING(fp,(arr)[tmp2int32]); \
00128     } \
00129   }
00130 
00131 #define WRITE_STRINGLIST_EXCEPT(fp,arr,not) \
00132   /* first determin length of array */ \
00133   tmp3int32=0; \
00134   for (tmp2int32=0;(arr)[tmp2int32]!=NULL;tmp2int32++) \
00135     if (strcmp((arr)[tmp2int32],(not))!=0) \
00136       tmp3int32++; \
00137   /* write number of strings (mius one because we intend to skip one) */ \
00138   DEBUG_PRINT("WRITE_STRLST: var="__STRING(arr)" num=%d",(int)tmp3int32); \
00139   WRITE_TYPE(fp,tmp3int32,int32_t); \
00140   /* write strings */ \
00141   for (tmp2int32=0;(arr)[tmp2int32]!=NULL;tmp2int32++) \
00142   { \
00143     if (strcmp((arr)[tmp2int32],(not))!=0) \
00144     { \
00145       WRITE_STRING(fp,(arr)[tmp2int32]); \
00146     } \
00147   }
00148 
00149 
00150 /* READ macros, used for reading data, on read error they will
00151    call the ERROR_OUT_READERROR or ERROR_OUT_BUFERROR macro
00152    these macros may require the availability of the following
00153    variables:
00154    int32_t tmpint32; - temporary variable
00155    */
00156 
00157 #define READ(fp,ptr,size) \
00158   if (tio_read(fp,ptr,(size_t)size)) \
00159   { \
00160     DEBUG_PRINT("READ       : var="__STRING(ptr)" error: %s",strerror(errno)); \
00161     ERROR_OUT_READERROR(fp); \
00162   } \
00163   DEBUG_PRINT("READ       : var="__STRING(ptr)" size=%d",(int)size); \
00164   DEBUG_DUMP(ptr,size);
00165 
00166 #define READ_TYPE(fp,field,type) \
00167   READ(fp,&(field),sizeof(type))
00168 
00169 #define READ_INT32(fp,i) \
00170   READ_TYPE(fp,tmpint32,int32_t); \
00171   i=tmpint32; \
00172   DEBUG_PRINT("READ_INT32 : var="__STRING(i)" int32=%d",(int)i);
00173 
00174 /* read a string in a fixed-size "normal" buffer */
00175 #define READ_STRING(fp,buffer) \
00176   /* read the size of the string */ \
00177   READ_TYPE(fp,tmpint32,int32_t); \
00178   DEBUG_PRINT("READ_STRING: var="__STRING(buffer)" strlen=%d",tmpint32); \
00179   /* check if read would fit */ \
00180   if (((size_t)tmpint32)>=sizeof(buffer)) \
00181   { \
00182     /* will not fit */ \
00183     DEBUG_PRINT("READ       : buffer error: %d bytes too large",(tmpint32-sizeof(buffer))+1); \
00184     ERROR_OUT_BUFERROR(fp); \
00185   } \
00186   /* read string from the stream */ \
00187   if (tmpint32>0) \
00188     { READ(fp,buffer,(size_t)tmpint32); } \
00189   /* null-terminate string in buffer */ \
00190   buffer[tmpint32]='\0'; \
00191   DEBUG_PRINT("READ_STRING: var="__STRING(buffer)" string=\"%s\"",buffer);
00192 
00193 
00194 /* READ BUF macros that read data into a pre-allocated buffer.
00195    these macros may require the availability of the following
00196    variables:
00197    int32_t tmpint32; - temporary variable
00198    char *buffer;     - pointer to a buffer for reading strings
00199    size_t buflen;    - the size of the buffer
00200    size_t bufptr;    - the current position in the buffer
00201    */
00202 
00203 /* current position in the buffer */
00204 #define BUF_CUR \
00205   (buffer+bufptr)
00206 
00207 /* check that the buffer has sz bytes left in it */
00208 #define BUF_CHECK(fp,sz) \
00209   if ((bufptr+(size_t)(sz))>buflen) \
00210   { \
00211     /* will not fit */ \
00212     DEBUG_PRINT("READ       : buffer error: %d bytes too small",(bufptr+(sz)-(buflen))); \
00213     ERROR_OUT_BUFERROR(fp); \
00214   }
00215 
00216 /* move the buffer pointer */
00217 #define BUF_SKIP(sz) \
00218   bufptr+=(size_t)(sz);
00219 
00220 /* move BUF_CUR foreward so that it is aligned to the specified
00221    type width */
00222 #define BUF_ALIGN(fp,type) \
00223   /* figure out number of bytes to skip foreward */ \
00224   tmp2int32=(sizeof(type)-((BUF_CUR-(char *)NULL)%sizeof(type)))%sizeof(type); \
00225   /* check and skip */ \
00226   BUF_CHECK(fp,tmp2int32); \
00227   BUF_SKIP(tmp2int32);
00228 
00229 /* allocate a piece of the buffer to store an array in */
00230 #define BUF_ALLOC(fp,ptr,type,num) \
00231   /* align to the specified type width */ \
00232   BUF_ALIGN(fp,type); \
00233   /* check that we have enough room */ \
00234   BUF_CHECK(fp,(size_t)(num)*sizeof(type)); \
00235   /* store the pointer */ \
00236   (ptr)=(type *)BUF_CUR; \
00237   /* reserve the space */ \
00238   BUF_SKIP((size_t)(num)*sizeof(type));
00239 
00240 /* read a binary blob into the buffer */
00241 #define READ_BUF(fp,ptr,sz) \
00242   /* check that there is enough room and read */ \
00243   BUF_CHECK(fp,sz); \
00244   READ(fp,BUF_CUR,(size_t)sz); \
00245   /* store pointer and skip */ \
00246   (ptr)=BUF_CUR; \
00247   BUF_SKIP(sz);
00248 
00249 /* read string in the buffer (using buffer, buflen and bufptr)
00250    and store the actual location of the string in field */
00251 #define READ_BUF_STRING(fp,field) \
00252   /* read the size of the string */ \
00253   READ_TYPE(fp,tmpint32,int32_t); \
00254   DEBUG_PRINT("READ_BUF_STRING: var="__STRING(field)" strlen=%d",tmpint32); \
00255   /* check if read would fit */ \
00256   BUF_CHECK(fp,tmpint32+1); \
00257   /* read string from the stream */ \
00258   if (tmpint32>0) \
00259     { READ(fp,BUF_CUR,(size_t)tmpint32); } \
00260   /* null-terminate string in buffer */ \
00261   BUF_CUR[tmpint32]='\0'; \
00262   DEBUG_PRINT("READ_BUF_STRING: var="__STRING(field)" string=\"%s\"",BUF_CUR); \
00263   /* prepare result */ \
00264   (field)=BUF_CUR; \
00265   BUF_SKIP(tmpint32+1);
00266 
00267 /* read an array from a stram and store it as a null-terminated
00268    array list (size for the array is allocated) */
00269 #define READ_BUF_STRINGLIST(fp,arr) \
00270   /* read the number of entries */ \
00271   READ_TYPE(fp,tmp3int32,int32_t); \
00272   DEBUG_PRINT("READ_STRLST: var="__STRING(arr)" num=%d",(int)tmp3int32); \
00273   /* allocate room for *char[num+1] */ \
00274   BUF_ALLOC(fp,arr,char *,tmp3int32+1); \
00275   /* read all entries */ \
00276   for (tmp2int32=0;tmp2int32<tmp3int32;tmp2int32++) \
00277   { \
00278     READ_BUF_STRING(fp,(arr)[tmp2int32]); \
00279   } \
00280   /* set last entry to NULL */ \
00281   (arr)[tmp2int32]=NULL;
00282 
00283 
00284 /* SKIP macros for skipping over certain parts of the protocol stream. */
00285 
00286 /* skip a number of bytes foreward */
00287 #define SKIP(fp,sz) \
00288   DEBUG_PRINT("READ       : skip %d bytes",(int)(sz)); \
00289   /* read (skip) the specified number of bytes */ \
00290   if (tio_skip(fp,sz)) \
00291   { \
00292     DEBUG_PRINT("READ       : skip error: %s",strerror(errno)); \
00293     ERROR_OUT_READERROR(fp); \
00294   }
00295 
00296 /* read a string from the stream but don't do anything with the result */
00297 #define SKIP_STRING(fp) \
00298   /* read the size of the string */ \
00299   READ_TYPE(fp,tmpint32,int32_t); \
00300   DEBUG_PRINT("READ_STRING: skip %d bytes",(int)tmpint32); \
00301   /* read (skip) the specified number of bytes */ \
00302   SKIP(fp,tmpint32);
00303 
00304 /* skip a list of strings */
00305 #define SKIP_STRINGLIST(fp) \
00306   /* read the number of entries */ \
00307   READ_TYPE(fp,tmp3int32,int32_t); \
00308   DEBUG_PRINT("READ_STRLST: skip %d strings",(int)tmp3int32); \
00309   /* read all entries */ \
00310   for (tmp2int32=0;tmp2int32<tmp3int32;tmp2int32++) \
00311   { \
00312     SKIP_STRING(fp); \
00313   }
00314 
00315 
00316 /* These are functions and macors for performing common operations in
00317    the nslcd request/response protocol. */
00318 
00319 /* returns a socket to the server or NULL on error (see errno),
00320    socket should be closed with tio_close() */
00321 TFILE *nslcd_client_open(void)
00322   MUST_USE;
00323 
00324 /* generic request code */
00325 #define NSLCD_REQUEST(fp,action,writefn) \
00326   /* open a client socket */ \
00327   if ((fp=nslcd_client_open())==NULL) \
00328     { ERROR_OUT_OPENERROR } \
00329   /* write a request header with a request code */ \
00330   WRITE_INT32(fp,(int32_t)NSLCD_VERSION) \
00331   WRITE_INT32(fp,(int32_t)action) \
00332   /* write the request parameters (if any) */ \
00333   writefn; \
00334   /* flush the stream */ \
00335   if (tio_flush(fp)<0) \
00336   { \
00337     DEBUG_PRINT("WRITE_FLUSH : error: %s",strerror(errno)); \
00338     ERROR_OUT_WRITEERROR(fp); \
00339   } \
00340   /* read and check response version number */ \
00341   READ_TYPE(fp,tmpint32,int32_t); \
00342   if (tmpint32!=(int32_t)NSLCD_VERSION) \
00343     { ERROR_OUT_READERROR(fp) } \
00344   /* read and check response request number */ \
00345   READ_TYPE(fp,tmpint32,int32_t); \
00346   if (tmpint32!=(int32_t)(action)) \
00347     { ERROR_OUT_READERROR(fp) }
00348 
00349 /* Read the response code (the result code of the query) from
00350    the stream. */
00351 #define READ_RESPONSE_CODE(fp) \
00352   READ_TYPE(fp,tmpint32,int32_t); \
00353   if (tmpint32!=(int32_t)NSLCD_RESULT_BEGIN) \
00354     { ERROR_OUT_NOSUCCESS(fp) }
00355 
00356 #endif /* not _NSLCD_PROT_H */