2 nslcd-prot.h - helper macros for reading and writing in protocol streams
4 Copyright (C) 2006 West Consulting
5 Copyright (C) 2006, 2007, 2009 Arthur de Jong
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 #define _NSLCD_PROT_H 1
28 /* If you use these macros you should define the following macros to
29 handle error conditions (these marcos should clean up and return from the
31 ERROR_OUT_WRITEERROR(fp)
32 ERROR_OUT_READERROR(fp)
33 ERROR_OUT_BUFERROR(fp)
34 ERROR_OUT_NOSUCCESS(fp) */
37 /* Debugging marcos that can be used to enable detailed protocol logging,
38 pass -DDEBUG_PROT to do overall protocol debugging, and -DDEBUG_PROT_DUMP
39 to dump the actual bytestream. */
42 /* define a debugging macro to output logging */
45 #define DEBUG_PRINT(fmt,arg) \
46 fprintf(stderr,"%s:%d:%s: " fmt "\n",__FILE__,__LINE__,__PRETTY_FUNCTION__,arg);
47 #else /* DEBUG_PROT */
48 /* define an empty debug macro to disable logging */
49 #define DEBUG_PRINT(fmt,arg)
50 #endif /* not DEBUG_PROT */
52 #ifdef DEBUG_PROT_DUMP
53 /* define a debugging macro to output detailed logging */
56 #endif /* HAVE_STDINT_H */
57 static void debug_dump(const void *ptr,size_t size)
61 fprintf(stderr," %02x",((const uint8_t *)ptr)[i]);
64 #define DEBUG_DUMP(ptr,size) \
65 fprintf(stderr,"%s:%d:%s:",__FILE__,__LINE__,__PRETTY_FUNCTION__); \
67 #else /* DEBUG_PROT_DUMP */
68 /* define an empty debug macro to disable logging */
69 #define DEBUG_DUMP(ptr,size)
70 #endif /* not DEBUG_PROT_DUMP */
73 /* WRITE marcos, used for writing data, on write error they will
74 call the ERROR_OUT_WRITEERROR macro
75 these macros may require the availability of the following
77 int32_t tmpint32; - temporary variable
80 #define WRITE(fp,ptr,size) \
81 DEBUG_PRINT("WRITE : var="__STRING(ptr)" size=%d",(int)size); \
82 DEBUG_DUMP(ptr,size); \
83 if (tio_write(fp,ptr,(size_t)size)) \
85 DEBUG_PRINT("WRITE : var="__STRING(ptr)" error: %s",strerror(errno)); \
86 ERROR_OUT_WRITEERROR(fp); \
89 #define WRITE_TYPE(fp,field,type) \
90 WRITE(fp,&(field),sizeof(type))
92 #define WRITE_INT32(fp,i) \
93 DEBUG_PRINT("WRITE_INT32 : var="__STRING(i)" int32=%d",(int)i); \
94 tmpint32=(int32_t)(i); \
95 WRITE_TYPE(fp,tmpint32,int32_t)
97 #define WRITE_STRING(fp,str) \
98 DEBUG_PRINT("WRITE_STRING: var="__STRING(str)" string=\"%s\"",(str)); \
105 WRITE_INT32(fp,strlen(str)); \
107 { WRITE(fp,(str),tmpint32); } \
110 #define WRITE_STRINGLIST(fp,arr) \
113 DEBUG_PRINT("WRITE_STRLST: var="__STRING(arr)" num=%d",0); \
118 /* first determin length of array */ \
119 for (tmp3int32=0;(arr)[tmp3int32]!=NULL;tmp3int32++) \
121 /* write number of strings */ \
122 DEBUG_PRINT("WRITE_STRLST: var="__STRING(arr)" num=%d",(int)tmp3int32); \
123 WRITE_TYPE(fp,tmp3int32,int32_t); \
124 /* write strings */ \
125 for (tmp2int32=0;tmp2int32<tmp3int32;tmp2int32++) \
127 WRITE_STRING(fp,(arr)[tmp2int32]); \
131 #define WRITE_STRINGLIST_EXCEPT(fp,arr,not) \
132 /* first determin length of array */ \
134 for (tmp2int32=0;(arr)[tmp2int32]!=NULL;tmp2int32++) \
135 if (strcmp((arr)[tmp2int32],(not))!=0) \
137 /* write number of strings (mius one because we intend to skip one) */ \
138 DEBUG_PRINT("WRITE_STRLST: var="__STRING(arr)" num=%d",(int)tmp3int32); \
139 WRITE_TYPE(fp,tmp3int32,int32_t); \
140 /* write strings */ \
141 for (tmp2int32=0;(arr)[tmp2int32]!=NULL;tmp2int32++) \
143 if (strcmp((arr)[tmp2int32],(not))!=0) \
145 WRITE_STRING(fp,(arr)[tmp2int32]); \
150 /* READ macros, used for reading data, on read error they will
151 call the ERROR_OUT_READERROR or ERROR_OUT_BUFERROR macro
152 these macros may require the availability of the following
154 int32_t tmpint32; - temporary variable
157 #define READ(fp,ptr,size) \
158 if (tio_read(fp,ptr,(size_t)size)) \
160 DEBUG_PRINT("READ : var="__STRING(ptr)" error: %s",strerror(errno)); \
161 ERROR_OUT_READERROR(fp); \
163 DEBUG_PRINT("READ : var="__STRING(ptr)" size=%d",(int)size); \
164 DEBUG_DUMP(ptr,size);
166 #define READ_TYPE(fp,field,type) \
167 READ(fp,&(field),sizeof(type))
169 #define READ_INT32(fp,i) \
170 READ_TYPE(fp,tmpint32,int32_t); \
172 DEBUG_PRINT("READ_INT32 : var="__STRING(i)" int32=%d",(int)i);
174 /* read a string in a fixed-size "normal" buffer */
175 #define READ_STRING(fp,buffer) \
176 /* read the size of the string */ \
177 READ_TYPE(fp,tmpint32,int32_t); \
178 DEBUG_PRINT("READ_STRING: var="__STRING(buffer)" strlen=%d",tmpint32); \
179 /* check if read would fit */ \
180 if (((size_t)tmpint32)>=sizeof(buffer)) \
183 DEBUG_PRINT("READ : buffer error: %d bytes too large",(tmpint32-sizeof(buffer))+1); \
184 ERROR_OUT_BUFERROR(fp); \
186 /* read string from the stream */ \
188 { READ(fp,buffer,(size_t)tmpint32); } \
189 /* null-terminate string in buffer */ \
190 buffer[tmpint32]='\0'; \
191 DEBUG_PRINT("READ_STRING: var="__STRING(buffer)" string=\"%s\"",buffer);
194 /* READ BUF macros that read data into a pre-allocated buffer.
195 these macros may require the availability of the following
197 int32_t tmpint32; - temporary variable
198 char *buffer; - pointer to a buffer for reading strings
199 size_t buflen; - the size of the buffer
200 size_t bufptr; - the current position in the buffer
203 /* current position in the buffer */
207 /* check that the buffer has sz bytes left in it */
208 #define BUF_CHECK(fp,sz) \
209 if ((bufptr+(size_t)(sz))>buflen) \
212 DEBUG_PRINT("READ : buffer error: %d bytes too small",(bufptr+(sz)-(buflen))); \
213 ERROR_OUT_BUFERROR(fp); \
216 /* move the buffer pointer */
217 #define BUF_SKIP(sz) \
218 bufptr+=(size_t)(sz);
220 /* move BUF_CUR foreward so that it is aligned to the specified
222 #define BUF_ALIGN(fp,type) \
223 /* figure out number of bytes to skip foreward */ \
224 tmp2int32=(sizeof(type)-((BUF_CUR-(char *)NULL)%sizeof(type)))%sizeof(type); \
225 /* check and skip */ \
226 BUF_CHECK(fp,tmp2int32); \
229 /* allocate a piece of the buffer to store an array in */
230 #define BUF_ALLOC(fp,ptr,type,num) \
231 /* align to the specified type width */ \
232 BUF_ALIGN(fp,type); \
233 /* check that we have enough room */ \
234 BUF_CHECK(fp,(size_t)(num)*sizeof(type)); \
235 /* store the pointer */ \
236 (ptr)=(type *)BUF_CUR; \
237 /* reserve the space */ \
238 BUF_SKIP((size_t)(num)*sizeof(type));
240 /* read a binary blob into the buffer */
241 #define READ_BUF(fp,ptr,sz) \
242 /* check that there is enough room and read */ \
244 READ(fp,BUF_CUR,(size_t)sz); \
245 /* store pointer and skip */ \
249 /* read string in the buffer (using buffer, buflen and bufptr)
250 and store the actual location of the string in field */
251 #define READ_BUF_STRING(fp,field) \
252 /* read the size of the string */ \
253 READ_TYPE(fp,tmpint32,int32_t); \
254 DEBUG_PRINT("READ_BUF_STRING: var="__STRING(field)" strlen=%d",tmpint32); \
255 /* check if read would fit */ \
256 BUF_CHECK(fp,tmpint32+1); \
257 /* read string from the stream */ \
259 { READ(fp,BUF_CUR,(size_t)tmpint32); } \
260 /* null-terminate string in buffer */ \
261 BUF_CUR[tmpint32]='\0'; \
262 DEBUG_PRINT("READ_BUF_STRING: var="__STRING(field)" string=\"%s\"",BUF_CUR); \
263 /* prepare result */ \
265 BUF_SKIP(tmpint32+1);
267 /* read an array from a stram and store it as a null-terminated
268 array list (size for the array is allocated) */
269 #define READ_BUF_STRINGLIST(fp,arr) \
270 /* read the number of entries */ \
271 READ_TYPE(fp,tmp3int32,int32_t); \
272 DEBUG_PRINT("READ_STRLST: var="__STRING(arr)" num=%d",(int)tmp3int32); \
273 /* allocate room for *char[num+1] */ \
274 BUF_ALLOC(fp,arr,char *,tmp3int32+1); \
275 /* read all entries */ \
276 for (tmp2int32=0;tmp2int32<tmp3int32;tmp2int32++) \
278 READ_BUF_STRING(fp,(arr)[tmp2int32]); \
280 /* set last entry to NULL */ \
281 (arr)[tmp2int32]=NULL;
284 /* SKIP macros for skipping over certain parts of the protocol stream. */
286 /* skip a number of bytes foreward */
287 #define SKIP(fp,sz) \
288 DEBUG_PRINT("READ : skip %d bytes",(int)(sz)); \
289 /* read (skip) the specified number of bytes */ \
290 if (tio_skip(fp,sz)) \
292 DEBUG_PRINT("READ : skip error: %s",strerror(errno)); \
293 ERROR_OUT_READERROR(fp); \
296 /* read a string from the stream but don't do anything with the result */
297 #define SKIP_STRING(fp) \
298 /* read the size of the string */ \
299 READ_TYPE(fp,tmpint32,int32_t); \
300 DEBUG_PRINT("READ_STRING: skip %d bytes",(int)tmpint32); \
301 /* read (skip) the specified number of bytes */ \
304 /* skip a list of strings */
305 #define SKIP_STRINGLIST(fp) \
306 /* read the number of entries */ \
307 READ_TYPE(fp,tmp3int32,int32_t); \
308 DEBUG_PRINT("READ_STRLST: skip %d strings",(int)tmp3int32); \
309 /* read all entries */ \
310 for (tmp2int32=0;tmp2int32<tmp3int32;tmp2int32++) \
316 /* These are functions and macors for performing common operations in
317 the nslcd request/response protocol. */
319 /* returns a socket to the server or NULL on error (see errno),
320 socket should be closed with tio_close() */
321 TFILE *nslcd_client_open(void)
324 /* generic request code */
325 #define NSLCD_REQUEST(fp,action,writefn) \
326 /* open a client socket */ \
327 if ((fp=nslcd_client_open())==NULL) \
328 { ERROR_OUT_OPENERROR } \
329 /* write a request header with a request code */ \
330 WRITE_INT32(fp,(int32_t)NSLCD_VERSION) \
331 WRITE_INT32(fp,(int32_t)action) \
332 /* write the request parameters (if any) */ \
334 /* flush the stream */ \
335 if (tio_flush(fp)<0) \
337 DEBUG_PRINT("WRITE_FLUSH : error: %s",strerror(errno)); \
338 ERROR_OUT_WRITEERROR(fp); \
340 /* read and check response version number */ \
341 READ_TYPE(fp,tmpint32,int32_t); \
342 if (tmpint32!=(int32_t)NSLCD_VERSION) \
343 { ERROR_OUT_READERROR(fp) } \
344 /* read and check response request number */ \
345 READ_TYPE(fp,tmpint32,int32_t); \
346 if (tmpint32!=(int32_t)(action)) \
347 { ERROR_OUT_READERROR(fp) }
349 /* Read the response code (the result code of the query) from
351 #define READ_RESPONSE_CODE(fp) \
352 READ_TYPE(fp,tmpint32,int32_t); \
353 if (tmpint32!=(int32_t)NSLCD_RESULT_BEGIN) \
354 { ERROR_OUT_NOSUCCESS(fp) }
356 #endif /* not _NSLCD_PROT_H */