gdp / doc / developer / Libep.dbk @ master
History | View | Annotate | Download (94.7 KB)
1 | dc11518f | Eric Allman | <?xml version="1.0" encoding="US-ASCII"?> |
---|---|---|---|
2 | d63b8179 | Eric Allman | <!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" |
3 | "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"> |
||
4 | <article class="techreport"> |
||
5 | <articleinfo> |
||
6 | <title>Notes on "EP" Library</title> |
||
7 | |||
8 | <author> |
||
9 | <firstname>Eric</firstname> |
||
10 | |||
11 | <surname>Allman</surname> |
||
12 | </author> |
||
13 | |||
14 | <copyright> |
||
15 | 11ef2ab4 | Eric Allman | <year>2008, 2014–2018 Eric P. Allman. All rights reserved.</year> |
16 | d63b8179 | Eric Allman | </copyright> |
17 | |||
18 | 11ef2ab4 | Eric Allman | <date>2018-08-15</date> |
19 | d63b8179 | Eric Allman | </articleinfo> |
20 | |||
21 | <section> |
||
22 | <title>INTRODUCTION</title> |
||
23 | |||
24 | <para>This document describes the Enhanced Portability library. This is a |
||
25 | reduced version of Eric's Portability library (designed for sendmail), |
||
26 | removing many things that didn't work out or proved unnecessary, e.g., the |
||
27 | entire I/O subsystem. It was originally intended to be used in sendmail, |
||
28 | so some of the terminology is geared toward the email world; none the |
||
29 | less, it should be generally useful.</para> |
||
30 | |||
31 | 058dfca9 | Eric Allman | <para>Programs using <symbol>libep</symbol> should be able to minimize |
32 | <symbol>#ifdef</symbol> since often non-portable functionality is wrapped |
||
33 | in portability routines; for example, BSD-derived systems and |
||
34 | Linux-derived systems differ in how you get the name of the currently |
||
35 | running program. These differences are hidden if the application calls |
||
36 | <function>ep_app_getprogname</function>.</para> |
||
37 | |||
38 | d63b8179 | Eric Allman | <section> |
39 | <title>Design Goals</title> |
||
40 | |||
41 | <itemizedlist> |
||
42 | <listitem> |
||
43 | <para>Portable, to the extent possible. Where not possible, there |
||
44 | needs to be a clearly codified way to represent the externally |
||
45 | visible semantic differences.</para> |
||
46 | </listitem> |
||
47 | |||
48 | <listitem> |
||
49 | <para>Efficient.</para> |
||
50 | </listitem> |
||
51 | |||
52 | <listitem> |
||
53 | <para>Customizable -- try to implement mechanism, not policy.</para> |
||
54 | </listitem> |
||
55 | |||
56 | <listitem> |
||
57 | <para>TBD: It should be entirely UTF-8 internally. Any translations |
||
58 | to other character sets should be done on input or output, and then |
||
59 | only as strictly necessary.</para> |
||
60 | </listitem> |
||
61 | </itemizedlist> |
||
62 | </section> |
||
63 | |||
64 | <section> |
||
65 | <title>Assumptions</title> |
||
66 | |||
67 | <para>Use of this library requires that you have a C compiler that is |
||
68 | compliant with ANSI C as defined by ANSI/ISO 9899-1999. Also requires an |
||
69 | environment that is at least Posix based on Posix.1-2008.</para> |
||
70 | </section> |
||
71 | |||
72 | <section> |
||
73 | <title>Conventions</title> |
||
74 | |||
75 | <para><itemizedlist> |
||
76 | <listitem> |
||
77 | <para>All externally visible names (i.e., those not declared |
||
78 | "static" in a file) shall be named ep_* (for routine names) or Ep* |
||
79 | (for variable names). In a few cases, the names may begin with |
||
80 | __ep or __Ep; such names would be in the global namespace, but |
||
81 | 058dfca9 | Eric Allman | would be intended for use internal to the library only. There are |
82 | a few cases where "standard" names (such as |
||
83 | <function>strlcpy</function>) are defined if they are not included |
||
84 | in the standard library.</para> |
||
85 | d63b8179 | Eric Allman | </listitem> |
86 | </itemizedlist></para> |
||
87 | </section> |
||
88 | |||
89 | <section> |
||
90 | <title>Terminology</title> |
||
91 | |||
92 | <section> |
||
93 | <title>Warning, Error, Severe, Abort</title> |
||
94 | |||
95 | <para>These words get used fairly loosely, so they are worth defining. |
||
96 | In the context of libep:</para> |
||
97 | |||
98 | <itemizedlist> |
||
99 | <listitem> |
||
100 | <para>Warning means a condition that is expected in normal |
||
101 | operations, but is not the usual case. Reading an end-of-file on a |
||
102 | file might be a warning. Applications need to be aware of these, |
||
103 | but are expected to either ignore them or recover easily. This can |
||
104 | also be used for temporary errors which are likely to recover |
||
105 | after a delay. For example, the inability to open a connection to |
||
106 | a remote server might recover automatically if that server is |
||
107 | re-started. However, this sort of warnings that persist should |
||
108 | turn into permanent errors in a fashion appropriate for the |
||
109 | application.</para> |
||
110 | </listitem> |
||
111 | |||
112 | <listitem> |
||
113 | <para>Error means a situation that should not occur, but isn't |
||
114 | terribly unusual. For example, an attempt to open a file that |
||
115 | isn't accessible would be an error. Applications must be aware of |
||
116 | such conditions and handle them gracefully.</para> |
||
117 | </listitem> |
||
118 | |||
119 | <listitem> |
||
120 | <para>Severe means a situation that should not occur iand requires |
||
121 | exceptional handling. Severe errors are drastic conditions, but |
||
122 | are not so severe that the application can't take some reasonable |
||
123 | backout action.</para> |
||
124 | </listitem> |
||
125 | |||
126 | <listitem> |
||
127 | <para>Abort means a situation so drastic that an application |
||
128 | cannot be expected to make any reasonable recovery. These might |
||
129 | include assertion errors and memory allocation failures during a |
||
130 | critical step (e.g., something where backing out a single thread |
||
131 | won't solve the problem). About the only thing an application can |
||
132 | reasonably do is log an abort error and exit. In particular, an |
||
133 | abort is appropriate when an attempt for an application to recover |
||
134 | is likely to do additional damage. These should be extremely |
||
135 | rare.</para> |
||
136 | </listitem> |
||
137 | </itemizedlist> |
||
138 | </section> |
||
139 | </section> |
||
140 | </section> |
||
141 | |||
142 | <section> |
||
143 | <title>GENERAL ISSUES</title> |
||
144 | |||
145 | <para>All files using this library must use "<code>#include |
||
146 | <ep/ep.h></code>".</para> |
||
147 | </section> |
||
148 | |||
149 | <section> |
||
150 | <title>STATUS CODES</title> |
||
151 | |||
152 | <para>Almost all functions return an <type>EP_STAT</type> value. This is a |
||
153 | short (integer-encoded) status value that gives you a brief idea of how |
||
154 | severe the problem was and some idea of what it was, but not much else. |
||
155 | Think of it as an errno equivalent. Functions returning any status other |
||
156 | than OK are expected to provide some other way of returning detailed |
||
157 | data.</para> |
||
158 | |||
159 | <para><type>EP_STAT</type>s are also used as message identifiers for |
||
160 | logging (below).</para> |
||
161 | |||
162 | <para>Status codes are defined in |
||
163 | <filename><ep/ep_stat.h></filename>.</para> |
||
164 | |||
165 | <section> |
||
166 | <title>Severities</title> |
||
167 | |||
168 | <para>Severities are:</para> |
||
169 | |||
170 | <variablelist termlength="20"> |
||
171 | <varlistentry> |
||
172 | <term><errortype>EP_STAT_SEV_OK</errortype></term> |
||
173 | |||
174 | <listitem> |
||
175 | <para>Everything is fine. Detail may contain info. For messages, |
||
176 | can be used for debugging.</para> |
||
177 | </listitem> |
||
178 | </varlistentry> |
||
179 | |||
180 | <varlistentry> |
||
181 | <term><errortype>EP_STAT_SEV_WARN</errortype></term> |
||
182 | |||
183 | <listitem> |
||
184 | <para>The function partially succeeded, but there is something |
||
185 | that the application should be aware of, e.g., an end of file or a |
||
186 | short data read. Alternatively, the functionfailed, but it might |
||
187 | work again on a later try.</para> |
||
188 | </listitem> |
||
189 | </varlistentry> |
||
190 | |||
191 | <varlistentry> |
||
192 | <term><errortype>EP_STAT_SEV_ERROR</errortype></term> |
||
193 | |||
194 | <listitem> |
||
195 | <para>A normal error status. The call failed.</para> |
||
196 | </listitem> |
||
197 | </varlistentry> |
||
198 | |||
199 | <varlistentry> |
||
200 | <term><errortype>EP_STAT_SEV_SEVERE</errortype></term> |
||
201 | |||
202 | <listitem> |
||
203 | <para>A severe error status. The call failed, and the caller |
||
204 | should try to back out.</para> |
||
205 | </listitem> |
||
206 | </varlistentry> |
||
207 | |||
208 | <varlistentry> |
||
209 | <term><errortype>EP_STAT_SEV_ABORT</errortype></term> |
||
210 | |||
211 | <listitem> |
||
212 | dc11518f | Eric Allman | <para>A critical error occured — you should clean up and |
213 | exit as soon as possible; the program cannot be expected to |
||
214 | operate correctly.</para> |
||
215 | d63b8179 | Eric Allman | </listitem> |
216 | </varlistentry> |
||
217 | </variablelist> |
||
218 | |||
219 | <para>Some functions for testing values:</para> |
||
220 | |||
221 | <variablelist> |
||
222 | <varlistentry> |
||
223 | <term><function>EP_STAT_SEV_ISOK</function>(st)</term> |
||
224 | |||
225 | <listitem> |
||
226 | <para>Returns true if this is an |
||
227 | <errortype>EP_STAT_SEV_OK</errortype> status code.</para> |
||
228 | </listitem> |
||
229 | </varlistentry> |
||
230 | |||
231 | <varlistentry> |
||
232 | <term><function>EP_STAT_SEV_WARN</function>(st)</term> |
||
233 | |||
234 | <listitem> |
||
235 | <para>Returns true if this is an "warning" severity status code: |
||
236 | <errortype>EP_STAT_SEV_WARN</errortype>.</para> |
||
237 | </listitem> |
||
238 | </varlistentry> |
||
239 | |||
240 | <varlistentry> |
||
241 | <term><function>EP_STAT_SEV_ISERROR</function>(st)</term> |
||
242 | |||
243 | <listitem> |
||
244 | <para>Returns true if this is an "error" severity status code: |
||
245 | <errortype>EP_STAT_SEV_ERROR</errortype></para> |
||
246 | </listitem> |
||
247 | </varlistentry> |
||
248 | |||
249 | <varlistentry> |
||
250 | 1b56a7ee | Eric Allman | <term><function>EP_STAT_SEV_ISFAIL</function>(st)</term> |
251 | d63b8179 | Eric Allman | |
252 | <listitem> |
||
253 | 1b56a7ee | Eric Allman | <para>Returns true if this message is a "failure" severity status |
254 | code: <errortype>EP_STAT_SEV_ERROR</errortype> or higher.</para> |
||
255 | d63b8179 | Eric Allman | </listitem> |
256 | </varlistentry> |
||
257 | |||
258 | <varlistentry> |
||
259 | <term><function>EP_STAT_SEV_ISSEVERE</function>(st)</term> |
||
260 | |||
261 | <listitem> |
||
262 | <para>Returns true if this is an "severe" severity status code: |
||
263 | <errortype>EP_STAT_SEV_SEVERE</errortype></para> |
||
264 | </listitem> |
||
265 | </varlistentry> |
||
266 | |||
267 | <varlistentry> |
||
268 | 1b56a7ee | Eric Allman | <term><function>EP_STAT_SEV_ISSFAIL</function>(st)</term> |
269 | d63b8179 | Eric Allman | |
270 | <listitem> |
||
271 | <para>Returns true if this message is a "major" severity status |
||
272 | code: <errortype>EP_STAT_SEV_SEVERE</errortype> or higher</para> |
||
273 | </listitem> |
||
274 | </varlistentry> |
||
275 | |||
276 | <varlistentry> |
||
277 | <term><function>EP_STAT_SEV_ISABORT</function>(st)</term> |
||
278 | |||
279 | <listitem> |
||
280 | <para>Returns true if this is an "abort" severity status code: |
||
281 | <errortype>EP_STAT_SEV_ABORT</errortype></para> |
||
282 | </listitem> |
||
283 | </varlistentry> |
||
284 | </variablelist> |
||
285 | </section> |
||
286 | |||
287 | <section> |
||
288 | <title>Status Code Representation</title> |
||
289 | |||
290 | <para>Status codes are represented as four-part values: severity, |
||
291 | registry, module, and detail. The severities are described above. |
||
292 | Registries are globally registered by neophilic.com and are defined in |
||
293 | ep_registry.h. There are some registries for general use; in particular, |
||
294 | registry numbers between 0x001 and 0x1FF are available for local |
||
295 | (non-global) registry at the corporate or local level. Modules are |
||
296 | defined by registries, and detail is defined by module. It is |
||
297 | <emphasis>never</emphasis> acceptable to look at detail unless you |
||
298 | recognize the module. (OK, you can print it out for debugging.) Severity |
||
299 | = 3 bits, registry = 13 bits, module = 6 bits, detail = 10 bits.</para> |
||
300 | |||
301 | <para>Any severity where the top bit is zero is considered "OK", and the |
||
302 | rest of the word is available to encode a non-negative integer.</para> |
||
303 | |||
304 | <para>Status codes are represented as structures to ensure type safety. |
||
305 | Occassionally you might want to convert a status to or from a long |
||
306 | int:</para> |
||
307 | |||
308 | 42d9d20e | Eric Allman | <programlisting>int EP_STAT_TO_INT(EP_STAT stat) // convert status to unsigned int |
309 | EP_STAT EP_STAT_FROM_INT(unsigned int istat) // convert unsigned integer to status</programlisting> |
||
310 | d63b8179 | Eric Allman | |
311 | <para>The constituent parts of the status code can also be |
||
312 | extracted:</para> |
||
313 | |||
314 | <variablelist> |
||
315 | <varlistentry> |
||
316 | <term><function>EP_STAT_SEV</function>(st)</term> |
||
317 | |||
318 | <listitem> |
||
319 | <para>Returns the severity part of the status code.</para> |
||
320 | </listitem> |
||
321 | </varlistentry> |
||
322 | |||
323 | <varlistentry> |
||
324 | <term><function>EP_STAT_REGISTRY</function>(st)</term> |
||
325 | |||
326 | <listitem> |
||
327 | <para>Returns the registry part of the status code.</para> |
||
328 | </listitem> |
||
329 | </varlistentry> |
||
330 | |||
331 | <varlistentry> |
||
332 | <term><function>EP_STAT_MODULE</function>(st)</term> |
||
333 | |||
334 | <listitem> |
||
335 | <para>Returns the module part of the status code.</para> |
||
336 | </listitem> |
||
337 | </varlistentry> |
||
338 | |||
339 | <varlistentry> |
||
340 | <term><function>EP_STAT_DETAIL</function>(st)</term> |
||
341 | |||
342 | <listitem> |
||
343 | <para>Returns the detail part of the status code.</para> |
||
344 | </listitem> |
||
345 | </varlistentry> |
||
346 | </variablelist> |
||
347 | |||
348 | <para>To compare two statuses for equality, use |
||
349 | <function>EP_STAT_IS_SAME</function>(a, b).</para> |
||
350 | |||
351 | <para>As a special case, if the severity is |
||
352 | <errortype>EP_STAT_SEV_OK</errortype> the rest of the word is ignored; |
||
353 | 42d9d20e | Eric Allman | this can be used to pass small integers (no more than 31 bits) of |
354 | d63b8179 | Eric Allman | information.</para> |
355 | </section> |
||
356 | 42d9d20e | Eric Allman | |
357 | <section> |
||
358 | <title>Predefined Status Codes</title> |
||
359 | |||
360 | <para>All status codes from this library are in the |
||
361 | <constant>EP_REGISTRY_EPLIB</constant> registery. There are several |
||
362 | predefined status codes for generic use, all using module |
||
363 | <constant>EP_STAT_MOD_GENERIC</constant>:</para> |
||
364 | |||
365 | <informaltable border="1"> |
||
366 | 11ef2ab4 | Eric Allman | <col width="4*"/> |
367 | ac90b0f6 | Eric Allman | |
368 | 11ef2ab4 | Eric Allman | <col width="6*"/> |
369 | ac90b0f6 | Eric Allman | |
370 | 42d9d20e | Eric Allman | <tr> |
371 | <td>EP_STAT_OK</td> |
||
372 | |||
373 | <td>No error (also integer 0)</td> |
||
374 | </tr> |
||
375 | |||
376 | <tr> |
||
377 | <td>EP_STAT_WARN</td> |
||
378 | |||
379 | <td>Generic warning status</td> |
||
380 | </tr> |
||
381 | |||
382 | <tr> |
||
383 | <td>EP_STAT_ERROR</td> |
||
384 | |||
385 | <td>Generic error status</td> |
||
386 | </tr> |
||
387 | |||
388 | <tr> |
||
389 | <td>EP_STAT_SEVERE</td> |
||
390 | |||
391 | <td>Generic severe error status</td> |
||
392 | </tr> |
||
393 | |||
394 | <tr> |
||
395 | <td>EP_STAT_ABORT</td> |
||
396 | |||
397 | <td>Generic abortive status</td> |
||
398 | </tr> |
||
399 | |||
400 | <tr> |
||
401 | <td>EP_STAT_OUT_OF_MEMORY</td> |
||
402 | |||
403 | <td>Out of memory</td> |
||
404 | </tr> |
||
405 | |||
406 | <tr> |
||
407 | <td>EP_STAT_ARG_OUT_OF_RANGE</td> |
||
408 | |||
409 | <td>An argument was out of range</td> |
||
410 | </tr> |
||
411 | |||
412 | <tr> |
||
413 | <td>EP_STAT_END_OF_FILE</td> |
||
414 | |||
415 | <td>End of input</td> |
||
416 | </tr> |
||
417 | |||
418 | <tr> |
||
419 | <td>EP_STAT_TIME_BADFORMAT</td> |
||
420 | |||
421 | <td>Couldn't parse a date/time string</td> |
||
422 | </tr> |
||
423 | ac90b0f6 | Eric Allman | |
424 | <tr> |
||
425 | <td>EP_STAT_BUF_OVERFLOW</td> |
||
426 | |||
427 | <td>Buffer overflow averted</td> |
||
428 | </tr> |
||
429 | 8d7fc458 | Eric Allman | |
430 | <tr> |
||
431 | <td>EP_STAT_ASSERT_ABORT</td> |
||
432 | |||
433 | <td>Assertion failiure: backout now!</td> |
||
434 | </tr> |
||
435 | 42d9d20e | Eric Allman | </informaltable> |
436 | |||
437 | <para>There is also a special module |
||
438 | ac90b0f6 | Eric Allman | <constant>EP_STAT_MOD_ERRNO</constant> that encodes Posix-style errnos |
439 | (i.e., use <function>EP_STAT_DETAIL</function> on codes returned by that |
||
440 | module to get the Posix errno code).</para> |
||
441 | 42d9d20e | Eric Allman | </section> |
442 | |||
443 | <section> |
||
444 | <title>Manipulating Status Codes</title> |
||
445 | |||
446 | <para>There are several routines to print error codes or create them on |
||
447 | the fly. Note that <function>ep_stat_tostr</function> returns the buffer |
||
448 | itself.</para> |
||
449 | |||
450 | <programlisting>// create status code from UNIX errno |
||
451 | extern EP_STAT ep_stat_from_errno( |
||
452 | int uerrno); |
||
453 | |||
454 | // return string representation of status |
||
455 | char *ep_stat_tostr( |
||
456 | EP_STAT estat, |
||
457 | char *buf, |
||
458 | size_t bsize); |
||
459 | |||
460 | // return string representation of severity (in natural language) |
||
461 | const char *ep_stat_sev_tostr( |
||
462 | int sev); |
||
463 | |||
464 | // print a status code and abort (never returns) |
||
465 | void ep_stat_abort( |
||
466 | EP_STAT estat);</programlisting> |
||
467 | </section> |
||
468 | |||
469 | <section> |
||
470 | <title>Creating New Status Codes</title> |
||
471 | |||
472 | <para>Libraries and applications can create their own specific error |
||
473 | codes. There are four steps to do this:</para> |
||
474 | |||
475 | <orderedlist> |
||
476 | <listitem> |
||
477 | <para>Determine the registry. The registry name space is divided as |
||
478 | follows:</para> |
||
479 | |||
480 | <informaltable border="1"> |
||
481 | 11ef2ab4 | Eric Allman | <col width="4*"/> |
482 | ac90b0f6 | Eric Allman | |
483 | 11ef2ab4 | Eric Allman | <col width="6*"/> |
484 | ac90b0f6 | Eric Allman | |
485 | 42d9d20e | Eric Allman | <tr> |
486 | <td>0x000 (<constant>EP_REGISTRY_GENERIC</constant>)</td> |
||
487 | |||
488 | <td>reserved for generic status codes</td> |
||
489 | </tr> |
||
490 | |||
491 | <tr> |
||
492 | <td>0x001 (<constant>EP_REGISTRY_USER</constant>)</td> |
||
493 | |||
494 | <td>available for internal use to an application</td> |
||
495 | </tr> |
||
496 | |||
497 | <tr> |
||
498 | <td>0x002–0x07F</td> |
||
499 | |||
500 | <td>available for local, unregistered use, such as separate |
||
501 | applications within an application suite</td> |
||
502 | </tr> |
||
503 | |||
504 | <tr> |
||
505 | <td>0x080–0x0FF</td> |
||
506 | |||
507 | <td>available for internal corporate registry, but not |
||
508 | registered globally; conflicts may occur between organizations |
||
509 | but not within an organization</td> |
||
510 | </tr> |
||
511 | |||
512 | <tr> |
||
513 | <td>0x100 (<constant>EP_REGISTRY_EPLIB</constant>)</td> |
||
514 | |||
515 | <td>reserved for libep</td> |
||
516 | </tr> |
||
517 | |||
518 | <tr> |
||
519 | <td>0x101–0x6FF</td> |
||
520 | |||
521 | <td>available for centrally managed global registry — |
||
522 | contact the libep maintainers for an allocation</td> |
||
523 | </tr> |
||
524 | |||
525 | <tr> |
||
526 | <td>0x700–0x7FF</td> |
||
527 | |||
528 | <td>reserved</td> |
||
529 | </tr> |
||
530 | </informaltable> |
||
531 | </listitem> |
||
532 | |||
533 | <listitem> |
||
534 | <para>Determine the module(s) in which the error code should exist. |
||
535 | These must be unique within a registry and in the range |
||
536 | 0x00–0xFF.</para> |
||
537 | </listitem> |
||
538 | |||
539 | <listitem> |
||
540 | <para>Define the error codes you want to use using |
||
541 | <function>EP_STAT_NEW</function>, e.g.,</para> |
||
542 | |||
543 | <programlisting>#define FOO_STAT_ELEPHANT EP_STAT_NEW(ERROR, EP_REGISTRY_FOO, MOD_BAR, 1) |
||
544 | #define FOO_STAT_GIRAFFE EP_STAT_NEW(SEVERE, EP_REGISTRY_FOO, MOD_BAR, 2)</programlisting> |
||
545 | </listitem> |
||
546 | |||
547 | <listitem> |
||
548 | <para>(Optional step) Define the strings associated with the error |
||
549 | codes when they are printed. These are done by populating a table |
||
550 | and then calling <function>ep_stat_register_strings</function>. For |
||
551 | example:</para> |
||
552 | |||
553 | <programlisting>struct ep_stat_reg_strings FooStatusCodes[] = |
||
554 | { |
||
555 | FOO_STAT_ELEPHANT, "elephant in the room", }, |
||
556 | FOO_STAT_GIRAFFE, "too tall", }, |
||
557 | EP_STAT_OK, NULL, } |
||
558 | } |
||
559 | |||
560 | ep_stat_reg_strings(FooStatusCodes);</programlisting> |
||
561 | </listitem> |
||
562 | </orderedlist> |
||
563 | </section> |
||
564 | d63b8179 | Eric Allman | </section> |
565 | |||
566 | <section> |
||
567 | <title>INITIALIZATION</title> |
||
568 | |||
569 | <para>Although libep will generally work without initialization, in some |
||
570 | cases you may need to give it information about your usage. To do this |
||
571 | call <function>ep_lib_init</function>:</para> |
||
572 | |||
573 | <programlisting>#include <ep/ep.h> |
||
574 | |||
575 | EP_STAT |
||
576 | ep_lib_init(uint32_t flags)</programlisting> |
||
577 | |||
578 | <para>Flags can be:</para> |
||
579 | |||
580 | 42d9d20e | Eric Allman | <informaltable> |
581 | d63b8179 | Eric Allman | <tgroup cols="2"> |
582 | <tbody> |
||
583 | <row> |
||
584 | <entry>EP_LIB_USEPTHREADS</entry> |
||
585 | |||
586 | <entry>Initialize the thread support</entry> |
||
587 | </row> |
||
588 | </tbody> |
||
589 | </tgroup> |
||
590 | 42d9d20e | Eric Allman | </informaltable> |
591 | d63b8179 | Eric Allman | </section> |
592 | |||
593 | <section> |
||
594 | <title>MEMORY ALLOCATION AND RESOURCE POOLS</title> |
||
595 | |||
596 | <section> |
||
597 | <title>Memory</title> |
||
598 | |||
599 | <para>Memory support is much like malloc/free, but with some additional |
||
600 | functionality. One crucial difference is that most of these routines do |
||
601 | not return if memory is exhausted; instead they can call a cleanup |
||
602 | routine that might (for example) eliminate some old cache entries, or |
||
603 | pick a "victim" thread to kill and reclaim its memory. If successful |
||
604 | they can continue, otherwise the process is aborted.</para> |
||
605 | |||
606 | <programlisting> #include <ep/ep_mem.h> |
||
607 | |||
608 | void * |
||
609 | ep_mem_malloc(size_t nbytes) // allocate uninitialized memory |
||
610 | |||
611 | void * |
||
612 | ep_mem_zalloc(size_t nbytes) // allocate zeroed memory |
||
613 | |||
614 | void * |
||
615 | ep_mem_ralloc(size_t nbytes) // allocate randomized memory |
||
616 | |||
617 | void * |
||
618 | ep_mem_ealloc(size_t nbytes) // allocate memory, failure OK |
||
619 | |||
620 | void * |
||
621 | ep_mem_realloc(size_t nbytes, // reallocate (extend) memory |
||
622 | void *curmem) |
||
623 | |||
624 | void * |
||
625 | ep_mem_falloc(size_t nbytes, // allocate memory (see flags) |
||
626 | uint32_t flags) |
||
627 | |||
628 | void |
||
629 | ep_mem_mfree(void *mem) // free indicated memory |
||
630 | |||
631 | struct ep_malloc_functions |
||
632 | { |
||
633 | void *(*m_malloc)(size_t); |
||
634 | void *(*m_realloc)(void*, size_t); |
||
635 | void *(*m_valloc)(size_t); |
||
636 | void (*m_free)(void*); |
||
637 | }; |
||
638 | |||
639 | void |
||
640 | ep_mem_set_malloc_functions( // set underlying malloc functions |
||
641 | struct ep_malloc_functions *funcs)</programlisting> |
||
642 | |||
643 | <para>The <function>ep_mem_malloc</function>, |
||
644 | <function>ep_mem_zalloc</function>, <function>ep_mem_ralloc</function>, |
||
645 | and <function>ep_mem_realloc</function> are all implemented in terms of |
||
646 | <function>ep_mem_falloc</function>, which uses flags to tune the |
||
647 | behavior (see below). The primary interface is |
||
648 | <function>ep_mem_malloc</function>, which returns uninitialized data; |
||
649 | <function>ep_mem_zalloc</function> returns zeroed memory, and |
||
650 | <function>ep_mem_ralloc</function> returns memory that is initialized to |
||
651 | random or some other nonsensical data. The last would probably be used |
||
652 | only for debugging, and can be turned on at runtime using a debug flag |
||
653 | <remark>XXX TBD</remark>.</para> |
||
654 | |||
655 | <para>In all allocation schemes, the function returns a pointer to the |
||
656 | dc11518f | Eric Allman | allocated data — they cannot normally return |
657 | <constant>NULL</constant> (but see below). If they cannot allocate the |
||
658 | memory, they <remark>do error recovery (XXX describe)</remark>. If |
||
659 | recovery fails, the allocation system will abort the process. However, |
||
660 | d63b8179 | Eric Allman | <function>ep_mem_ealloc</function> can return <constant>NULL</constant> |
661 | on memory allocation failure, as can <function>ep_mem_falloc</function> |
||
662 | if the <constant>EP_MEM_F_FAILOK</constant> flag bit is set (see |
||
663 | below).</para> |
||
664 | |||
665 | <para>Flag bits are as follows:</para> |
||
666 | |||
667 | <variablelist> |
||
668 | <varlistentry> |
||
669 | <term><constant>EP_MEM_F_FAILOK</constant></term> |
||
670 | |||
671 | <listitem> |
||
672 | <para>Permits the routine to return <constant>NULL</constant> on |
||
673 | failure. This modifies the behavior described above. Note that if |
||
674 | this is set every call to the <function>ep_*malloc</function> |
||
675 | routines may potentially fail.</para> |
||
676 | </listitem> |
||
677 | </varlistentry> |
||
678 | |||
679 | <varlistentry> |
||
680 | <term><constant>EP_MEM_F_ZERO</constant></term> |
||
681 | |||
682 | <listitem> |
||
683 | <para>Zero any returned memory.</para> |
||
684 | </listitem> |
||
685 | </varlistentry> |
||
686 | |||
687 | <varlistentry> |
||
688 | <term><constant>EP_MEM_F_TRASH</constant></term> |
||
689 | |||
690 | <listitem> |
||
691 | <para>Randomize any returned memory.</para> |
||
692 | </listitem> |
||
693 | </varlistentry> |
||
694 | |||
695 | <varlistentry> |
||
696 | <term><constant>EP_MEM_F_ALIGN</constant></term> |
||
697 | |||
698 | <listitem> |
||
699 | <para>The application would prefer that the allocation is |
||
700 | page-aligned. This is not available on all architectures, and |
||
701 | other architectures do it automatically if the allocation is at |
||
702 | least as large as a page.</para> |
||
703 | </listitem> |
||
704 | </varlistentry> |
||
705 | |||
706 | <varlistentry> |
||
707 | <term><constant>EP_MEM_F_WAIT</constant></term> |
||
708 | |||
709 | <listitem> |
||
710 | <para>If memory is unavailable, try to wait for it to become |
||
711 | available (e.g., because another thread has released memory). |
||
712 | <remark>This is not yet implemented.</remark></para> |
||
713 | </listitem> |
||
714 | </varlistentry> |
||
715 | </variablelist> |
||
716 | |||
717 | <para>Specifying <constant>EP_MEM_F_ZERO</constant> and |
||
718 | <constant>EP_MEM_F_TRASH</constant> at the same time is |
||
719 | undefined.</para> |
||
720 | |||
721 | <para>Since <function>ep_mem_[mzr]alloc</function> are implemented as |
||
722 | macros, they can't be used as pointers to functions (e.g., for |
||
723 | specifying a memory allocator callback to a third party app). For this |
||
724 | reason, there are also <function>ep_mem_[mzr]alloc_f</function> "real" |
||
725 | functions to be used in this context.</para> |
||
726 | |||
727 | <para>Generally, unthreaded code and most application code will probably |
||
728 | be happy with the defaults. Threaded server code (which cannot be |
||
729 | permitted to die) is expected to catch the out of memory condition, do |
||
730 | some recovery operation such as terminating a task, and return |
||
731 | <errorcode>EP_MEM_STAT_TRYAGAIN</errorcode> so the memory allocation can |
||
732 | retry.</para> |
||
733 | |||
734 | <para>[[[XXX Document ep_set_malloc_functions XXX]]]</para> |
||
735 | </section> |
||
736 | |||
737 | <section> |
||
738 | <title>Resource Pools</title> |
||
739 | |||
740 | <para>Resources are allocatable global entities such as memory, file |
||
741 | descriptors, etc. Resources can be collected together into pools and |
||
742 | then freed in one call. Memory is specially handled to allow fast |
||
743 | allocation from a pool --- specifically, a chunk of memory can be |
||
744 | allocated from the heap to a pool and then sub-allocated as needed. |
||
745 | Allocating memory from resource pools is particularly fast for small |
||
746 | allocations. Also, pool allocations that are of a size that is a |
||
747 | multiple of the page size are guaranteed to return a page-aligned |
||
748 | pointer. This is particularly useful to allow the I/O level to implement |
||
749 | zero-copy I/O.</para> |
||
750 | |||
751 | <para>The heap used is the one that is current when |
||
752 | <function>ep_rpool_new</function> is invoked.</para> |
||
753 | |||
754 | <programlisting> #include <ep/ep_mem.h> |
||
755 | |||
756 | EP_RPOOL * |
||
757 | ep_rpool_new(const char *name, // for debugging |
||
758 | size_t qsize) // min memory allocation quantum |
||
759 | |||
760 | EP_STAT |
||
761 | ep_rpool_free(EP_RPOOL *rp) // free pool and all resources |
||
762 | |||
763 | void * |
||
764 | ep_rpool_malloc(EP_RPOOL *rp, // the pool to allocate from |
||
765 | size_t nbytes) // number of bytes |
||
766 | |||
767 | void * |
||
768 | ep_rpool_zalloc(EP_RPOOL *rp, // the pool to allocate from |
||
769 | size_t nbytes) // number of bytes |
||
770 | |||
771 | void * |
||
772 | ep_rpool_xalloc(EP_RPOOL *rp, // the pool to allocate from |
||
773 | size_t nbytes, // number of bytes |
||
774 | const char *filename, // file name (for debugging) |
||
775 | int lineno, // line number (for debugging) |
||
776 | uint32_t flags) // flag bits (see below) |
||
777 | |||
778 | void * |
||
779 | ep_rpool_strdup(EP_RPOOL *rp, // the pool to allocate from |
||
780 | char *str) // the string to save |
||
781 | |||
782 | void * |
||
783 | ep_rpool_realloc(EP_RPOOL *rp, // pool to allocate from |
||
784 | void *old mem, // old memory pointer |
||
785 | size_t oldsize, // old allocation size |
||
786 | size_t newsize) // new allocation size |
||
787 | |||
788 | void |
||
789 | ep_rpool_mfree(EP_RPOOL *rp, // the pool to release to |
||
790 | void *p); // the memory |
||
791 | |||
792 | void |
||
793 | ep_rpool_mfreeto(EP_RPOOL *rp, // the pool to release to |
||
794 | void *p); // restore up the pool to here |
||
795 | |||
796 | EP_STAT |
||
797 | ep_rpool_attach(EP_RPOOL *rp, // the resource pool |
||
798 | void freefunc(void *arg), // a function to call on free |
||
799 | void *arg) // argument to pass to it</programlisting> |
||
800 | |||
801 | <para>The <function>ep_rpool_mfreeto</function>() routine lets you treat |
||
802 | rpool memory like a stack; this call releases everything allocated back |
||
803 | to (and including) the pointer given. If <computeroutput>p == |
||
804 | NULL</computeroutput>, the entire memory contents of the rpool are |
||
805 | freed, but the rpool itself is still active. Deep care needs to be taken |
||
806 | here: if a subordinate routine is called that allocates memory from the |
||
807 | rpool, you may end up deallocating memory that is still in use. |
||
808 | <remark>Not implemented at this time.</remark></para> |
||
809 | |||
810 | <para>The <function>ep_rpool_attach</function>() routine is used to |
||
811 | associate other resources (such as files) with a pool. The corresponding |
||
812 | free functions will be invoked when the pool is freed.</para> |
||
813 | |||
814 | <para>In most cases, passing in <parameter>rp</parameter> == |
||
815 | <constant>NULL</constant> treats the call like the corresponding heap |
||
816 | allocation. In this case the caller is responsible for freeing the |
||
817 | memory. For example, |
||
818 | <function>ep_rpool_malloc</function>(<constant>NULL</constant>, |
||
819 | <varname>nbytes</varname>) is equivalent to |
||
820 | <function>ep_mem_malloc</function>(<varname>nbytes</varname>).</para> |
||
821 | |||
822 | <para>The distinction between multiple heaps and resource pools are that |
||
823 | heaps are not intended for application use other than for doing recovery |
||
824 | for out-of-memory conditions. Pools are intended for general use. Pools |
||
825 | are fast at allocation time (since they just grab space from the end of |
||
826 | the pool) and fast at free time (since the entire pool can be |
||
827 | deallocated at once); heaps are comparatively slow.</para> |
||
828 | |||
829 | <para>When any memory collections (heaps or pools) are freed, all |
||
830 | objects allocated from that collection are freed (i.e., their |
||
831 | destructors are automatically invoked).</para> |
||
832 | </section> |
||
833 | |||
834 | <section> |
||
835 | <title>Opening Memory as a File</title> |
||
836 | |||
837 | <programlisting> FILE * |
||
838 | a5a912e2 | Eric Allman | ep_fopen_smem(void *buf, // block of memory to open |
839 | d63b8179 | Eric Allman | size_t bsize, // size of that memory |
840 | const char *mode) // fopen(3) mode string</programlisting> |
||
841 | </section> |
||
842 | </section> |
||
843 | |||
844 | <section> |
||
845 | <title>TIME</title> |
||
846 | |||
847 | <para>The ep library has a separate time abstraction. This is for two |
||
848 | reasons: first, it guarantees that the number of seconds since January 1, |
||
849 | 1970 will be sufficiently long to last past 2038 (this varies from system |
||
850 | to system), and it includes a "<structfield>tv_accuracy</structfield>" |
||
851 | (type float) to indicate the approximate accuracy of the clock relative to |
||
852 | absolute time. For example, a clock synchronized from a GPS clock might be |
||
853 | accurate within perhaps 100nsec, whereas a standard crystal clock |
||
854 | synchronized once a day might only have an accuracy of a few |
||
855 | seconds.</para> |
||
856 | |||
857 | <programlisting>#include <ep/ep_time.h> |
||
858 | |||
859 | typedef struct |
||
860 | { |
||
861 | int64_t tv_sec; // seconds since Jan 1, 1970 |
||
862 | int32_t tv_nsec; // nanoseconds |
||
863 | float tv_accuracy; // clock accuracy in seconds |
||
864 | } EP_TIME_SPEC; |
||
865 | |||
866 | 65ffb923 | Eric Allman | #define EP_TIME_NOTIME (-INT64_MAX) |
867 | #define EP_TIME_MAXTIME (INT64_MAX) |
||
868 | |||
869 | d63b8179 | Eric Allman | EP_STAT |
870 | ep_time_now( // return current time |
||
871 | EP_TIME_SPEC *tv); |
||
872 | |||
873 | EP_STAT |
||
874 | ep_time_deltanow( // return time in the future (or past) |
||
875 | uint64_t delta_nanoseconds, |
||
876 | EP_TIME_SPEC *tv); |
||
877 | |||
878 | void |
||
879 | ep_time_add_delta( // add a delta to a time (delta may be negative) |
||
880 | EP_TIME_SPEC *delta, |
||
881 | EP_TIME_SPEC *tv); |
||
882 | |||
883 | bool |
||
884 | ep_time_before( // determine if A occurred before B |
||
885 | EP_TIME_SPEC *a, |
||
886 | EP_TIME_SPEC *b); |
||
887 | |||
888 | void |
||
889 | ep_time_from_nsec( // create a time from a scalar number of nanoseconds |
||
890 | 65ffb923 | Eric Allman | int64_t nsec, |
891 | EP_TIME_SPEC *tv); |
||
892 | |||
893 | void |
||
894 | ep_time_from_sec( // create a time from a scalar number of seconds |
||
895 | int64_t sec, |
||
896 | d63b8179 | Eric Allman | EP_TIME_SPEC *tv); |
897 | |||
898 | float |
||
899 | ep_time_accuracy(void); // return putative clock accuracy |
||
900 | |||
901 | void |
||
902 | ep_time_setaccuracy( // set the clock accuracy (may not be available) |
||
903 | float accuracy); |
||
904 | |||
905 | void |
||
906 | ep_time_format( // format a time string into a buffer |
||
907 | EP_TIME_SPEC *tv, |
||
908 | char *buf, |
||
909 | size_t bufsize, |
||
910 | 034d97fd | Eric Allman | uint32_t flags); |
911 | d63b8179 | Eric Allman | |
912 | void |
||
913 | ep_time_print( // format a time string to a file |
||
914 | EP_TIME_SPEC *tv, |
||
915 | FILE *fp, |
||
916 | 034d97fd | Eric Allman | uint32_t flags); |
917 | |||
918 | // values for ep_time_format and ep_time_print flags |
||
919 | #define EP_TIME_FMT_DEFAULT 0 // pseudo-flag |
||
920 | #define EP_TIME_FMT_HUMAN 0x00000001 // format for humans |
||
921 | #define EP_TIME_FMT_NOFUZZ 0x00000002 // suppress accuracy printing |
||
922 | d63b8179 | Eric Allman | |
923 | EP_STAT |
||
924 | ep_time_parse( // parse a time string |
||
925 | const char *timestr, |
||
926 | d2647d1f | Eric Allman | EP_TIME_SPEC *tv, |
927 | uint32_t flags); |
||
928 | |||
929 | // values for ep_time_parse flags |
||
930 | #define EP_TIME_USE_UTC 0x00000000 // assume UTC (default) |
||
931 | #define EP_TIME_USE_LOCALTIME 0x00000001 // assume times in local zone |
||
932 | d63b8179 | Eric Allman | |
933 | EP_STAT |
||
934 | ep_time_nanosleep( // sleep for the indicated number of nanoseconds |
||
935 | int64_t nanoseconds); |
||
936 | |||
937 | bool |
||
938 | d2647d1f | Eric Allman | EP_TIME_IS_VALID( // test to see if a timestamp is valid |
939 | d63b8179 | Eric Allman | EP_TIME_SPEC *tv); |
940 | |||
941 | void |
||
942 | EP_TIME_INVALIDATE( // invalidate a timestamp |
||
943 | EP_TIME_SPEC *tv);</programlisting> |
||
944 | |||
945 | <para>"Human" formatted times are intended to be human readable, and may |
||
946 | use non-ASCII characters. Otherwise the format is intended to be machine |
||
947 | readable, e.g., using <function>ep_time_parse</function>.</para> |
||
948 | </section> |
||
949 | |||
950 | <section> |
||
951 | <title>DATA STRUCTURES</title> |
||
952 | |||
953 | <section> |
||
954 | <title>Property Lists</title> |
||
955 | |||
956 | <para><remark>Not implemented at this time.</remark> A series of |
||
957 | key=value pairs. Used for many things, including configuration files. |
||
958 | For example, looking in the "configuration" property list for |
||
959 | "<varname>mailer.local.timeout.connect</varname>" would return the |
||
960 | connect timeout for the local mailer. <remark>[[How does this deal with |
||
961 | dc11518f | Eric Allman | nested defaults — e.g., looking for timeout.connect if the full |
962 | path cannot be found?]]</remark></para> |
||
963 | d63b8179 | Eric Allman | |
964 | <programlisting> EP_PLIST * |
||
965 | ep_plist_new( |
||
966 | const char *name) // for printing |
||
967 | |||
968 | EP_STAT |
||
969 | ep_plist_load( |
||
970 | EP_PLIST *plp, // the list to read into |
||
971 | FILE *sp, // the stream to load from |
||
972 | const char *prefix) // prefix added to all properties |
||
973 | |||
974 | EP_STAT |
||
975 | ep_plist_set( |
||
976 | EP_PLIST *plp, // the plist in which to set |
||
977 | const char *keyname, // the name of the key to set |
||
978 | const char *value) // the value to set (will be copied) |
||
979 | |||
980 | const char * |
||
981 | ep_plist_get( |
||
982 | EP_PLIST *plp, // the plist to search |
||
983 | const char *keyname) // the name of the key to get |
||
984 | |||
985 | void |
||
986 | ep_plist_dump( |
||
987 | EP_PLIST *plp, // plist to print |
||
988 | FILE *sp) // stream to print to |
||
989 | |||
990 | void |
||
991 | ep_plist_free( |
||
992 | EP_PLIST *plp) // plist to free</programlisting> |
||
993 | |||
994 | <para>A property list can be loaded from an external stream using |
||
995 | <function>ep_plist_load</function>. The syntax of the file is a simple |
||
996 | text file with "key=value" pairs on separate lines, with blank lines and |
||
997 | those with # at the beginning of the line ignored. The values are |
||
998 | strictly strings. <remark>[[Does it make sense to type |
||
999 | them?]]</remark></para> |
||
1000 | |||
1001 | <para><remark>[[Note the overlap between plists and the |
||
1002 | <function>ep_adm</function> interface. Does this make |
||
1003 | sense?]]</remark></para> |
||
1004 | |||
1005 | <para>Property lists can be printed using |
||
1006 | <function>ep_plist_dump</function>. The output format will be readable |
||
1007 | by <function>ep_plist_load</function>. For the time being, |
||
1008 | <varname>flags</varname> should always be <constant>0</constant>.</para> |
||
1009 | |||
1010 | <warning> |
||
1011 | <para>The property list is not guaranteed to be dumped in the same |
||
1012 | order items are inserted.</para> |
||
1013 | </warning> |
||
1014 | </section> |
||
1015 | |||
1016 | <section> |
||
1017 | <title>Hashes</title> |
||
1018 | |||
1019 | <programlisting> #include <ep/ep_hash.h> |
||
1020 | |||
1021 | EP_HASH * |
||
1022 | ep_hash_new( |
||
1023 | const char *name, // for printing |
||
1024 | EP_HASH_HASH_FUNCP *hfunc, // alternate hash function |
||
1025 | int tabsize) // hash table function size |
||
1026 | |||
1027 | void |
||
1028 | ep_hash_free( |
||
1029 | EP_HASH *hp) // hash to free |
||
1030 | |||
1031 | void * |
||
1032 | ep_hash_search( |
||
1033 | const EP_HASH *hp, // hash to search |
||
1034 | size_t keylen, // length of key |
||
1035 | const void *key) // pointer to key |
||
1036 | |||
1037 | void * |
||
1038 | ep_hash_insert( // returns old value for key |
||
1039 | EP_HASH *hp, // hash to modify |
||
1040 | size_t keylen, // length of key |
||
1041 | const void *key, // pointer to key |
||
1042 | void *val) // value to insert |
||
1043 | |||
1044 | ep_hash_forall(EP_HASH *hp, // hash to walk |
||
1045 | void (func)( // function to call |
||
1046 | int keylen, // key length |
||
1047 | const void *key, // key value |
||
1048 | void *val, // value |
||
1049 | void *closure), // from caller |
||
1050 | void *closure) // passed to func |
||
1051 | |||
1052 | ep_hash_dump(EP_TREE *tree, // tree to dump |
||
1053 | FILE *sp) // stream to print on</programlisting> |
||
1054 | |||
1055 | <para><remark>[[Should <function>ep_hash_dump</function> take the same |
||
1056 | parameters as the usual object print routine? For that matter, should |
||
1057 | there be a separate <function>ep_hash_dump</function> routine, or should |
||
1058 | it just be a generic <function>ep_obj_dump</function>? Note that |
||
1059 | <function>ep_hash_dump</function> is not implemented at this time, but |
||
1060 | an internal (object-based) dump is.]]</remark></para> |
||
1061 | </section> |
||
1062 | |||
1063 | <section> |
||
1064 | <title>Function Lists</title> |
||
1065 | |||
1066 | <programlisting> #include <ep/ep_funclist.h> |
||
1067 | |||
1068 | EP_FUNCLIST * |
||
1069 | ep_funclist_new( |
||
1070 | const char *name) // name for printing/debugging |
||
1071 | |||
1072 | void |
||
1073 | ep_funclist_free(EP_FUNCLIST *fp) // list to free |
||
1074 | |||
1075 | void |
||
1076 | ep_funclist_push(EP_FUNCLIST *fp, // list to push to |
||
1077 | 11ef2ab4 | Eric Allman | void (*func)( // the function to invoke |
1078 | void *closure, // from the ep_funclist_push call |
||
1079 | void *arg), // from the ep_funclist_invoke call |
||
1080 | void *closure) // the closure arg to pass to it |
||
1081 | d63b8179 | Eric Allman | |
1082 | void |
||
1083 | ep_funclist_pop(EP_FUNCLIST *fp) // list to pop from, value discarded |
||
1084 | |||
1085 | void |
||
1086 | ep_funclist_clear(EP_FUNCLIST *fp) // list to clear |
||
1087 | |||
1088 | void |
||
1089 | 11ef2ab4 | Eric Allman | ep_funclist_invoke(EP_FUNCLIST *fp, // invoke all functions in list |
1090 | void *arg) // second func arg</programlisting> |
||
1091 | d63b8179 | Eric Allman | </section> |
1092 | </section> |
||
1093 | |||
1094 | <section> |
||
1095 | 42d9d20e | Eric Allman | <title>CRYPTOGRAPHIC SUPPORT</title> |
1096 | |||
1097 | <para>The current implementation wraps the OpenSSL library, but it could |
||
1098 | be retargeted.</para> |
||
1099 | |||
1100 | ac90b0f6 | Eric Allman | <para>Before any cryptographic functions can be used, the library must be |
1101 | initialized:</para> |
||
1102 | |||
1103 | <programlisting>void ep_crypto_init(uint32_t flags)</programlisting> |
||
1104 | |||
1105 | <para>At the moment flags is unused (just pass zero). There are also |
||
1106 | several general purpose definitions, useful for declaring buffers without |
||
1107 | memory allocation:</para> |
||
1108 | |||
1109 | <informaltable border="1"> |
||
1110 | 11ef2ab4 | Eric Allman | <col width="4*"/> |
1111 | ac90b0f6 | Eric Allman | |
1112 | 11ef2ab4 | Eric Allman | <col width="6*"/> |
1113 | ac90b0f6 | Eric Allman | |
1114 | <tr> |
||
1115 | <td><constant>EP_CRYPTO_MAX_PUB_KEY</constant></td> |
||
1116 | |||
1117 | <td>Maximum length of a public key</td> |
||
1118 | </tr> |
||
1119 | |||
1120 | <tr> |
||
1121 | <td><constant>EP_CRYPTO_MAX_SEC_KEY</constant></td> |
||
1122 | |||
1123 | <td>Maximum length of a secret key</td> |
||
1124 | </tr> |
||
1125 | |||
1126 | <tr> |
||
1127 | <td><constant>EP_CRYPTO_MAX_DIGEST</constant></td> |
||
1128 | |||
1129 | <td>Maximum length of a message digest</td> |
||
1130 | </tr> |
||
1131 | |||
1132 | <tr> |
||
1133 | <td><constant>EP_CRYPTO_MAX_DER</constant></td> |
||
1134 | |||
1135 | <td>Maximum length of a DER-encoded key</td> |
||
1136 | </tr> |
||
1137 | </informaltable> |
||
1138 | |||
1139 | 42d9d20e | Eric Allman | <section> |
1140 | <title>Key Management</title> |
||
1141 | |||
1142 | <para>Internally all keys are represented as <type>EP_CRYPTO_KEY</type> |
||
1143 | variables, defined in <filename>ep_crypto.h</filename>. External |
||
1144 | representations for keys may be either PEM (Privacy Enhanced Mail, |
||
1145 | represented as text) or DER (Distinguished Encoding Rules, represented |
||
1146 | in binary). PEM self identifies the type of key, but DER does not, so in |
||
1147 | some cases the key type needs to be pre-arranged.</para> |
||
1148 | |||
1149 | <programlisting>// on-disk key formats |
||
1150 | # define EP_CRYPTO_KEYFORM_UNKNOWN 0 // error |
||
1151 | ac90b0f6 | Eric Allman | # define EP_CRYPTO_KEYFORM_PEM 1 // PEM (ASCII-encoded text) |
1152 | 42d9d20e | Eric Allman | # define EP_CRYPTO_KEYFORM_DER 2 // DER (binary ASN.1)</programlisting> |
1153 | |||
1154 | <para>Internally, algorithms (e.g., for keys and hash/digest functions) |
||
1155 | are represented by a scalar value. Keys also have to be identified as |
||
1156 | public or secret.</para> |
||
1157 | |||
1158 | ac90b0f6 | Eric Allman | <remark>[[Note: DH is not supported at this time.]]</remark> |
1159 | 42d9d20e | Eric Allman | |
1160 | <programlisting>// key types |
||
1161 | # define EP_CRYPTO_KEYTYPE_UNKNOWN 0 // error |
||
1162 | # define EP_CRYPTO_KEYTYPE_RSA 1 // RSA |
||
1163 | # define EP_CRYPTO_KEYTYPE_DSA 2 // DSA |
||
1164 | # define EP_CRYPTO_KEYTYPE_EC 3 // Elliptic curve |
||
1165 | # define EP_CRYPTO_KEYTYPE_DH 4 // Diffie-Hellman |
||
1166 | |||
1167 | // flag bits |
||
1168 | # define EP_CRYPTO_F_PUBLIC 0x0000 // public key (no flags set) |
||
1169 | # define EP_CRYPTO_F_SECRET 0x0001 // secret key</programlisting> |
||
1170 | |||
1171 | <para>Keys are represented as an <type>EP_CRYPTO_KEY</type>. New keys |
||
1172 | can be created by giving the type of the key desired, the length of the |
||
1173 | key in bits, and two other values that are interpreted by the key type. |
||
1174 | The first is primarily for RSA and gives the exponent, and the second is |
||
1175 | primarily for EC and gives the curve name.</para> |
||
1176 | |||
1177 | <programlisting>EP_CRYPTO_KEY *ep_crypto_key_create( |
||
1178 | int keytype, |
||
1179 | int keylen, |
||
1180 | int keyexp, |
||
1181 | const char *curve);</programlisting> |
||
1182 | |||
1183 | <para>Keys can be read from or written to named files, open files, or |
||
1184 | memory. All the read routines create and return a new key data |
||
1185 | structure. If the <varname>keyform</varname> is |
||
1186 | <constant>EP_CRYPTO_KEYFORM_PEM</constant> then the |
||
1187 | <varname>keytype</varname> need not be specified.</para> |
||
1188 | |||
1189 | <programlisting>EP_CRYPTO_KEY *ep_crypto_key_read_file( |
||
1190 | const char *filename, |
||
1191 | int keyform, |
||
1192 | uint32_t flags); |
||
1193 | EP_CRYPTO_KEY *ep_crypto_key_read_fp( |
||
1194 | FILE *fp, |
||
1195 | const char *filename, |
||
1196 | int keyform, |
||
1197 | uint32_t flags); |
||
1198 | EP_CRYPTO_KEY *ep_crypto_key_read_mem( |
||
1199 | const void *buf, |
||
1200 | size_t buflen, |
||
1201 | int keyform, |
||
1202 | uint32_t flags); |
||
1203 | EP_STAT ep_crypto_key_write_file( |
||
1204 | EP_CRYPTO_KEY *key, |
||
1205 | const char *filename, |
||
1206 | int keyform, |
||
1207 | int cipher, |
||
1208 | uint32_t flags); |
||
1209 | EP_STAT ep_crypto_key_write_fp( |
||
1210 | EP_CRYPTO_KEY *key, |
||
1211 | FILE *fp, |
||
1212 | int keyform, |
||
1213 | int cipher, |
||
1214 | uint32_t flags); |
||
1215 | EP_STAT ep_crypto_key_write_mem( |
||
1216 | EP_CRYPTO_KEY *key, |
||
1217 | void *buf, |
||
1218 | size_t bufsize, |
||
1219 | int keyform, |
||
1220 | int cipher, |
||
1221 | uint32_t flags);</programlisting> |
||
1222 | |||
1223 | <para>When finished with a key it must be freed.</para> |
||
1224 | |||
1225 | <programlisting>void ep_crypto_key_free( |
||
1226 | EP_CRYPTO_KEY *key);</programlisting> |
||
1227 | |||
1228 | <para>There are also some utility routines. A public and a secret key |
||
1229 | can be compared to see if they match each other (same algorithm, |
||
1230 | keysize, etc.) using <function>ep_crypto_key_compat</function>. Various |
||
1231 | conversions are also included: |
||
1232 | <function>ep_crypto_keyform_byname</function> converts a text string |
||
1233 | (e.g., "pem") to an internal code, |
||
1234 | <function>ep_crypto_keytype_fromkey</function> returns the type of a |
||
1235 | key, and <function>ep_crypto_keytype_byname</function> converts a text |
||
1236 | string to a type.</para> |
||
1237 | |||
1238 | <programlisting>EP_STAT ep_crypto_key_compat( |
||
1239 | const EP_CRYPTO_KEY *pubkey, |
||
1240 | const EP_CRYPTO_KEY *seckey); |
||
1241 | int ep_crypto_keyform_byname( |
||
1242 | const char *fmt); |
||
1243 | int ep_crypto_keytype_fromkey( |
||
1244 | EP_CRYPTO_KEY *key); |
||
1245 | int ep_crypto_keytype_byname( |
||
1246 | const char *alg_name);</programlisting> |
||
1247 | </section> |
||
1248 | |||
1249 | <section> |
||
1250 | <title>Message Digests (Hashes)</title> |
||
1251 | |||
1252 | <para>Several message digest (cryptographic hash) algorithms are |
||
1253 | supported. Text can be converted to one of these values, and the |
||
1254 | algorithm type can be extracted from the internal form.</para> |
||
1255 | |||
1256 | <programlisting>// digest algorithms (no more than 4 bits) |
||
1257 | # define EP_CRYPTO_MD_NULL 0 |
||
1258 | # define EP_CRYPTO_MD_SHA1 1 |
||
1259 | # define EP_CRYPTO_MD_SHA224 2 |
||
1260 | # define EP_CRYPTO_MD_SHA256 3 |
||
1261 | # define EP_CRYPTO_MD_SHA384 4 |
||
1262 | # define EP_CRYPTO_MD_SHA512 5 |
||
1263 | |||
1264 | int ep_crypto_md_alg_byname( |
||
1265 | const char *algname); |
||
1266 | int ep_crypto_md_type( |
||
1267 | EP_CRYPTO_MD *md);</programlisting> |
||
1268 | |||
1269 | <para>Digests (type <type>EP_CRYPTO_MD</type>) can be created, freed, |
||
1270 | and cloned. Cloning lets an application compute the a fixed part of a |
||
1271 | digest (perhaps an unchanging header) and then produce separate digests |
||
1272 | for individual records.</para> |
||
1273 | |||
1274 | <programlisting>EP_CRYPTO_MD *ep_crypto_md_new( |
||
1275 | int md_alg_id); |
||
1276 | EP_CRYPTO_MD *ep_crypto_md_clone( |
||
1277 | EP_CRYPTO_MD *base_md); |
||
1278 | void ep_crypto_md_free( |
||
1279 | EP_CRYPTO_MD *md);</programlisting> |
||
1280 | |||
1281 | <para>The typical lifetime of a digest is to be created (as above), |
||
1282 | updated with additional data, possibly multiple times, and then |
||
1283 | finalized to give the output hash.</para> |
||
1284 | |||
1285 | <programlisting>EP_STAT ep_crypto_md_update( |
||
1286 | EP_CRYPTO_MD *md, |
||
1287 | void *data, |
||
1288 | size_t dsize); |
||
1289 | EP_STAT ep_crypto_md_final( |
||
1290 | EP_CRYPTO_MD *md, |
||
1291 | void *dbuf, |
||
1292 | size_t *dbufsize);</programlisting> |
||
1293 | </section> |
||
1294 | |||
1295 | <section> |
||
1296 | <title>Signing and Verification</title> |
||
1297 | |||
1298 | <para>Signing and verification are quite similar. A new internal |
||
1299 | structure is created, using the same type as a message digest, data is |
||
1300 | added to the existing hash, possibly multiple times, the signature is |
||
1301 | created or verified, and finally the structure is freed.</para> |
||
1302 | |||
1303 | <programlisting># define EP_CRYPTO_MAX_SIG (1024 * 8) |
||
1304 | |||
1305 | EP_CRYPTO_MD *ep_crypto_sign_new( |
||
1306 | EP_CRYPTO_KEY *skey, |
||
1307 | int md_alg_id); |
||
1308 | void ep_crypto_sign_free( |
||
1309 | EP_CRYPTO_MD *md); |
||
1310 | EP_STAT ep_crypto_sign_update( |
||
1311 | EP_CRYPTO_MD *md, |
||
1312 | void *dbuf, |
||
1313 | size_t dbufsize); |
||
1314 | EP_STAT ep_crypto_sign_final( |
||
1315 | EP_CRYPTO_MD *md, |
||
1316 | void *sbuf, |
||
1317 | size_t *sbufsize); |
||
1318 | |||
1319 | EP_CRYPTO_MD *ep_crypto_vrfy_new( |
||
1320 | EP_CRYPTO_KEY *pkey, |
||
1321 | int md_alg_id); |
||
1322 | void ep_crypto_vrfy_free( |
||
1323 | EP_CRYPTO_MD *md); |
||
1324 | EP_STAT ep_crypto_vrfy_update( |
||
1325 | EP_CRYPTO_MD *md, |
||
1326 | void *dbuf, |
||
1327 | size_t dbufsize); |
||
1328 | EP_STAT ep_crypto_vrfy_final( |
||
1329 | EP_CRYPTO_MD *md, |
||
1330 | void *obuf, |
||
1331 | size_t obufsize);</programlisting> |
||
1332 | </section> |
||
1333 | |||
1334 | <section> |
||
1335 | <title>Encryption and Decryption (Asymmetric)</title> |
||
1336 | |||
1337 | <para>To be supplied.</para> |
||
1338 | </section> |
||
1339 | |||
1340 | <section> |
||
1341 | <title>Encryption and Decryption (Symmetric Ciphers)</title> |
||
1342 | |||
1343 | ac90b0f6 | Eric Allman | <para>Symmetric Ciphers are driven by a Chaining Mode (how subsequent |
1344 | blocks have the key modified to prevent replay and brute force attacks) |
||
1345 | and the actual cipher itself. The chaining modes are:</para> |
||
1346 | |||
1347 | <informaltable border="1"> |
||
1348 | 11ef2ab4 | Eric Allman | <col width="4*"/> |
1349 | ac90b0f6 | Eric Allman | |
1350 | 11ef2ab4 | Eric Allman | <col width="6*"/> |
1351 | ac90b0f6 | Eric Allman | |
1352 | <tr> |
||
1353 | <td width=""><constant>EP_CRYPTO_MODE_CBC</constant></td> |
||
1354 | |||
1355 | <td>Cipher Block Chaining</td> |
||
1356 | </tr> |
||
1357 | |||
1358 | <tr> |
||
1359 | <td width=""><constant>EP_CRYPTO_MODE_CFB</constant></td> |
||
1360 | |||
1361 | <td>Cipher Feedback mode</td> |
||
1362 | </tr> |
||
1363 | |||
1364 | <tr> |
||
1365 | <td width=""><constant>EP_CRYPTO_MODE_OFB</constant></td> |
||
1366 | |||
1367 | <td>Output Feedback mode</td> |
||
1368 | </tr> |
||
1369 | </informaltable> |
||
1370 | |||
1371 | <para>The various cipher algorithms (which is equivalent to the key |
||
1372 | type) are:</para> |
||
1373 | |||
1374 | <informaltable border="1"> |
||
1375 | 11ef2ab4 | Eric Allman | <col width="4*"/> |
1376 | ac90b0f6 | Eric Allman | |
1377 | 11ef2ab4 | Eric Allman | <col width="6*"/> |
1378 | ac90b0f6 | Eric Allman | |
1379 | <tr> |
||
1380 | <td><constant>EP_CRYPTO_SYMKEY_NONE</constant></td> |
||
1381 | |||
1382 | <td>Error/unencrypted</td> |
||
1383 | </tr> |
||
1384 | |||
1385 | <tr> |
||
1386 | <td><constant>EP_CRYPTO_SYMKEY_AES128</constant></td> |
||
1387 | |||
1388 | <td>Advanced Encr Std, 128-bit key</td> |
||
1389 | </tr> |
||
1390 | |||
1391 | <tr> |
||
1392 | <td><constant>EP_CRYPTO_SYMKEY_AES192</constant></td> |
||
1393 | |||
1394 | <td>Advanced Encr Std, 192-bit key</td> |
||
1395 | </tr> |
||
1396 | |||
1397 | <tr> |
||
1398 | <td><constant>EP_CRYPTO_SYMKEY_AES256</constant></td> |
||
1399 | |||
1400 | <td>Advanced Encr Std, 256-bit key</td> |
||
1401 | </tr> |
||
1402 | |||
1403 | <tr> |
||
1404 | <td><constant>EP_CRYPTO_SYMKEY_CAMELLIA128</constant></td> |
||
1405 | |||
1406 | <td>Camellia, 128-bit key</td> |
||
1407 | </tr> |
||
1408 | |||
1409 | <tr> |
||
1410 | <td><constant>EP_CRYPTO_SYMKEY_CAMELLIA192</constant></td> |
||
1411 | |||
1412 | <td>Camellia, 192-bit key</td> |
||
1413 | </tr> |
||
1414 | |||
1415 | <tr> |
||
1416 | <td><constant>EP_CRYPTO_SYMKEY_CAMELLIA256</constant></td> |
||
1417 | |||
1418 | <td>Camellia, 256-bit key</td> |
||
1419 | </tr> |
||
1420 | |||
1421 | <tr> |
||
1422 | <td><constant>EP_CRYPTO_SYMKEY_DES</constant></td> |
||
1423 | |||
1424 | <td>Data Encryption Standard, single, 56-bit key</td> |
||
1425 | </tr> |
||
1426 | |||
1427 | <tr> |
||
1428 | <td><constant>EP_CRYPTO_SYMKEY_3DES</constant></td> |
||
1429 | |||
1430 | <td>Data Encryption Standard, triple, 128-bit key (112-bit |
||
1431 | effective)</td> |
||
1432 | </tr> |
||
1433 | |||
1434 | <tr> |
||
1435 | <td><constant>EP_CRYPTO_SYMKEY_IDEA</constant></td> |
||
1436 | |||
1437 | <td>International Data Encryption Alg, 128-bit key</td> |
||
1438 | </tr> |
||
1439 | </informaltable> |
||
1440 | |||
1441 | <para>One value from each table are "or"ed together to specify a full |
||
1442 | symmetric cipher. The rest of the interface is as follows:</para> |
||
1443 | |||
1444 | <programlisting>/* |
||
1445 | ** The cipher is set to encrypt or decrypt when the context |
||
1446 | ** is created. |
||
1447 | ** |
||
1448 | ** ep_crypto_cipher_crypt is just shorthand for a single |
||
1449 | 7023c91a | Eric Allman | ** call to ep_crypto_cipher_update followed by a single |
1450 | ** call to ep_crypto_cipher_final. Final pads out any |
||
1451 | ac90b0f6 | Eric Allman | ** remaining block and returns that data. |
1452 | */ |
||
1453 | |||
1454 | EP_CRYPTO_CIPHER_CTX *ep_crypto_cipher_new( |
||
1455 | uint32_t ciphertype, // mode + keytype & len |
||
1456 | uint8_t *key, // the key |
||
1457 | uint8_t *iv, // initialization vector |
||
1458 | bool enc); // true => encrypt |
||
1459 | void ep_crypto_cipher_free( |
||
1460 | EP_CRYPTO_CIPHER_CTX *cipher); |
||
1461 | |||
1462 | EP_STAT ep_crypto_cipher_crypt( |
||
1463 | EP_CRYPTO_CIPHER_CTX *cipher, |
||
1464 | void *in, // input data |
||
1465 | size_t inlen, // input length |
||
1466 | void *out, // output buffer |
||
1467 | size_t outlen); // output buf size |
||
1468 | 7023c91a | Eric Allman | EP_STAT ep_crypto_cipher_update( |
1469 | ac90b0f6 | Eric Allman | EP_CRYPTO_CIPHER_CTX *cipher, |
1470 | void *in, // input data |
||
1471 | size_t inlen, // input length |
||
1472 | void *out, // output buffer |
||
1473 | size_t outlen); // output buf size |
||
1474 | 7023c91a | Eric Allman | EP_STAT ep_crypto_cipher_final( |
1475 | ac90b0f6 | Eric Allman | EP_CRYPTO_CIPHER_CTX *cipher, |
1476 | void *out, // output buffer |
||
1477 | size_t outlen); // output buf size</programlisting> |
||
1478 | 42d9d20e | Eric Allman | </section> |
1479 | |||
1480 | <section> |
||
1481 | <title>Cryptography-specific Error Codes</title> |
||
1482 | |||
1483 | <para>There are several status codes that may be returned from the |
||
1484 | cryptography routines. These are all in module |
||
1485 | EP_STAT_MOD_CRYPTO.</para> |
||
1486 | |||
1487 | <informaltable border="1"> |
||
1488 | 11ef2ab4 | Eric Allman | <col width="4*"/> |
1489 | ac90b0f6 | Eric Allman | |
1490 | 11ef2ab4 | Eric Allman | <col width="6*"/> |
1491 | ac90b0f6 | Eric Allman | |
1492 | 42d9d20e | Eric Allman | <tr> |
1493 | ac90b0f6 | Eric Allman | <td><errorcode>EP_STAT_CRYPTO_DIGEST</errorcode></td> |
1494 | 42d9d20e | Eric Allman | |
1495 | <td>Failed to update or finalize a digest (hash)</td> |
||
1496 | </tr> |
||
1497 | |||
1498 | <tr> |
||
1499 | ac90b0f6 | Eric Allman | <td><errorcode>EP_STAT_CRYPTO_SIGN</errorcode></td> |
1500 | 42d9d20e | Eric Allman | |
1501 | <td>Failed to update or finalize a digest for signing</td> |
||
1502 | </tr> |
||
1503 | |||
1504 | <tr> |
||
1505 | ac90b0f6 | Eric Allman | <td><errorcode>EP_STAT_CRYPTO_VRFY</errorcode></td> |
1506 | 42d9d20e | Eric Allman | |
1507 | <td>Failed to update or finalize a digest for verification</td> |
||
1508 | </tr> |
||
1509 | |||
1510 | <tr> |
||
1511 | ac90b0f6 | Eric Allman | <td><errorcode>EP_STAT_CRYPTO_BADSIG</errorcode></td> |
1512 | 42d9d20e | Eric Allman | |
1513 | <td>Signature did not match</td> |
||
1514 | </tr> |
||
1515 | |||
1516 | <tr> |
||
1517 | ac90b0f6 | Eric Allman | <td><errorcode>EP_STAT_CRYPTO_KEYTYPE</errorcode></td> |
1518 | 42d9d20e | Eric Allman | |
1519 | <td>Unknown key type</td> |
||
1520 | </tr> |
||
1521 | |||
1522 | <tr> |
||
1523 | ac90b0f6 | Eric Allman | <td><errorcode>EP_STAT_CRYPTO_KEYFORM</errorcode></td> |
1524 | 42d9d20e | Eric Allman | |
1525 | <td>Unknown key format</td> |
||
1526 | </tr> |
||
1527 | |||
1528 | <tr> |
||
1529 | ac90b0f6 | Eric Allman | <td><errorcode>EP_STAT_CRYPTO_CONVERT</errorcode></td> |
1530 | 42d9d20e | Eric Allman | |
1531 | <td>Couldn't read or write a key</td> |
||
1532 | </tr> |
||
1533 | |||
1534 | <tr> |
||
1535 | ac90b0f6 | Eric Allman | <td><errorcode>EP_STAT_CRYPTO_KEYCREATE</errorcode></td> |
1536 | 42d9d20e | Eric Allman | |
1537 | <td>Couldn't create a new key</td> |
||
1538 | </tr> |
||
1539 | |||
1540 | <tr> |
||
1541 | ac90b0f6 | Eric Allman | <td><errorcode>EP_STAT_CRYPTO_KEYCOMPAT</errorcode></td> |
1542 | 42d9d20e | Eric Allman | |
1543 | 25e66e4f | Eric Allman | <td>Public and secret keys are incompatible</td> |
1544 | 42d9d20e | Eric Allman | </tr> |
1545 | ac90b0f6 | Eric Allman | |
1546 | <tr> |
||
1547 | <td><errorcode>EP_STAT_CRYPTO_CIPHER</errorcode></td> |
||
1548 | |||
1549 | <td>Symmetric cipher failure</td> |
||
1550 | </tr> |
||
1551 | 42d9d20e | Eric Allman | </informaltable> |
1552 | </section> |
||
1553 | </section> |
||
1554 | |||
1555 | <section> |
||
1556 | d63b8179 | Eric Allman | <title>APPLICATION SUPPORT</title> |
1557 | |||
1558 | <para>The following routines are intended to provide useful support to |
||
1559 | applications, but are not otherwise fundamental</para> |
||
1560 | |||
1561 | <section> |
||
1562 | <title>Printing Flag Words, Etc.</title> |
||
1563 | |||
1564 | <programlisting> #include <ep/ep_prflags.h> |
||
1565 | |||
1566 | void |
||
1567 | ep_prflags( |
||
1568 | u_int32 flagword, // the flags word to print |
||
1569 | EP_PRFLAGS_DESC *flaglist, // descriptor of flags |
||
1570 | FILE *out) // output stream |
||
1571 | |||
1572 | typedef struct ep_prflags_desc |
||
1573 | { |
||
1574 | u_int32 bits; // bits to compare against |
||
1575 | u_int32 mask; // mask against flagword |
||
1576 | char *name; // printable name |
||
1577 | } EP_PRFLAGS_DESC;</programlisting> |
||
1578 | |||
1579 | <para>For example, given a descriptor of:</para> |
||
1580 | |||
1581 | <programlisting> 0x0000, 0x0003, "READ", |
||
1582 | 0x0001, 0x0003, "WRITE", |
||
1583 | 0x0002, 0x0003, "READWRITE", |
||
1584 | 0x0003, 0x0003, "[INVALID MODE]", |
||
1585 | 0x0004, 0x0004, "NONBLOCK", |
||
1586 | 0x0008, 0x0008, "APPEND", |
||
1587 | 0, 0, NULL</programlisting> |
||
1588 | |||
1589 | <para>then a flagword of 0x0009 would print:</para> |
||
1590 | |||
1591 | <para><computeroutput> 0009<WRITE,APPEND></computeroutput></para> |
||
1592 | </section> |
||
1593 | |||
1594 | <section> |
||
1595 | <title>Printing Helpers</title> |
||
1596 | |||
1597 | <para>A few routines to make it easier to create string versions of |
||
1598 | other type variables, e.g., for |
||
1599 | <function>ep_stat_post</function>.</para> |
||
1600 | |||
1601 | <programlisting> #include <ep/ep_pcvt.h> |
||
1602 | |||
1603 | char *ep_pcvt_str(size_t osize, // output buffer size |
||
1604 | char *obuf, // output buffer |
||
1605 | const char *val) // value to convert |
||
1606 | |||
1607 | char *ep_pcvt_int(size_t osize, // output buffer size |
||
1608 | char *obuf, // output buffer |
||
1609 | int base, // base of value |
||
1610 | int val) // value to convert</programlisting> |
||
1611 | |||
1612 | <para>All of these return their input buffer.</para> |
||
1613 | |||
1614 | <para>The routine <function>ep_pcvt_str</function> truncates the value |
||
1615 | to the indicated size. If the value won't fit, it renders |
||
1616 | "<replaceable>beginning</replaceable>...<replaceable>end</replaceable>" |
||
1617 | where <replaceable>end</replaceable> is the last three bytes of the |
||
1618 | value.</para> |
||
1619 | </section> |
||
1620 | |||
1621 | <section> |
||
1622 | <title>Application Messages</title> |
||
1623 | |||
1624 | <para>Associated with status printing.</para> |
||
1625 | |||
1626 | <programlisting> #include <ep/ep_app.h> |
||
1627 | |||
1628 | 174526d7 | Eric Allman | void ep_app_info(const char *fmt, // printf-style format |
1629 | ...) |
||
1630 | |||
1631 | d63b8179 | Eric Allman | void ep_app_warn(const char *fmt, // printf-style format |
1632 | ...) |
||
1633 | |||
1634 | void ep_app_error(const char *fmt, // printf-style format |
||
1635 | ...) |
||
1636 | |||
1637 | b73e1ad7 | Eric Allman | void ep_app_fatal(const char *fmt, // printf-style format |
1638 | ...) |
||
1639 | |||
1640 | d63b8179 | Eric Allman | void ep_app_abort(const char *fmt, // printf-style format |
1641 | b73e1ad7 | Eric Allman | ...) |
1642 | |||
1643 | void ep_app_setflags(uint32_t flags) // set operational tweaks</programlisting> |
||
1644 | d63b8179 | Eric Allman | |
1645 | 174526d7 | Eric Allman | <para>The first three just print messages; the second two print the |
1646 | b73e1ad7 | Eric Allman | message and does not return. <function>ep_app_abort</function> generates |
1647 | 174526d7 | Eric Allman | a core dump on termination. All five use printf formats. |
1648 | b73e1ad7 | Eric Allman | <function>ep_app_setflags</function> sets flags telling when to also do |
1649 | logging; the flags are <constant>EP_APP_FLAG_LOGABORTS</constant>, |
||
1650 | <constant>EP_APP_FLAG_LOGFATALS</constant>, |
||
1651 | 174526d7 | Eric Allman | <constant>EP_APP_FLAG_LOGERRORS</constant>, |
1652 | <constant>EP_APP_FLAG_LOGWARNINGS</constant>, and |
||
1653 | <constant>EP_APP_FLAG_LOGINFOS</constant>. The log severity is different |
||
1654 | for these various functions.</para> |
||
1655 | d63b8179 | Eric Allman | |
1656 | <programlisting> const char * |
||
1657 | ep_app_getprogname(void) // get current program name</programlisting> |
||
1658 | |||
1659 | <para>This is a portability wrapper that returns the name of the current |
||
1660 | program (essentially, the last component of argv[0]).</para> |
||
1661 | </section> |
||
1662 | |||
1663 | <section> |
||
1664 | <title>Printing Memory</title> |
||
1665 | |||
1666 | <para>To print out a block of binary memory, use ep_hexdump.</para> |
||
1667 | |||
1668 | <programlisting> #include <ep/ep_hexdump.h> |
||
1669 | |||
1670 | void |
||
1671 | ep_hexdump(void *bufp, // block of memory to print |
||
1672 | size_t buflen, // size of that block |
||
1673 | FILE *fp, // output file |
||
1674 | int format, // see description |
||
1675 | size_t offset); // offset</programlisting> |
||
1676 | |||
1677 | <para>This prints a block of memory as a hexadecimal dump, optionally |
||
1678 | with an ASCII rendition. The offset printed starts at the |
||
1679 | <varname>offset</varname> parameter (zero to make the printed offsets be |
||
1680 | relative to <varname>bufp</varname>). The <varname>format</varname> may |
||
1681 | be <constant>EP_HEXDUMP_HEX</constant> to print only the hexadecimal or |
||
1682 | <constant>EP_HEXDUMP_ASCII</constant> to also show the bytes interpreted |
||
1683 | as ASCII (unprintable characters are substituted).</para> |
||
1684 | </section> |
||
1685 | </section> |
||
1686 | |||
1687 | <section> |
||
1688 | <title>DEBUGGING, TRACING, ASSERTIONS</title> |
||
1689 | |||
1690 | <para>Named flags, each settable from 0 to 127.</para> |
||
1691 | |||
1692 | <para>When setting flags, wildcards can be used (only <quote>*</quote> |
||
1693 | supported for now).</para> |
||
1694 | |||
1695 | <programlisting> #include <ep/ep_dbg.h> |
||
1696 | |||
1697 | void |
||
1698 | ep_dbg_init(void) // initialize debugging |
||
1699 | |||
1700 | void |
||
1701 | ep_dbg_set(const char *fspec) // set debug flags (command line) |
||
1702 | |||
1703 | void |
||
1704 | ep_dbg_setto(const char *fpat, // flag pattern |
||
1705 | int lev) // level |
||
1706 | |||
1707 | EP_DBG <replaceable>flag</replaceable> EP_DBG_INIT( // opaque structure for flag |
||
1708 | name, // external name of flag |
||
1709 | desc); // description (internal use only) |
||
1710 | |||
1711 | int |
||
1712 | ep_dbg_level(EP_DBG *flag) // return level of given flag |
||
1713 | |||
1714 | bool |
||
1715 | ep_dbg_test(EP_DBG *flag, |
||
1716 | int value) // true if flag set to >= value |
||
1717 | |||
1718 | void |
||
1719 | ep_dbg_printf(fmt, ...) // print to EpStStddbg |
||
1720 | |||
1721 | void |
||
1722 | ep_dbg_cprintf(EP_DBG *flag, // if flag level >= value, |
||
1723 | int value, |
||
1724 | fmt, ...) // print fmt etc as though printf. |
||
1725 | |||
1726 | void |
||
1727 | ep_dbg_setfile(FILE *fp) // set debug output to indicated file |
||
1728 | |||
1729 | void |
||
1730 | ep_dbg_getfile(void) // return current debug output file</programlisting> |
||
1731 | |||
1732 | c71b5a7a | Eric Allman | <para>Assertions are intended to catch "cannot happen" cases. They are not |
1733 | necessarily fatal, depending on configuration controlled by administrative |
||
1734 | parameters: <parameter>libep.assert.maxfailures</parameter> specifies the |
||
1735 | number of assertion failures that will be tolerated before the process |
||
1736 | aborts; however, every <parameter>libep.assert.resetinterval</parameter> |
||
1737 | cca7ea5f | Eric Allman | milliseconds the failure count is reset. For example, if |
1738 | c71b5a7a | Eric Allman | <parameter>libep.assert.maxfailures</parameter> is one, all assertion |
1739 | cca7ea5f | Eric Allman | failures are fatal; if zero, none are. It defaults to 100. |
1740 | <parameter>libep.assert.resetinterval</parameter> defaults to 2000 (two |
||
1741 | seconds).</para> |
||
1742 | d63b8179 | Eric Allman | |
1743 | <programlisting> #include <ep/ep_assert.h> |
||
1744 | |||
1745 | c71b5a7a | Eric Allman | EP_ASSERT(condition) // fail if condition is false; returns the condition itself |
1746 | 8d7fc458 | Eric Allman | |
1747 | EP_ASSERT_ELSE(condition, recovery) // print and run recovery code if condition not satisfied |
||
1748 | |||
1749 | EP_ASSERT_PRINT( // print assertion failure message |
||
1750 | const char *msg, // message to print |
||
1751 | ...) // arguments to message |
||
1752 | c71b5a7a | Eric Allman | ep_assert_print( // print assertion failure with extra info and message |
1753 | const char *file, // file name |
||
1754 | int line, // line number |
||
1755 | const char *msg, // message to print |
||
1756 | ...) // arguments to message |
||
1757 | d63b8179 | Eric Allman | |
1758 | a346c64c | Eric Allman | EP_ASSERT_FAILURE( // abort process with message |
1759 | const char *msg, // message to print |
||
1760 | ...) // arguments to message |
||
1761 | ep_assert_failure( // abort process with extra info and message |
||
1762 | const char *file, // file name |
||
1763 | int line, // line number |
||
1764 | const char *msg, // message to print |
||
1765 | ...) // arguments to message |
||
1766 | |||
1767 | 8d7fc458 | Eric Allman | void (*EpAssertInfo)(void) // if set, call to print additional information |
1768 | ddbd01b3 | Eric Allman | void (*EpAssertAbort)(void) // function to call before aborting |
1769 | bool EpAssertAllAbort // if set, all assertions are immediately fatal</programlisting> |
||
1770 | a346c64c | Eric Allman | |
1771 | c71b5a7a | Eric Allman | <para>Programs may try to recover from assertion failures by testing the |
1772 | result of <function>EP_ASSERT</function>, which will be true if the |
||
1773 | condition holds. For example, either of these return an error code if a |
||
1774 | pointer is <constant>NULL</constant>:</para> |
||
1775 | |||
1776 | <programlisting> if (!EP_ASSERT(p != NULL)) |
||
1777 | return EP_STAT_ASSERT_ABORT; |
||
1778 | |||
1779 | EP_ASSERT_ELSE(p != NULL, return EP_STAT_ASSERT_ABORT);</programlisting> |
||
1780 | |||
1781 | <para>Processes can force an abort as though they got an assertion failure |
||
1782 | by calling <function>ep_assert_failure</function>. Note that this does not |
||
1783 | attempt any recovery; <function>ep_assert_print</function> does the same |
||
1784 | thing but does not abort. The macros |
||
1785 | <function>EP_ASSERT_FAILURE</function> and |
||
1786 | <function>EP_ASSERT_PRINT</function> do the same thing, but provide the |
||
1787 | <parameter>file</parameter> name and <parameter>line</parameter> number in |
||
1788 | the same way as the assertion tests. If the |
||
1789 | 8d7fc458 | Eric Allman | <varname>EpAssertInfo</varname> variable is set, that function will be |
1790 | called after printing the message but before aborting. It can be used to |
||
1791 | dump process state for debugging. If the <varname>EpAssertAbort</varname> |
||
1792 | variable is set, that function will be called after the message is printed |
||
1793 | and immediately before the process aborts. This might do last minute |
||
1794 | recovery or alternative termination (e.g., terminate just the thread |
||
1795 | rather than the entire process).</para> |
||
1796 | d63b8179 | Eric Allman | </section> |
1797 | |||
1798 | <section> |
||
1799 | <title>THREAD SUPPORT</title> |
||
1800 | |||
1801 | <para>These are mostly wrappers around the pthreads library, but they will |
||
1802 | print errors if the <code>ep.thr</code> debug flag is set to at least |
||
1803 | 4.</para> |
||
1804 | |||
1805 | <programlisting>#include <ep/ep_thr.h> |
||
1806 | |||
1807 | int |
||
1808 | ep_thr_mutex_init(EP_THR_MUTEX *mtx, int type); |
||
1809 | |||
1810 | int |
||
1811 | ep_thr_mutex_destroy(EP_THR_MUTEX *mtx); |
||
1812 | |||
1813 | int |
||
1814 | ep_thr_mutex_lock(EP_THR_MUTEX *mtx); |
||
1815 | |||
1816 | int |
||
1817 | ep_thr_mutex_trylock(EP_THR_MUTEX *mtx); |
||
1818 | |||
1819 | int |
||
1820 | ep_thr_mutex_unlock(EP_THR_MUTEX *mtx); |
||
1821 | |||
1822 | int |
||
1823 | ep_thr_mutex_check(EP_THR_MUTEX *mtx); |
||
1824 | |||
1825 | int |
||
1826 | ep_thr_cond_init(EP_THR_COND *cv); |
||
1827 | |||
1828 | int |
||
1829 | ep_thr_cond_destroy(EP_THR_COND *cv); |
||
1830 | |||
1831 | int |
||
1832 | ep_thr_cond_signal(EP_THR_COND *cv); |
||
1833 | |||
1834 | int |
||
1835 | ep_thr_cond_wait(EP_THR_COND *cv, EP_THR_MUTEX *mtx, EP_TIME_SPEC *timeout); |
||
1836 | |||
1837 | int |
||
1838 | ep_thr_cond_broadcast(EP_THR_COND *cv); |
||
1839 | |||
1840 | int |
||
1841 | ep_thr_rwlock_init(EP_THR_RWLOCK *rwl); |
||
1842 | |||
1843 | int |
||
1844 | ep_thr_rwlock_destroy(EP_THR_RWLOCK *rwl); |
||
1845 | |||
1846 | int |
||
1847 | ep_thr_rwlock_rdlock(EP_THR_RWLOCK *rwl); |
||
1848 | |||
1849 | int |
||
1850 | ep_thr_rwlock_tryrdlock(EP_THR_RWLOCK *rwl); |
||
1851 | |||
1852 | int |
||
1853 | ep_thr_rwlock_wrlock(EP_THR_RWLOCK *rwl); |
||
1854 | |||
1855 | int |
||
1856 | ep_thr_rwlock_tryrwlock(EP_THR_RWLOCK *rwl); |
||
1857 | |||
1858 | int |
||
1859 | ep_thr_rwlock_unlock(EP_THR_RWLOCK *rwl);</programlisting> |
||
1860 | |||
1861 | <para>The ep_thr_*_check routines check the structures for consistency and |
||
1862 | print an error; this is only for debugging. <remark>This should be |
||
1863 | expanded to include spawning threads etc.; for the time being just use the |
||
1864 | pthreads primitives.</remark></para> |
||
1865 | |||
1866 | <para>There is also a basic thread pool implementation:</para> |
||
1867 | |||
1868 | <programlisting>#include <ep/ep_thr.h> |
||
1869 | |||
1870 | void |
||
1871 | ep_thr_pool_init( |
||
1872 | int min_threads, |
||
1873 | int max_threads, |
||
1874 | uint32_t flags); |
||
1875 | |||
1876 | void |
||
1877 | ep_thr_pool_run( |
||
1878 | void (*func)(void *), |
||
1879 | void *arg);</programlisting> |
||
1880 | |||
1881 | <para>Thread pools are initially started with |
||
1882 | <varname>min_threads</varname> workers (which may be zero; defaults to the |
||
1883 | <parameter>libep.thr.pool.min_workers</parameter> administrative |
||
1884 | parameter, or 1 if that is not set). Threads will be spawned as necessary |
||
1885 | up to <varname>max_threads</varname> total workers (defaults to |
||
1886 | <parameter>libep.thr.pool.max_workers</parameter>; if that is not set, |
||
1887 | defaults to twice the number of cores available).</para> |
||
1888 | |||
1889 | <para>Threads are run in essentially the same way as spawning a pthreads |
||
1890 | thread; this is really just a convenience wrapper around that so resources |
||
1891 | can be better controlled.</para> |
||
1892 | </section> |
||
1893 | |||
1894 | <section> |
||
1895 | <title>LOGGING</title> |
||
1896 | |||
1897 | <para>Messages may be logged together with a status code:</para> |
||
1898 | |||
1899 | <programlisting>#include <ep/ep_log.h> |
||
1900 | |||
1901 | void |
||
1902 | ep_log_init( |
||
1903 | const char *tag, |
||
1904 | int logfac, |
||
1905 | 58c51fe6 | Eric Allman | FILE *logfile); |
1906 | |||
1907 | void |
||
1908 | ep_log_addmethod( |
||
1909 | void (*func)(void *ctx, EP_STAT estat, const char *fmt, va_list ap), |
||
1910 | void *ctx, |
||
1911 | int minsev); |
||
1912 | d63b8179 | Eric Allman | |
1913 | void |
||
1914 | ep_log( |
||
1915 | EP_STAT estat, |
||
1916 | const char *fmt, |
||
1917 | 1081f575 | Eric Allman | ...); |
1918 | |||
1919 | void |
||
1920 | ep_logv( |
||
1921 | EP_STAT estat, |
||
1922 | const char *fmt, |
||
1923 | va_list va);</programlisting> |
||
1924 | d63b8179 | Eric Allman | |
1925 | 58c51fe6 | Eric Allman | <para>The <function>ep_log</function> and <function>ep_logv</function> |
1926 | routines send information to various system logs. The default is to send |
||
1927 | to <function>syslog</function>(3) and to <symbol>stderr</symbol>. You can |
||
1928 | disable or change this by calling <function>ep_log_init</function> before |
||
1929 | the first logging call, and extend it by passing another logging method to |
||
1930 | <function>ep_log_addmethod</function>, which causes |
||
1931 | <parameter>func</parameter> to be called whenever a message with severity |
||
1932 | at least the value of the <parameter>minsev</parameter> parameter |
||
1933 | (<constant>EP_STAT_SEV_OK</constant>, |
||
1934 | <constant>EP_STAT_SEV_WARN</constant>, |
||
1935 | <constant>EP_STAT_SEV_ERROR</constant>, |
||
1936 | <constant>EP_STAT_SEV_SEVERE</constant>, |
||
1937 | <constant>EP_STAT_SEV_ABORT</constant>).</para> |
||
1938 | |||
1939 | <para>The status code is logged together with the printf-style message. |
||
1940 | The syslog severity is determined from the severity of the status code: |
||
1941 | <constant>OK</constant> codes log an <constant>LOG_INFO</constant> |
||
1942 | message, <constant>WARN</constant> codes log a |
||
1943 | <constant>LOG_WARNING</constant> message, <constant>ERROR</constant> codes |
||
1944 | log a <constant>LOG_ERR</constant> message, <constant>SEVERE</constant> |
||
1945 | codes log a <constant>LOG_CRIT</constant> message, and |
||
1946 | <constant>ABORT</constant> codes log a <constant>LOG_ALERT</constant> |
||
1947 | message.</para> |
||
1948 | d63b8179 | Eric Allman | </section> |
1949 | |||
1950 | <section> |
||
1951 | <title>ARGUMENT CRACKING</title> |
||
1952 | |||
1953 | <para><remark>Not implemented at this time</remark>. To help with parsing |
||
1954 | command line arguments. A descriptor is declared as follows:</para> |
||
1955 | |||
1956 | <programlisting> #include <ep/ep_crackargv.h> |
||
1957 | |||
1958 | unsigned long NTests; |
||
1959 | long Seed; |
||
1960 | static char *FileName; |
||
1961 | |||
1962 | EP_CAV_DESCR ArgvDescriptor[] = |
||
1963 | { |
||
1964 | { "debug", EP_CAV_TYPE(debug), 'D', 5, |
||
1965 | "Debug", "debug-flags", NULL, |
||
1966 | EP_CAV_FLAG_NOARGS |
||
1967 | }, |
||
1968 | { "ntests", EP_CAV_TYPE(ulong), 'n', 1, |
||
1969 | "Number of tests", NULL, &NTests, |
||
1970 | EP_CAV_FLAG_REQUIRED |
||
1971 | }, |
||
1972 | { "seed", EP_CAV_TYPE(long), 's', 1, |
||
1973 | NULL, NULL, &Seed, |
||
1974 | EP_CAV_FLAG_NONE |
||
1975 | } |
||
1976 | { NULL, EP_CAV_TYPE(string), '\0', 0, |
||
1977 | NULL, NULL, &FileName, |
||
1978 | EP_CAV_FLAG_NONE |
||
1979 | } |
||
1980 | EP_CAV_DESCR_END |
||
1981 | };</programlisting> |
||
1982 | |||
1983 | <para>The <function>ep_crackargv</function> routine is then called with an |
||
1984 | argument vector and a descriptor:</para> |
||
1985 | |||
1986 | <programlisting> stat = ep_crackargv(const char **argv, const EP_CAV_DESCR *descr);</programlisting> |
||
1987 | |||
1988 | <para>The argument vector is then matched to the descriptor and |
||
1989 | appropriate bindings done. Duplicate and missing flags are diagnosed and |
||
1990 | all conversions are done.</para> |
||
1991 | |||
1992 | <para>The fields in the descriptor are:</para> |
||
1993 | |||
1994 | <itemizedlist> |
||
1995 | <listitem> |
||
1996 | <para>The long name. On Unix, this is matched against arguments |
||
1997 | beginning "--". This is case independent.</para> |
||
1998 | </listitem> |
||
1999 | |||
2000 | <listitem> |
||
2001 | <para>The data type. This is always |
||
2002 | <constant>EP_CAV_TYPE</constant>(something), which calls the |
||
2003 | conversion routine named <function>ep_cvt_txt_to_something</function> |
||
2004 | passing it the value as a text string and a pointer to the output |
||
2005 | location (see below).</para> |
||
2006 | </listitem> |
||
2007 | |||
2008 | <listitem> |
||
2009 | <para>The short (single character) name. On Unix, this is matched |
||
2010 | against arguments beginning "-". Flags without values can be combined |
||
2011 | into one flag -- that is, if "-a -b" sets two boolean flags, "-ab" |
||
2012 | does the same thing.</para> |
||
2013 | </listitem> |
||
2014 | |||
2015 | <listitem> |
||
2016 | <para>The number of bytes of the long name that must match. This |
||
2017 | allows abbreviation of names. See below.</para> |
||
2018 | </listitem> |
||
2019 | |||
2020 | <listitem> |
||
2021 | <para>The prompt. If flags are required and a prompt is available, |
||
2022 | <function>ep_crackargv</function> can prompt for missing parameters. |
||
2023 | Not yet implemented.</para> |
||
2024 | </listitem> |
||
2025 | |||
2026 | <listitem> |
||
2027 | <para>The usage message to describe this parameter. Defaults to the |
||
2028 | long name.</para> |
||
2029 | </listitem> |
||
2030 | |||
2031 | <listitem> |
||
2032 | <para>The value pointer. A pointer to the data area in which to store |
||
2033 | the results. If NULL, this parameter cannot accept a value.</para> |
||
2034 | </listitem> |
||
2035 | |||
2036 | <listitem> |
||
2037 | <para>Flag bits, as described below.</para> |
||
2038 | </listitem> |
||
2039 | </itemizedlist> |
||
2040 | |||
2041 | <para>Long flag names can be abbreviated. All characters of the command |
||
2042 | line must match the descriptor, but only the number indicated in the "must |
||
2043 | match" field need be present. For example, given a name in the descriptor |
||
2044 | of "ntests" with a "must match" field of 2 will match "--ntests", |
||
2045 | "--ntes", "--nt", but not "--ntext", "--n", or "--nteststotry".</para> |
||
2046 | |||
2047 | <para>Flag bits include:</para> |
||
2048 | |||
2049 | <variablelist> |
||
2050 | <varlistentry> |
||
2051 | <term><constant>EP_CAV_FLAG_NONE</constant></term> |
||
2052 | |||
2053 | <listitem> |
||
2054 | <para>No special processing</para> |
||
2055 | </listitem> |
||
2056 | </varlistentry> |
||
2057 | |||
2058 | <varlistentry> |
||
2059 | <term><constant>EP_CAV_FLAG_NOARGS</constant></term> |
||
2060 | |||
2061 | <listitem> |
||
2062 | <para>This parameter takes no arguments (e.g., a boolean)</para> |
||
2063 | </listitem> |
||
2064 | </varlistentry> |
||
2065 | |||
2066 | <varlistentry> |
||
2067 | <term><constant>EP_CAV_FLAG_NOMORE</constant></term> |
||
2068 | |||
2069 | <listitem> |
||
2070 | <para>This consumes all remaining arguments (normally |
||
2071 | EP_CAV_TYPE(Vector))</para> |
||
2072 | </listitem> |
||
2073 | </varlistentry> |
||
2074 | |||
2075 | <varlistentry> |
||
2076 | <term><constant>EP_CAV_FLAG_MULTVAL</constant></term> |
||
2077 | |||
2078 | <listitem> |
||
2079 | <para>There can be multiple values for this parameter (only relevant |
||
2080 | for flags)</para> |
||
2081 | </listitem> |
||
2082 | </varlistentry> |
||
2083 | |||
2084 | <varlistentry> |
||
2085 | <term><constant>EP_CAV_FLAG_REQUIRED</constant></term> |
||
2086 | |||
2087 | <listitem> |
||
2088 | <para>If this parameter is missing it is an error</para> |
||
2089 | </listitem> |
||
2090 | </varlistentry> |
||
2091 | </variablelist> |
||
2092 | |||
2093 | <para>Predefined types and the type of the corresponding value pointer |
||
2094 | are:</para> |
||
2095 | |||
2096 | <simplelist columns="3" type="horiz"> |
||
2097 | <member>bool</member> |
||
2098 | |||
2099 | <member>bool_t *</member> |
||
2100 | |||
2101 | <member>Booleans. Should have |
||
2102 | <constant>EP_CAV_FLAG_NOARGS</constant>.</member> |
||
2103 | |||
2104 | <member>string</member> |
||
2105 | |||
2106 | <member>const char **</member> |
||
2107 | |||
2108 | <member>Strings.</member> |
||
2109 | |||
2110 | <member>long</member> |
||
2111 | |||
2112 | <member>long *</member> |
||
2113 | |||
2114 | <member>Signed long integers.</member> |
||
2115 | |||
2116 | <member>ulong</member> |
||
2117 | |||
2118 | <member>unsigned long *</member> |
||
2119 | |||
2120 | <member>Unsigned long integers.</member> |
||
2121 | |||
2122 | <member>double</member> |
||
2123 | |||
2124 | <member>double *</member> |
||
2125 | |||
2126 | <member>Double point floating point.</member> |
||
2127 | |||
2128 | <member>vector</member> |
||
2129 | |||
2130 | <member>const char ***</member> |
||
2131 | |||
2132 | <member>Vectors. Must have the EP_CAV_FLAG_MULTVAL flag set. Can only be |
||
2133 | one, and it must be at the end.</member> |
||
2134 | |||
2135 | <member>debug</member> |
||
2136 | |||
2137 | <member>NULL</member> |
||
2138 | |||
2139 | <member>Sets debug flags</member> |
||
2140 | </simplelist> |
||
2141 | |||
2142 | <para>To appear:</para> |
||
2143 | |||
2144 | <simplelist columns="2" type="horiz"> |
||
2145 | <member>int8</member> |
||
2146 | |||
2147 | <member>int8_t *</member> |
||
2148 | |||
2149 | <member>uint8</member> |
||
2150 | |||
2151 | <member>uint8_t *</member> |
||
2152 | |||
2153 | <member>int16</member> |
||
2154 | |||
2155 | <member>int16_t *</member> |
||
2156 | |||
2157 | <member>uint16</member> |
||
2158 | |||
2159 | <member>uint16_t *</member> |
||
2160 | |||
2161 | <member>int32</member> |
||
2162 | |||
2163 | <member>int32_t *</member> |
||
2164 | |||
2165 | <member>uint32</member> |
||
2166 | |||
2167 | <member>uint32_t *</member> |
||
2168 | |||
2169 | <member>int64</member> |
||
2170 | |||
2171 | <member>int64_t *</member> |
||
2172 | |||
2173 | <member>uint64</member> |
||
2174 | |||
2175 | <member>uint64_t *</member> |
||
2176 | |||
2177 | <member>admparam</member> |
||
2178 | |||
2179 | <member>const char *</member> |
||
2180 | </simplelist> |
||
2181 | |||
2182 | <para>Administrative parameters (see |
||
2183 | <function>ep_adm_getintparam</function> and |
||
2184 | <function>ep_adm_getstrparam</function>). The value pointer is the name of |
||
2185 | the parameter to set.</para> |
||
2186 | |||
2187 | <para>New parameter types can be trivially created by defining new |
||
2188 | routines named |
||
2189 | <function>ep_cvt_txt_to_</function><replaceable>type</replaceable> that |
||
2190 | take a <type>const char *</type> as input and a |
||
2191 | <type><replaceable>type</replaceable> *</type> output pointer. They return |
||
2192 | <type>EP_STAT</type>. Conversion errors should fail.</para> |
||
2193 | </section> |
||
2194 | |||
2195 | <section> |
||
2196 | <title>MISCELLANEOUS STUFF</title> |
||
2197 | |||
2198 | <programlisting linenumbering="numbered"> EP_UT_BITSET(uint32 bits, // return true if any bits... |
||
2199 | uint32_t word) // ... are set in word |
||
2200 | |||
2201 | /* |
||
2202 | EP_UT_SETBIT(uint32_t bits, // set these bits... |
||
2203 | uint32_t word) // ... in this word |
||
2204 | |||
2205 | EP_UT_CLRBIT(uint32 bits, // clear these bits... |
||
2206 | uint32_t word) // ... in this word |
||
2207 | */ |
||
2208 | |||
2209 | EP_UT_BITMAP( // declare bitmap |
||
2210 | name, // name of bitmap to declare |
||
2211 | nbits) // number of bits in map |
||
2212 | |||
2213 | EP_UT_CLRBITMAP( // clear bitmap |
||
2214 | name) // bitmap to clear |
||
2215 | |||
2216 | EP_UT_BITNSET(int bitn, // true if bit number bitn is set... |
||
2217 | bitmap) // ... in this map |
||
2218 | |||
2219 | EP_UT_SETBITN(int bitn, // set bit number bitn... |
||
2220 | bitmap) // ... in this map |
||
2221 | |||
2222 | EP_UT_CLRBITN(int bitn, // clear bit number bitn... |
||
2223 | bitmap) // ... in this map |
||
2224 | |||
2225 | EP_GEN_DEADBEEF // a value you can use to trash memory</programlisting> |
||
2226 | |||
2227 | <warning> |
||
2228 | <para>There is no checking for the BITMAP routines |
||
2229 | (<function>EP_UT_BITNSET</function>, <function>EP_UT_SETBITN</function>, |
||
2230 | <function>EP_UT_CLRBITN</function>) to ensure that the bit indicated is |
||
2231 | in range for the size of the bitmap.</para> |
||
2232 | </warning> |
||
2233 | </section> |
||
2234 | |||
2235 | <section> |
||
2236 | <title>INTERACTION WITH THE ENVIRONMENT</title> |
||
2237 | |||
2238 | <section> |
||
2239 | <title>Global Administrative Parameters</title> |
||
2240 | |||
2241 | <para>There are a bunch of parameters that we would prefer to be |
||
2242 | settable at run time. We'll model this on sysctl(8). Before accessing |
||
2243 | parameters you must read them using |
||
2244 | <function>ep_adm_readparams</function>. This routine takes a |
||
2245 | <varname>name</varname> and then looks for a file in a search path. That |
||
2246 | path may be set using the PARAM_PATH environment variable, and defaults |
||
2247 | to:<programlisting>.ep_adm_params:~/.ep_adm_params:/usr/local/etc/ep_adm_params:/etc/ep_adm_params</programlisting>For |
||
2248 | example, searching for a name such as "<userinput>defaults</userinput>" |
||
2249 | will first try to read the file |
||
2250 | <filename>.ep_adm_params/defaults</filename>. If that is found the |
||
2251 | search stops, otherwise it trys |
||
2252 | <filename>~/.ep_adm_params/defaults</filename>, and so forth. New values |
||
2253 | replace old ones, so programs that want to search more than one file |
||
2254 | should start with the most generic one and continue to the least generic |
||
2255 | one.</para> |
||
2256 | |||
2257 | <programlisting> #include <ep/ep_adm.h> |
||
2258 | |||
2259 | void |
||
2260 | ep_adm_readparams( |
||
2261 | const char *name) // basename of the parameter file |
||
2262 | |||
2263 | int |
||
2264 | ep_adm_getintparam( |
||
2265 | const char *name, // name of the parameter |
||
2266 | int default) // value if parameter not set |
||
2267 | |||
2268 | dc11518f | Eric Allman | long |
2269 | d63b8179 | Eric Allman | ep_adm_getlongparam( |
2270 | const char *name, // name of the parameter |
||
2271 | long default) // value if parameter not set |
||
2272 | |||
2273 | c7258388 | Eric Allman | intmax_t |
2274 | ep_adm_getintmaxparam( |
||
2275 | const char *name, // name of the parameter |
||
2276 | intmax_t default) // value if the parameter is not set |
||
2277 | |||
2278 | dc11518f | Eric Allman | bool |
2279 | d63b8179 | Eric Allman | ep_adm_getboolparam( |
2280 | const char *name, // name of the parameter |
||
2281 | bool default) // value if parameter not set |
||
2282 | |||
2283 | dc11518f | Eric Allman | const char * |
2284 | d63b8179 | Eric Allman | ep_adm_getstrparam( |
2285 | const char *name, // name of the parameter |
||
2286 | char *default) // value if parameter not set</programlisting> |
||
2287 | |||
2288 | <para>Names are structured kind of like <function>sysctl</function> |
||
2289 | arguments or X Resource names, e.g., |
||
2290 | "<varname>libep.stream.hfile.bsize</varname>". You must read one or more |
||
2291 | parameter files before getting parameters.</para> |
||
2292 | 59c6c7e0 | Eric Allman | |
2293 | <para>If the <constant>EP_CONF_ADM_ENV_OVERRIDE</constant> defined |
||
2294 | constant is set to <constant>1</constant> during compilation, parameters |
||
2295 | can be overridden in the environment. For example,</para> |
||
2296 | |||
2297 | <programlisting>env swarm.gdp.routers=foo.example.com gdplogd</programlisting> |
||
2298 | |||
2299 | <para>This only works if the program is running as a non-root user |
||
2300 | without setuid.</para> |
||
2301 | d63b8179 | Eric Allman | </section> |
2302 | |||
2303 | <section> |
||
2304 | <title>Terminal Video Sequences and Characters</title> |
||
2305 | |||
2306 | <para>Mostly for debugging use. Right now compiled in for ANSI |
||
2307 | xterms.</para> |
||
2308 | |||
2309 | <programlisting> #include <ep/ep_string.h> |
||
2310 | |||
2311 | struct epVidSequences |
||
2312 | { |
||
2313 | const char *vidnorm; // set video to normal |
||
2314 | const char *vidbold; // set video to bold |
||
2315 | const char *vidfaint; // set video to faint |
||
2316 | const char *vidstout; // set viadeo to "standout" |
||
2317 | const char *viduline; // set video to underline |
||
2318 | const char *vidblink; // set video to blink |
||
2319 | const char *vidinv; // set video to invert |
||
2320 | const char *vidfgblack; // set foreground black |
||
2321 | const char *vidfgred; // set foreground red |
||
2322 | const char *vidfggreen; // set foreground green |
||
2323 | const char *vidfgyellow; // set foreground yellow |
||
2324 | const char *vidfgblue; // set foreground blue |
||
2325 | const char *vidfgmagenta; // set foreground magenta |
||
2326 | const char *vidfgcyan; // set foreground cyan |
||
2327 | const char *vidfgwhite // set foreground white |
||
2328 | const char *vidbgblack; // set background black |
||
2329 | const char *vidbgred; // set background red |
||
2330 | const char *vidbggreen; // set background green |
||
2331 | const char *vidbgyellow; // set background yellow |
||
2332 | const char *vidbgblue // set background blue |
||
2333 | const char *vidbgmagenta; // set background magenta |
||
2334 | const char *vidbgcyan; // set background cyan |
||
2335 | const char *vidbtwhite; // set background white |
||
2336 | } *EpVid; |
||
2337 | |||
2338 | struct epCharSequences |
||
2339 | { |
||
2340 | const char *lquote; // left quote sequence |
||
2341 | const char *rquote; // right quote sequence |
||
2342 | const char *copyright; // copyright symbol |
||
2343 | const char *degree; // degree symbol |
||
2344 | const char *micro; // micro symbol |
||
2345 | const char *plusminus; // +/- symbol |
||
2346 | const char *times; // mathematical times symbol |
||
2347 | const char *divide; // mathematical division symbol |
||
2348 | const char *null; // "null" symbol |
||
2349 | const char *notequal; // mathematical "not equal" symbol |
||
2350 | const char *unprintable; // substitution for unprintable characters |
||
2351 | const char *paragraph; // paragraph symbol |
||
2352 | const char *section; // section symbol |
||
2353 | const char *notsign; // logical not symbol |
||
2354 | const char *infinity; // infinity symbol |
||
2355 | } *EpChar; |
||
2356 | |||
2357 | EP_STAT ep_str_vid_set( // set video style |
||
2358 | const char *type); // NULL, "none", or "ansi" |
||
2359 | |||
2360 | EP_STAT ep_str_char_set( // set special characters |
||
2361 | const char *type); // character set (see below)</programlisting> |
||
2362 | |||
2363 | <para>These structures contain character sequences used for printing |
||
2364 | video controls and special characters respectively. The |
||
2365 | <function>ep_str_vid_set</function> routines allows you to choose the |
||
2366 | video escape sequences. Passing <constant>NULL</constant> causes an |
||
2367 | educated guess at the default on the basis of the <envar>TERM</envar> |
||
2368 | environment variable. Any <envar>TERM</envar> setting beginning with |
||
2369 | "<constant>xterm</constant>" is the same as specifying |
||
2370 | "<constant>ansi</constant>" as the type and anything else is the same as |
||
2371 | specifying "<constant>none</constant>" as the type (which sets all the |
||
2372 | video strings to null strings). Blessedly, xterm doesn't seem to render |
||
2373 | blink, nor faint or standout. Bold and blink are both rendered in bold. |
||
2374 | So, for best results use bold, uline, and inv (and of course |
||
2375 | norm).</para> |
||
2376 | |||
2377 | <para>The <function>ep_str_char_set</function> allows you to set special |
||
2378 | character encodings. Its parameter may be <constant>NULL</constant> |
||
2379 | (which guesses based on the <envar>LANG</envar> environment variable), |
||
2380 | "<constant>ascii</constant>", "<constant>iso-8859-1</constant>", |
||
2381 | "<constant>iso-latin-1</constant>", "<constant>utf-8</constant>", or |
||
2382 | "<constant>utf8</constant>". The mappings are shown in the following |
||
2383 | table:</para> |
||
2384 | |||
2385 | <informaltable frame="box" rules="all"> |
||
2386 | <thead> |
||
2387 | <tr align="center"> |
||
2388 | <th>Name</th> |
||
2389 | |||
2390 | <th>ASCII</th> |
||
2391 | |||
2392 | <th>Other Charset</th> |
||
2393 | </tr> |
||
2394 | </thead> |
||
2395 | |||
2396 | <tbody> |
||
2397 | <tr> |
||
2398 | <td>lquote</td> |
||
2399 | |||
2400 | <td align="center">`</td> |
||
2401 | |||
2402 | dc11518f | Eric Allman | <td align="center">«</td> |
2403 | d63b8179 | Eric Allman | </tr> |
2404 | |||
2405 | <tr> |
||
2406 | <td>rquote</td> |
||
2407 | |||
2408 | <td align="center">'</td> |
||
2409 | |||
2410 | dc11518f | Eric Allman | <td align="center">»</td> |
2411 | d63b8179 | Eric Allman | </tr> |
2412 | |||
2413 | <tr> |
||
2414 | <td>copyright</td> |
||
2415 | |||
2416 | <td align="center">(c)</td> |
||
2417 | |||
2418 | dc11518f | Eric Allman | <td align="center">©</td> |
2419 | d63b8179 | Eric Allman | </tr> |
2420 | |||
2421 | <tr> |
||
2422 | <td>degree</td> |
||
2423 | |||
2424 | <td align="center">deg</td> |
||
2425 | |||
2426 | 42d9d20e | Eric Allman | <td align="center">°</td> |
2427 | d63b8179 | Eric Allman | </tr> |
2428 | |||
2429 | <tr> |
||
2430 | <td>micro</td> |
||
2431 | |||
2432 | <td align="center">u</td> |
||
2433 | |||
2434 | dc11518f | Eric Allman | <td align="center">µ</td> |
2435 | d63b8179 | Eric Allman | </tr> |
2436 | |||
2437 | <tr> |
||
2438 | <td>plusminus</td> |
||
2439 | |||
2440 | <td align="center">+/-</td> |
||
2441 | |||
2442 | dc11518f | Eric Allman | <td align="center">±</td> |
2443 | d63b8179 | Eric Allman | </tr> |
2444 | |||
2445 | <tr> |
||
2446 | <td>times</td> |
||
2447 | |||
2448 | <td align="center">*</td> |
||
2449 | |||
2450 | dc11518f | Eric Allman | <td align="center">×</td> |
2451 | d63b8179 | Eric Allman | </tr> |
2452 | |||
2453 | <tr> |
||
2454 | <td>divide</td> |
||
2455 | |||
2456 | <td align="center">/</td> |
||
2457 | |||
2458 | dc11518f | Eric Allman | <td align="center">÷</td> |
2459 | d63b8179 | Eric Allman | </tr> |
2460 | |||
2461 | <tr> |
||
2462 | <td>null</td> |
||
2463 | |||
2464 | <td align="center">NULL</td> |
||
2465 | |||
2466 | 42d9d20e | Eric Allman | <td align="center">∅</td> |
2467 | d63b8179 | Eric Allman | </tr> |
2468 | |||
2469 | <tr> |
||
2470 | <td>notequal</td> |
||
2471 | |||
2472 | <td align="center">!=</td> |
||
2473 | |||
2474 | dc11518f | Eric Allman | <td align="center">≠</td> |
2475 | d63b8179 | Eric Allman | </tr> |
2476 | |||
2477 | <tr> |
||
2478 | <td>unprintable</td> |
||
2479 | |||
2480 | <td align="center">?</td> |
||
2481 | |||
2482 | dc11518f | Eric Allman | <td align="center">⌧</td> |
2483 | d63b8179 | Eric Allman | </tr> |
2484 | |||
2485 | <tr> |
||
2486 | <td>paragraph</td> |
||
2487 | |||
2488 | <td align="center">pp.</td> |
||
2489 | |||
2490 | dc11518f | Eric Allman | <td align="center">¶</td> |
2491 | d63b8179 | Eric Allman | </tr> |
2492 | |||
2493 | <tr> |
||
2494 | <td>section</td> |
||
2495 | |||
2496 | <td align="center">sec.</td> |
||
2497 | |||
2498 | dc11518f | Eric Allman | <td align="center">§</td> |
2499 | d63b8179 | Eric Allman | </tr> |
2500 | |||
2501 | <tr> |
||
2502 | <td>notsign</td> |
||
2503 | |||
2504 | <td align="center">(not)</td> |
||
2505 | |||
2506 | dc11518f | Eric Allman | <td align="center">¬</td> |
2507 | d63b8179 | Eric Allman | </tr> |
2508 | |||
2509 | <tr> |
||
2510 | <td>infinity</td> |
||
2511 | |||
2512 | <td align="center">(inf)</td> |
||
2513 | |||
2514 | dc11518f | Eric Allman | <td align="center">∞</td> |
2515 | d63b8179 | Eric Allman | </tr> |
2516 | </tbody> |
||
2517 | </informaltable> |
||
2518 | |||
2519 | <para>Other values may be added to this table as needed.</para> |
||
2520 | |||
2521 | <para>Example:</para> |
||
2522 | |||
2523 | <programlisting> fprintf(ep_dbg_getfile(), "Input was %s%s%s\n", |
||
2524 | EpVidSeq.lquote, input, EpVidSeq.rquote);</programlisting> |
||
2525 | </section> |
||
2526 | 55b46f00 | Eric Allman | |
2527 | <section> |
||
2528 | <title>Startup/Shutdown</title> |
||
2529 | |||
2530 | <para>If running under <systemitem>systemd</systemitem>-based versions |
||
2531 | of Linux, it is possible to signal status changes to the startup |
||
2532 | environment, notably about system startup and shutdown. This is only |
||
2533 | relevant for programs that run as system daemons.</para> |
||
2534 | |||
2535 | <programlisting>#include <ep/ep_sd.h> |
||
2536 | |||
2537 | void |
||
2538 | ep_sd_notifyf( |
||
2539 | const char *fmt, |
||
2540 | ...);</programlisting> |
||
2541 | |||
2542 | <para>The <parameter>fmt</parameter> and any arguments are printed a'la |
||
2543 | <function>printf</function>(3) to a system buffer that is delivered to |
||
2544 | <systemitem>systemd</systemitem>. The format of that buffer is defined |
||
2545 | by <function>sd_notify</function>(3) and is not detailed here. Roughly, |
||
2546 | each line of the output looks like an environment variable definition. |
||
2547 | For example:</para> |
||
2548 | |||
2549 | <programlisting>// to inform the system that this service is ready: |
||
2550 | ep_sd_notifyf( |
||
2551 | "READY=1"); |
||
2552 | |||
2553 | // to inform the system that this service is shutting down: |
||
2554 | ep_sd_notifyf( |
||
2555 | "STOPPING=1\n" |
||
2556 | "STATUS=Exiting on user signal %d\n", |
||
2557 | sig);</programlisting> |
||
2558 | |||
2559 | <para>Important values include <literal>READY=1</literal>, |
||
2560 | <literal>RELOADING=1</literal>, <literal>WATCHDOG=1</literal>, and |
||
2561 | <literal>STOPPING=...</literal>.</para> |
||
2562 | |||
2563 | <para>If the <constant>EP_OSCF_HAS_SD_NOTIFY</constant> flag is set to |
||
2564 | zero at compilation time, this call is a no-op. This is the case on most |
||
2565 | systems.</para> |
||
2566 | |||
2567 | <remark>This should really abstract the syntax out more, rather than |
||
2568 | making it <systemitem>systemd</systemitem> specific, so that it can |
||
2569 | potentially be used on other systems.</remark> |
||
2570 | </section> |
||
2571 | d63b8179 | Eric Allman | </section> |
2572 | |||
2573 | <section> |
||
2574 | <title>TRANSLATIONS</title> |
||
2575 | |||
2576 | b0136566 | Eric Allman | <para>Simple string translations for certain external formats, for example |
2577 | as might be used by URLs or Quoted-Printable.</para> |
||
2578 | d63b8179 | Eric Allman | |
2579 | <programlisting> #include <ep/ep_xlate.h> |
||
2580 | |||
2581 | int |
||
2582 | ep_xlate_in( |
||
2583 | b0136566 | Eric Allman | const void *ext, // external (encoded) string input |
2584 | d63b8179 | Eric Allman | uchar_t *out, // pointer to output buffer |
2585 | size_t olen, // length of output buffer |
||
2586 | char stopchar, // input char to stop at |
||
2587 | uint32_t how) // what kind of translations to do</programlisting> |
||
2588 | |||
2589 | b0136566 | Eric Allman | <para>Translates an external form (with encodings) into internal form |
2590 | (potentially 8-bit binary). Returns the number of output bytes. The "how" |
||
2591 | parameter tells what translations to do -- they can be combined:</para> |
||
2592 | d63b8179 | Eric Allman | |
2593 | <table> |
||
2594 | <title>EP_XLATE "how" Bits</title> |
||
2595 | |||
2596 | <tgroup cols="2"> |
||
2597 | 11ef2ab4 | Eric Allman | <colspec/> |
2598 | d63b8179 | Eric Allman | |
2599 | 11ef2ab4 | Eric Allman | <colspec colwidth="3*"/> |
2600 | d63b8179 | Eric Allman | |
2601 | <tbody> |
||
2602 | <row> |
||
2603 | <entry>EP_XLATE_PERCENT</entry> |
||
2604 | |||
2605 | <entry>Translate "%xx" like ESMTP</entry> |
||
2606 | </row> |
||
2607 | |||
2608 | <row> |
||
2609 | <entry>EP_XLATE_BSLASH</entry> |
||
2610 | |||
2611 | <entry>Translate backslash escapes like C</entry> |
||
2612 | </row> |
||
2613 | |||
2614 | <row> |
||
2615 | <entry>EP_XLATE_AMPER</entry> |
||
2616 | |||
2617 | <entry>Translate "&name;" like HTML</entry> |
||
2618 | </row> |
||
2619 | |||
2620 | <row> |
||
2621 | <entry>EP_XLATE_PLUS</entry> |
||
2622 | |||
2623 | <entry>Translate "+xx" like DNSs</entry> |
||
2624 | </row> |
||
2625 | |||
2626 | <row> |
||
2627 | <entry>EP_XLATE_EQUAL</entry> |
||
2628 | |||
2629 | <entry>Translate "=xx" like quoted-printable</entry> |
||
2630 | </row> |
||
2631 | |||
2632 | <row> |
||
2633 | <entry>EP_XLATE_8BIT</entry> |
||
2634 | |||
2635 | <entry>Translate 8-bit characters |
||
2636 | (<function>ep_xlate_out</function> only)</entry> |
||
2637 | </row> |
||
2638 | b0136566 | Eric Allman | |
2639 | <row> |
||
2640 | <entry>EP_XLATE_NPRINT</entry> |
||
2641 | |||
2642 | <entry>Translate non-printable characters |
||
2643 | (<function>ep_xlate_out</function> only)</entry> |
||
2644 | </row> |
||
2645 | d63b8179 | Eric Allman | </tbody> |
2646 | </tgroup> |
||
2647 | </table> |
||
2648 | |||
2649 | <programlisting> int |
||
2650 | ep_xlate_out( |
||
2651 | b0136566 | Eric Allman | const void *in, // internal (not encoded) input string |
2652 | d63b8179 | Eric Allman | size_t ilen, // length of in |
2653 | b0136566 | Eric Allman | FILE *osp, // encoded output stream pointer |
2654 | d63b8179 | Eric Allman | const char *forbid, // list of characters to encode |
2655 | uint32_t how) // how to do output translations</programlisting> |
||
2656 | |||
2657 | <para>Unlike input, it doesn't make sense to list more than one of |
||
2658 | <constant>EP_XLATE_PERCENT</constant>, |
||
2659 | <constant>EP_XLATE_BSLASH</constant>, <constant>EP_XLATE_EQUAL</constant>, |
||
2660 | and <constant>EP_XLATE_PLUS</constant>. If none are listed, |
||
2661 | <constant>EP_XLATE_PLUS</constant> is assumed. |
||
2662 | <constant>EP_XLATE_8BIT</constant> can be added to encode all 8-bit |
||
2663 | b0136566 | Eric Allman | characters and <constant>EP_XLATE_NPRINT</constant> translates all |
2664 | unprintable characters (as determined by <function>isprint(3)</function>, |
||
2665 | which generally does understand locales). Returns the number of bytes |
||
2666 | output to the indicated osp.</para> |
||
2667 | d63b8179 | Eric Allman | |
2668 | <note> |
||
2669 | <para>[[Arguably they should both use streams for both input and |
||
2670 | output.]]</para> |
||
2671 | </note> |
||
2672 | |||
2673 | <para>There are also routines to encode/decode binaries in base64.</para> |
||
2674 | |||
2675 | <programlisting> #include <ep/ep_b64.h> |
||
2676 | |||
2677 | EP_STAT |
||
2678 | ep_b64_encode( |
||
2679 | const void *bin, // binary data to encode |
||
2680 | size_t bsize, // size of bin to encode |
||
2681 | char *txt, // text output buffer |
||
2682 | size_t tsize, // size of output buffer |
||
2683 | const char *encoding) // type of encoding (see below) |
||
2684 | |||
2685 | EP_STAT |
||
2686 | ep_b64_decode( |
||
2687 | const char *txt, // text to decode |
||
2688 | size_t tsize, // stop after tsize characters |
||
2689 | void *bin, // binary output buffer |
||
2690 | size_t bsize, // size of bin buffer |
||
2691 | const char *encoding) // type of encoding (see below) |
||
2692 | |||
2693 | #define EP_B64_NOWRAP 0x00 // never wrap lines |
||
2694 | #define EP_B64_WRAP64 0x01 // wrap at 64 characters |
||
2695 | #define EP_B64_WRAP76 0x02 // wrap at 76 characters |
||
2696 | #define EP_B64_WRAPMASK 0x03 // bit mask for wrapping |
||
2697 | #define EP_B64_PAD 0x04 // pad with '=' |
||
2698 | #define EP_B64_IGNCRUD 0x08 // ignore unrecognized chars |
||
2699 | |||
2700 | // encodings for common standards |
||
2701 | #define EP_B64_ENC_MIME "+/N" // WRAP76 PAD IGNCRUD |
||
2702 | #define EP_B64_ENC_PEM "+/E" // WRAP64 PAD -IGNCRUD |
||
2703 | #define EP_B64_ENC_URL "-_@" // NOWRAP -PAD -IGNCRUD</programlisting> |
||
2704 | |||
2705 | <para>The encoding is a three character string. The first two characters |
||
2706 | are used to represent the codes for positions 62 and 63 (these are the |
||
2707 | only two that are not letters or digits). The third is used as flag bits |
||
2708 | to indicate variations for various encodings. The three most common |
||
2709 | strings are included as defined constants (for MIME email, Privacy |
||
2710 | Enhanced Mail, and URLs).</para> |
||
2711 | </section> |
||
2712 | |||
2713 | <section> |
||
2714 | <title>XXX TO BE DONE</title> |
||
2715 | |||
2716 | <itemizedlist> |
||
2717 | <listitem> |
||
2718 | <para>Document ep_pprint.</para> |
||
2719 | </listitem> |
||
2720 | |||
2721 | <listitem> |
||
2722 | <para>Document ep_dumpfds (shows open file descriptors (for |
||
2723 | debugging).</para> |
||
2724 | </listitem> |
||
2725 | |||
2726 | <listitem> |
||
2727 | <para>Document ep_fread_unlocked.</para> |
||
2728 | </listitem> |
||
2729 | </itemizedlist> |
||
2730 | </section> |
||
2731 | 11ef2ab4 | Eric Allman | </article> |