]> git.sur5r.net Git - openldap/blob - contrib/slapd-modules/nssov/nss-ldapd/nslcd-common.h
ITS#5801
[openldap] / contrib / slapd-modules / nssov / nss-ldapd / nslcd-common.h
1 /*
2    nslcd-common.h - helper macros for reading and writing in
3                     protocol streams
4
5    Copyright (C) 2006 West Consulting
6    Copyright (C) 2006, 2007 Arthur de Jong
7
8    This library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Lesser General Public
10    License as published by the Free Software Foundation; either
11    version 2.1 of the License, or (at your option) any later version.
12
13    This library is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Lesser General Public License for more details.
17
18    You should have received a copy of the GNU Lesser General Public
19    License along with this library; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301 USA
22 */
23
24 #ifndef _NSLCD_COMMON_H
25 #define _NSLCD_COMMON_H 1
26
27 #include <stdio.h>
28
29 #ifdef DEBUG_PROT
30 /* define a debugging macro to output logging */
31 #include <string.h>
32 #include <errno.h>
33 #define DEBUG_PRINT(fmt,arg) \
34   fprintf(stderr,"%s:%d:%s: " fmt "\n",__FILE__,__LINE__,__PRETTY_FUNCTION__,arg);
35 #else /* DEBUG_PROT */
36 /* define an empty debug macro to disable logging */
37 #define DEBUG_PRINT(fmt,arg)
38 #endif /* not DEBUG_PROT */
39
40 #ifdef DEBUG_PROT_DUMP
41 /* define a debugging macro to output detailed logging */
42 #ifdef HAVE_STDINT_H
43 #include <stdint.h>
44 #endif /* HAVE_STDINT_H */
45 static void debug_dump(const void *ptr,size_t size)
46 {
47   int i;
48   for (i=0;i<size;i++)
49     fprintf(stderr," %02x",((const uint8_t *)ptr)[i]);
50   fprintf(stderr,"\n");
51 }
52 #define DEBUG_DUMP(ptr,size) \
53   fprintf(stderr,"%s:%d:%s:",__FILE__,__LINE__,__PRETTY_FUNCTION__); \
54   debug_dump(ptr,size);
55 #else /* DEBUG_PROT_DUMP */
56 /* define an empty debug macro to disable logging */
57 #define DEBUG_DUMP(ptr,size)
58 #endif /* not DEBUG_PROT_DUMP */
59
60 /* WRITE marcos, used for writing data, on write error they will
61    call the ERROR_OUT_WRITEERROR macro
62    these macros may require the availability of the following
63    variables:
64    int32_t tmpint32; - temporary variable
65    */
66
67 #define WRITE(fp,ptr,size) \
68   DEBUG_PRINT("WRITE       : var="__STRING(ptr)" size=%d",(int)size); \
69   DEBUG_DUMP(ptr,size); \
70   if (tio_write(fp,ptr,(size_t)size)) \
71   { \
72     DEBUG_PRINT("WRITE       : var="__STRING(ptr)" error: %s",strerror(errno)); \
73     ERROR_OUT_WRITEERROR(fp); \
74   }
75
76 #define WRITE_TYPE(fp,field,type) \
77   WRITE(fp,&(field),sizeof(type))
78
79 #define WRITE_INT32(fp,i) \
80   DEBUG_PRINT("WRITE_INT32 : var="__STRING(i)" int32=%d",(int)i); \
81   tmpint32=(int32_t)(i); \
82   WRITE_TYPE(fp,tmpint32,int32_t)
83
84 #define WRITE_STRING(fp,str) \
85   DEBUG_PRINT("WRITE_STRING: var="__STRING(str)" string=\"%s\"",str); \
86   if (str==NULL) \
87   { \
88     WRITE_INT32(fp,0); \
89   } \
90   else \
91   { \
92     WRITE_INT32(fp,strlen(str)); \
93     if (tmpint32>0) \
94       { WRITE(fp,str,tmpint32); } \
95   }
96
97 #define WRITE_FLUSH(fp) \
98   if (tio_flush(fp)<0) \
99   { \
100     DEBUG_PRINT("WRITE_FLUSH : error: %s",strerror(errno)); \
101     ERROR_OUT_WRITEERROR(fp); \
102   }
103
104 #define WRITE_STRINGLIST(fp,arr) \
105   /* first determin length of array */ \
106   for (tmp3int32=0;(arr)[tmp3int32]!=NULL;tmp3int32++) \
107     /*noting*/ ; \
108   /* write number of strings */ \
109   DEBUG_PRINT("WRITE_STRLST: var="__STRING(arr)" num=%d",(int)tmp3int32); \
110   WRITE_TYPE(fp,tmp3int32,int32_t); \
111   /* write strings */ \
112   for (tmp2int32=0;tmp2int32<tmp3int32;tmp2int32++) \
113   { \
114     WRITE_STRING(fp,(arr)[tmp2int32]); \
115   }
116
117 #define WRITE_STRINGLIST_EXCEPT(fp,arr,not) \
118   /* first determin length of array */ \
119   for (tmp3int32=0;(arr)[tmp3int32]!=NULL;tmp3int32++) \
120     /*noting*/ ; \
121   /* write number of strings (mius one because we intend to skip one) */ \
122   tmp3int32--; \
123   DEBUG_PRINT("WRITE_STRLST: var="__STRING(arr)" num=%d",(int)tmp3int32); \
124   WRITE_TYPE(fp,tmp3int32,int32_t); \
125   tmp3int32++; \
126   /* write strings */ \
127   for (tmp2int32=0;tmp2int32<tmp3int32;tmp2int32++) \
128   { \
129     if (strcmp((arr)[tmp2int32],(not))!=0) \
130     { \
131       WRITE_STRING(fp,(arr)[tmp2int32]); \
132     } \
133   }
134
135 /* READ macros, used for reading data, on read error they will
136    call the ERROR_OUT_READERROR or ERROR_OUT_BUFERROR macro
137    these macros may require the availability of the following
138    variables:
139    int32_t tmpint32; - temporary variable
140    char *buffer;     - pointer to a buffer for reading strings
141    size_t buflen;    - the size of the buffer
142    size_t bufptr;    - the current position in the buffer
143    */
144
145 #define READ(fp,ptr,size) \
146   if (tio_read(fp,ptr,(size_t)size)) \
147   { \
148     DEBUG_PRINT("READ       : var="__STRING(ptr)" error: %s",strerror(errno)); \
149     ERROR_OUT_READERROR(fp); \
150   } \
151   DEBUG_PRINT("READ       : var="__STRING(ptr)" size=%d",(int)size); \
152   DEBUG_DUMP(ptr,size);
153
154 #define READ_TYPE(fp,field,type) \
155   READ(fp,&(field),sizeof(type))
156
157 #define READ_INT32(fp,i) \
158   READ_TYPE(fp,tmpint32,int32_t); \
159   i=tmpint32; \
160   DEBUG_PRINT("READ_INT32 : var="__STRING(i)" int32=%d",(int)i);
161
162 /* current position in the buffer */
163 #define BUF_CUR \
164   (buffer+bufptr)
165
166 /* check that the buffer has sz bytes left in it */
167 #define BUF_CHECK(fp,sz) \
168   if ((bufptr+(size_t)(sz))>buflen) \
169   { \
170     /* will not fit */ \
171     DEBUG_PRINT("READ       : buffer error: %d bytes too small",(bufptr+(sz)-(buflen))); \
172     ERROR_OUT_BUFERROR(fp); \
173   }
174
175 /* move the buffer pointer */
176 #define BUF_SKIP(sz) \
177   bufptr+=(size_t)(sz);
178
179 /* move BUF_CUR foreward so that it is aligned to the specified
180    type width */
181 #define BUF_ALIGN(fp,type) \
182   /* figure out number of bytes to skip foreward */ \
183   tmp2int32=(sizeof(type)-((BUF_CUR-(char *)NULL)%sizeof(type)))%sizeof(type); \
184   /* check and skip */ \
185   BUF_CHECK(fp,tmp2int32); \
186   BUF_SKIP(tmp2int32);
187
188 /* allocate a piece of the buffer to store an array in */
189 #define BUF_ALLOC(fp,ptr,type,num) \
190   /* align to the specified type width */ \
191   BUF_ALIGN(fp,type); \
192   /* check that we have enough room */ \
193   BUF_CHECK(fp,(size_t)(num)*sizeof(type)); \
194   /* store the pointer */ \
195   (ptr)=(type *)BUF_CUR; \
196   /* reserve the space */ \
197   BUF_SKIP((size_t)(num)*sizeof(type));
198
199 /* read string in the buffer (using buffer, buflen and bufptr)
200    and store the actual location of the string in field */
201 #define READ_STRING_BUF(fp,field) \
202   /* read the size of the string */ \
203   READ_TYPE(fp,tmpint32,int32_t); \
204   DEBUG_PRINT("READ_STRING: var="__STRING(field)" strlen=%d",tmpint32); \
205   /* check if read would fit */ \
206   BUF_CHECK(fp,tmpint32+1); \
207   /* read string from the stream */ \
208   if (tmpint32>0) \
209     { READ(fp,BUF_CUR,(size_t)tmpint32); } \
210   /* null-terminate string in buffer */ \
211   BUF_CUR[tmpint32]='\0'; \
212   DEBUG_PRINT("READ_STRING: var="__STRING(field)" string=\"%s\"",BUF_CUR); \
213   /* prepare result */ \
214   (field)=BUF_CUR; \
215   BUF_SKIP(tmpint32+1);
216
217 /* read a string in a fixed-size "normal" buffer */
218 #define READ_STRING_BUF2(fp,buffer,buflen) \
219   /* read the size of the string */ \
220   READ_TYPE(fp,tmpint32,int32_t); \
221   DEBUG_PRINT("READ_STRING: var="__STRING(buffer)" strlen=%d",tmpint32); \
222   /* check if read would fit */ \
223   if (((size_t)tmpint32)>=(buflen)) \
224   { \
225     /* will not fit */ \
226     DEBUG_PRINT("READ       : buffer error: %d bytes too large",(tmpint32-(buflen))+1); \
227     ERROR_OUT_BUFERROR(fp); \
228   } \
229   /* read string from the stream */ \
230   if (tmpint32>0) \
231     { READ(fp,buffer,(size_t)tmpint32); } \
232   /* null-terminate string in buffer */ \
233   buffer[tmpint32]='\0'; \
234   DEBUG_PRINT("READ_STRING: var="__STRING(buffer)" string=\"%s\"",buffer);
235
236 /* read a binary blob into the buffer */
237 #define READ_BUF(fp,ptr,sz) \
238   /* check that there is enough room and read */ \
239   BUF_CHECK(fp,sz); \
240   READ(fp,BUF_CUR,(size_t)sz); \
241   /* store pointer and skip */ \
242   (ptr)=BUF_CUR; \
243   BUF_SKIP(sz);
244
245 /* read an array from a stram and store the length of the
246    array in num (size for the array is allocated) */
247 #define READ_STRINGLIST_NUM(fp,arr,num) \
248   /* read the number of entries */ \
249   READ_INT32(fp,(num)); \
250   DEBUG_PRINT("READ_STRLST: var="__STRING(arr)" num=%d",(int)(num)); \
251   /* allocate room for *char[num] */ \
252   BUF_ALLOC(fp,arr,char *,tmpint32); \
253   /* read all the strings */ \
254   for (tmp2int32=0;tmp2int32<(int32_t)(num);tmp2int32++) \
255   { \
256     READ_STRING_BUF(fp,(arr)[tmp2int32]); \
257   }
258
259 /* read an array from a stram and store it as a null-terminated
260    array list (size for the array is allocated) */
261 #define READ_STRINGLIST_NULLTERM(fp,arr) \
262   /* read the number of entries */ \
263   READ_TYPE(fp,tmp3int32,int32_t); \
264   DEBUG_PRINT("READ_STRLST: var="__STRING(arr)" num=%d",(int)tmp3int32); \
265   /* allocate room for *char[num+1] */ \
266   BUF_ALLOC(fp,arr,char *,tmp3int32+1); \
267   /* read all entries */ \
268   for (tmp2int32=0;tmp2int32<tmp3int32;tmp2int32++) \
269   { \
270     READ_STRING_BUF(fp,(arr)[tmp2int32]); \
271   } \
272   /* set last entry to NULL */ \
273   (arr)[tmp2int32]=NULL;
274
275 /* skip a number of bytes foreward
276    Note that this macro modifies the sz variable */
277 #define SKIP(fp,sz) \
278   DEBUG_PRINT("READ       : skip %d bytes",(int)(sz)); \
279   /* read (skip) the specified number of bytes */ \
280   if (tio_skip(fp,sz)) \
281   { \
282     DEBUG_PRINT("READ       : skip error: %s",strerror(errno)); \
283     ERROR_OUT_READERROR(fp); \
284   }
285
286 /* read a string from the stream but don't do anything with the result */
287 #define SKIP_STRING(fp) \
288   /* read the size of the string */ \
289   READ_TYPE(fp,tmpint32,int32_t); \
290   DEBUG_PRINT("READ_STRING: skip %d bytes",(int)tmpint32); \
291   /* read (skip) the specified number of bytes */ \
292   SKIP(fp,tmpint32);
293
294 /* skip a loop of strings */
295 #define SKIP_STRINGLIST(fp) \
296   /* read the number of entries */ \
297   READ_TYPE(fp,tmp3int32,int32_t); \
298   DEBUG_PRINT("READ_STRLST: skip %d strings",(int)tmp3int32); \
299   /* read all entries */ \
300   for (tmp2int32=0;tmp2int32<tmp3int32;tmp2int32++) \
301   { \
302     SKIP_STRING(fp); \
303   }
304
305 #endif /* not _NSLCD_COMMON_H */