1 
2 /*-------------------------------------------------------------*/
3 /***************************************************************
4  * A netwib_io is the main way to exchange data in netwib.     *
5  *                                                             *
6  * A concrete example first :                                  *
7  *   ----.     ,-----.     ,-------.     ,----.     ,------    *
8  *   file >---->readl >---( program )---->conv >---->socket    *
9  *   ----'     `-----'     `-------'     `----'     `------    *
10  *                                                             *
11  * It works like this :                                        *
12  *  - read data from a file                                    *
13  *  - read only line by line                                   *
14  *  - treat it in the program                                  *
15  *  - write data for output                                    *
16  *  - convert data, for example replacing '\' by "\\"          *
17  *  - write data to socket                                     *
18  *                                                             *
19  * This example contains 3 types of netwib_io :                *
20  *  - file and socket are "io final link"                      *
21  *  - readl and conv are "io link"                             *
22  *  - file and socket are also "io link" (because a            *
23  *    "io final link" is a special kind of "io link")          *
24  *  - conv is a "io chain" composed of conv+socket             *
25  *  - readl is a "io chain" composed of readl+file             *
26  *  - socket is a "io chain" composed of only socket           *
27  *  - file is a "io chain" composed of only file               *
28  *                                                             *
29  * Using the same program, we might for example read data      *
30  * from a file and write them back to a socket. This can be    *
31  * represented as :                                            *
32  *   ------.      ,-------.      ,---------                    *
33  *    file  >----( program )-----> socket                      *
34  *   ------'      `-------'      `---------                    *
35  * Another variant would be to plug readl or conv to other     *
36  * "io chain", such as :                                       *
37  *   ----.     ,-----.     ,-------.     ,----.     ,------    *
38  *   ipc  >---->readl >---( program )---->conv >---->record    *
39  *   ----'     `-----'     `-------'     `----'     `------    *
40  * An "io chain" can be bi-directional. For example :          *
41  *   --------.       ,--.      ,-------.                       *
42  *    socket  >------>l5 >----( program )-.                    *
43  *           <------<   <--.   `-------'  |                    *
44  *   --------'       `--'   `-------------'                    *
45  *                                                             *
46  * Note : you can find other examples at the end of this file  *
47  *                                                             *
48  * The main ideas to remember is :                             *
49  *  - a "io chain" is composed of one or more "io link"        *
50  *  - a "io link" might be intermediary or "io final link"     *
51  *  - those 3 types use the same structure : netwib_io         *
52  ***************************************************************/
53 
54 /*-------------------------------------------------------------*/
55 typedef struct netwib_io netwib_io;
56 
57 /*-------------------------------------------------------------*/
58 /* direction */
59 typedef enum {
60   NETWIB_IO_WAYTYPE_READ = 1,    /* read */
61   NETWIB_IO_WAYTYPE_WRITE,       /* write */
62   NETWIB_IO_WAYTYPE_RDWR,        /* read and write */
63   NETWIB_IO_WAYTYPE_NONE,        /* nor read nor write */
64   NETWIB_IO_WAYTYPE_SUPPORTED    /* every way supported by the io */
65 } netwib_io_waytype;
66 
67 /*-------------------------------------------------------------*/
68 /***************************************************************
69  * Currently, system "io final link" are :                     *
70  *    Name      Definition     Read/Write                      *
71  *   FILE   : regular file   : read/write                      *
72  *   FD     : file desc      : read/write                      *
73  *   HANDLE : Windows HANDLE : read/write                      *
74  *   KBD    : keyboard       : read                            *
75  *   RECORD : record         : read/write                      *
76  *   SOCK   : socket         : read/write                      *
77  *   SNIFF  : sniff          : read                            *
78  *   SPOOF  : spoof          : write                           *
79  * They are initialized by :                                   *
80  *  - netwib_io_init_file                                      *
81  *  - netwib_io_init_fd                                        *
82  *  - etc.                                                     *
83  ***************************************************************/
84 
85 /*-------------------------------------------------------------*/
86 /***************************************************************
87  * Those five functions permits to create and to navigate      *
88  * through a "io chain".                                       *
89  ***************************************************************/
90 
91 /*-------------------------------------------------------------*/
92 /* Name : netwib_io_plug
93    Description :
94      Create a chain by pluging one link/chain to another.
95    Input parameter(s) :
96      *piowheretoplug : io where to plug
97      typeofplug : type of plug
98    Input/output parameter(s) :
99      *pio : current io
100    Output parameter(s) :
101    Normal return values :
102      NETWIB_ERR_OK : ok
103 */
104 netwib_err netwib_io_plug(netwib_io *pio,
105                           netwib_io_waytype typeofplug,
106                           netwib_io *piowheretoplug);
107 /* netwib_err f(netwib_io *pio, netwib_io *piowheretoplug); */
108 #define netwib_io_plug_read(pio,piowheretoplug) netwib_io_plug(pio,NETWIB_IO_WAYTYPE_READ,piowheretoplug)
109 #define netwib_io_plug_write(pio,piowheretoplug) netwib_io_plug(pio,NETWIB_IO_WAYTYPE_WRITE,piowheretoplug)
110 #define netwib_io_plug_rdwr(pio,piowheretoplug) netwib_io_plug(pio,NETWIB_IO_WAYTYPE_RDWR,piowheretoplug)
111 #define netwib_io_plug_supported(pio,piowheretoplug) netwib_io_plug(pio,NETWIB_IO_WAYTYPE_SUPPORTED,piowheretoplug)
112 
113 /*-------------------------------------------------------------*/
114 /***************************************************************
115  * There are three ways to unplug :                            *
116  *      ,----.     ,----.     ,----.     ,----.     ,----.     *
117  *   ---> io1 >----> io2 >----> io3 >----> io4 >----> io5 >--  *
118  *      `----'     `----'     `----'     `----'     `----'     *
119  *                                                             *
120  * netwib_io_unplug_next with:                                 *
121  *   pio = &io1                                                *
122  *  ==> cut between io1 and io2, and put &io2 in pnextio       *
123  *                                                             *
124  * netwib_io_unplug_before with:                               *
125  *   pio = &io1                                                *
126  *   psearchedio = &io3                                        *
127  *  ==> cut between io2 and io3                                *
128  *                                                             *
129  * netwib_io_unplug_after with:                                *
130  *   pio = &io1                                                *
131  *   psearchedio = &io3                                        *
132  *  ==> cut between io3 and io4, and put &io4 in pafterio      *
133  ***************************************************************/
134 
135 /*-------------------------------------------------------------*/
136 /* Name : netwib_io_unplug_xyz
137    Description :
138      Separate a chain by unplugging one link/chain from another.
139    Input parameter(s) :
140      typeofplug : type of plug
141      *psearchedio : searched io
142    Input/output parameter(s) :
143      *pio : io chain
144    Output parameter(s) :
145      **ppnextio : next io or NULL if at end
146      **ppafterio : next io or NULL if at end
147    Normal return values :
148      NETWIB_ERR_OK : ok
149      NETWIB_ERR_NOTFOUND : psearchedio was not found
150 */
151 netwib_err netwib_io_unplug_next(netwib_io *pio,
152                                  netwib_io_waytype typeofplug,
153                                  netwib_io **ppnextio);
154 netwib_err netwib_io_unplug_before(netwib_io *pio,
155                                    netwib_io_waytype typeofplug,
156                                    netwib_io *psearchedio);
157 netwib_err netwib_io_unplug_after(netwib_io *pio,
158                                   netwib_io_waytype typeofplug,
159                                   netwib_io *psearchedio,
160                                   netwib_io **ppafterio);
161 #define netwib_io_unplug_next_read(pio,ppnextio) netwib_io_unplug_next(pio,NETWIB_IO_WAYTYPE_READ,ppnextio)
162 #define netwib_io_unplug_before_read(pio,psearchedio) netwib_io_unplug_before(pio,NETWIB_IO_WAYTYPE_READ,psearchedio)
163 #define netwib_io_unplug_after_read(pio,psearchedio,ppafterio) netwib_io_unplug_after(pio,NETWIB_IO_WAYTYPE_READ,psearchedio,ppafterio)
164 #define netwib_io_unplug_next_write(pio,ppnextio) netwib_io_unplug_next(pio,NETWIB_IO_WAYTYPE_WRITE,ppnextio)
165 #define netwib_io_unplug_before_write(pio,psearchedio) netwib_io_unplug_before(pio,NETWIB_IO_WAYTYPE_WRITE,psearchedio)
166 #define netwib_io_unplug_after_write(pio,psearchedio,ppafterio) netwib_io_unplug_after(pio,NETWIB_IO_WAYTYPE_WRITE,psearchedio,ppafterio)
167 #define netwib_io_unplug_next_rdwr(pio,ppnextio) netwib_io_unplug_next(pio,NETWIB_IO_WAYTYPE_RDWR,ppnextio)
168 #define netwib_io_unplug_before_rdwr(pio,psearchedio) netwib_io_unplug_before(pio,NETWIB_IO_WAYTYPE_RDWR,psearchedio)
169 #define netwib_io_unplug_after_rdwr(pio,psearchedio,ppafterio) netwib_io_unplug_after(pio,NETWIB_IO_WAYTYPE_RDWR,psearchedio,ppafterio)
170 #define netwib_io_unplug_next_supported(pio,ppnextio) netwib_io_unplug_next(pio,NETWIB_IO_WAYTYPE_SUPPORTED,ppnextio)
171 #define netwib_io_unplug_before_supported(pio,psearchedio) netwib_io_unplug_before(pio,NETWIB_IO_WAYTYPE_SUPPORTED,psearchedio)
172 #define netwib_io_unplug_after_supported(pio,psearchedio,ppafterio) netwib_io_unplug_after(pio,NETWIB_IO_WAYTYPE_SUPPORTED,psearchedio,ppafterio)
173 
174 /*-------------------------------------------------------------*/
175 /* Name : netwib_io_next
176    Description :
177      Obtain the next io in the chain.
178    Input parameter(s) :
179      *pio : io
180    Input/output parameter(s) :
181      **ppionext : io after pio of type typetofollow
182    Output parameter(s) :
183    Normal return values :
184      NETWIB_ERR_OK : ok
185      NETWIB_ERR_DATAEND : there is no more io after
186 */
187 netwib_err netwib_io_next(netwib_io *pio,
188                           netwib_io_waytype typetofollow,
189                           netwib_io **ppionext);
190 /* netwib_err f(netwib_io *pio, netwib_io *pionext); */
191 #define netwib_io_next_read(pio,pionext) netwib_io_next(pio,NETWIB_IO_WAYTYPE_READ,pionext)
192 #define netwib_io_next_write(pio,pionext) netwib_io_next(pio,NETWIB_IO_WAYTYPE_WRITE,pionext)
193 #define netwib_io_next_rdwr(pio,pionext) netwib_io_next(pio,NETWIB_IO_WAYTYPE_RDWR,pionext)
194 #define netwib_io_next_supported(pio,pionext) netwib_io_next(pio,NETWIB_IO_WAYTYPE_SUPPORTED,pionext)
195 
196 /*-------------------------------------------------------------*/
197 /***************************************************************
198  * Those three functions permits to exchange data through a    *
199  * "io chain".                                                 *
200  ***************************************************************/
201 
202 /*-------------------------------------------------------------*/
203 /* Name : netwib_io_write_xyz
204    Description :
205      Write data to a netwib_io.
206    Input parameter(s) :
207      *pbuf : buffer to write
208    Input/output parameter(s) :
209      **pio : netwib_io where to write
210    Output parameter(s) :
211    Normal return values :
212      NETWIB_ERR_OK : ok
213 */
214 netwib_err netwib_io_write(netwib_io *pio,
215                            netwib_constbuf *pbuf);
216 
217 /*-------------------------------------------------------------*/
218 /* Name : netwib_io_read_xyz
219    Description :
220      Read data to a netwib_io.
221    Input parameter(s) :
222    Input/output parameter(s) :
223      **pio : netwib_io where to read
224      *pbuf : buffer storing read data
225    Output parameter(s) :
226    Normal return values :
227      NETWIB_ERR_OK : ok
228      NETWIB_ERR_DATAEND : end of data
229 */
230 netwib_err netwib_io_read(netwib_io *pio,
231                           netwib_buf *pbuf);
232 
233 /*-------------------------------------------------------------*/
234 /* Name : netwib_io_unread
235    Description :
236      Put data back in the read io.
237    Input parameter(s) :
238    Input/output parameter(s) :
239      **pio : netwib_io where to read
240      *pbuf : buffer containing data
241    Output parameter(s) :
242    Normal return values :
243      NETWIB_ERR_OK : ok
244 */
245 netwib_err netwib_io_unread(netwib_io *pio,
246                             netwib_constbuf *pbuf);
247 
248 /*-------------------------------------------------------------*/
249 /***************************************************************
250  * Those three functions permits to control an "io chain".     *
251  ***************************************************************/
252 
253 /*-------------------------------------------------------------*/
254 /* Name : netwib_io_wait
255    Description :
256      Wait for data in the io.
257    Input parameter(s) :
258      *pabstime : end time. If *pabstime is reached, function
259                  returns (*pevent set to NETWIB_FALSE).
260    Input/output parameter(s) :
261      **pio : netwib_io where to wait
262    Output parameter(s) :
263      *pevent : an event occurred
264    Normal return values :
265      NETWIB_ERR_OK : ok
266 */
267 netwib_err netwib_io_wait(netwib_io *pio,
268                           netwib_io_waytype way,
269                           netwib_consttime *pabstime,
270                           netwib_bool *pevent);
271 /* netwib_err f(netwib_io *pio, netwib_consttime *pabstime, netwib_bool *pevent); */
272 #define netwib_io_wait_read(pio,pabstime,pevent) netwib_io_wait(pio,NETWIB_IO_WAYTYPE_READ,pabstime,pevent)
273 #define netwib_io_wait_write(pio,pabstime,pevent) netwib_io_wait(pio,NETWIB_IO_WAYTYPE_WRITE,pabstime,pevent)
274 #define netwib_io_wait_rdwr(pio,pabstime,pevent) netwib_io_wait(pio,NETWIB_IO_WAYTYPE_RDWR,pabstime,pevent)
275 #define netwib_io_wait_supported(pio,pabstime,pevent) netwib_io_wait(pio,NETWIB_IO_WAYTYPE_SUPPORTED,pabstime,pevent)
276 
277 /*-------------------------------------------------------------*/
278 /* Explaining those values would be too complicated here. Please
279    refer to the defines using them (which are documented).
280 */
281 typedef enum {
282   /** values working on current io (they are not recursive) **/
283   NETWIB_IO_CTLTYPE_SUPPORT = 1,
284   NETWIB_IO_CTLTYPE_NUMUSERS,
285   NETWIB_IO_CTLTYPE_NUMUSERSINC,
286   /** values working on current io (if NETWIB_ERR_OK is returned) or
287       on next io (if NETWIB_ERR_PLEASETRYNEXT is returned) **/
288   NETWIB_IO_CTLTYPE_RES = 100,
289   NETWIB_IO_CTLTYPE_END,
290   /** values which are specific **/
291   /* file : 200 */
292   NETWIB_IO_CTLTYPE_FILE_SEEK_BEGIN = 200,
293   NETWIB_IO_CTLTYPE_FILE_SEEK_CURRENT,
294   NETWIB_IO_CTLTYPE_FILE_SEEK_END,
295   NETWIB_IO_CTLTYPE_FILE_TELL,
296   NETWIB_IO_CTLTYPE_FILE_TRUNCATE,
297   /* fd : 300 */
298   /* handle : 400 */
299   /* ipc : 500 */
300   NETWIB_IO_CTLTYPE_IPC_SIDEREAD = 500,
301   NETWIB_IO_CTLTYPE_IPC_SIDEWRITE,
302   NETWIB_IO_CTLTYPE_IPC_NOTUSED,
303   /* kbd : 600 */
304   NETWIB_IO_CTLTYPE_KBD_ECHO = 600,
305   NETWIB_IO_CTLTYPE_KBD_LINE,
306   NETWIB_IO_CTLTYPE_KBD_PURGE,
307   /* record : 700 */
308   /* sock : 800 */
309   NETWIB_IO_CTLTYPE_SOCK_IP4OPTS = 800,
310   NETWIB_IO_CTLTYPE_SOCK_IP6EXTS,
311   NETWIB_IO_CTLTYPE_SOCK_LOCAL,
312   NETWIB_IO_CTLTYPE_SOCK_REMOTE,
313   NETWIB_IO_CTLTYPE_SOCK_MULTICASTTTL,
314   NETWIB_IO_CTLTYPE_SOCK_SOCKTYPE,
315   /* sockv : 900 */
316   NETWIB_IO_CTLTYPE_SOCKV_ANSWERALIVE = 900,
317   /* sniff : 1000 */
318   NETWIB_IO_CTLTYPE_SNIFF_FILTER = 1000,
319   NETWIB_IO_CTLTYPE_SNIFF_DLT,
320   /* spoof : 1100 */
321   NETWIB_IO_CTLTYPE_SPOOF_DLT= 1100,
322   /** values which are specific to iousual.h **/
323   /* ioutil : 2000 */
324   NETWIB_IO_CTLTYPE_DATA_LINE_MSDOS = 2000,
325   NETWIB_IO_CTLTYPE_DATA_CHUNK_MINSIZE,
326   NETWIB_IO_CTLTYPE_DATA_CHUNK_MAXSIZE,
327   NETWIB_IO_CTLTYPE_DATA_FIXED_SIZE,
328   NETWIB_IO_CTLTYPE_DATA_TYPE,
329   NETWIB_IO_CTLTYPE_STORAGE_FLUSH,
330   /** values which are specific to users' utilities **/
331   /* user defined : start at 10000 */
332   NETWIB_IO_CTLTYPE_USER_BEGIN = NETWIB_ENUM_USER_BEGIN
333 } netwib_io_ctltype;
334 /* Those functions permit to set/get parameters (pointer and
335    integer) about a netwib_io. It should not be used directly,
336    but by the defines.
337    In function netwib_io_ctl_get, parameter p could be
338    a "netwib_ptr *pp" instead of "netwib_ptr p", but it
339    complicates things for nothing : a pointer can be
340    used for what we want. For example, its easier to use
341    ctl_get(..., &buf, &ui) instead of ("&&buf", &ui).
342 */
343 netwib_err netwib_io_ctl_set(netwib_io *pio,
344                              netwib_io_waytype way,
345                              netwib_io_ctltype ctltype,
346                              netwib_ptr p,
347                              netwib_uint32 ui);
348 netwib_err netwib_io_ctl_get(netwib_io *pio,
349                              netwib_io_waytype way,
350                              netwib_io_ctltype ctltype,
351                              netwib_ptr p,
352                              netwib_uint32 *pui);
353 
354 /*-------------------------------------------------------------*/
355 /***************************************************************
356  * This function permits to close an "io chain".               *
357  ***************************************************************/
358 
359 /*-------------------------------------------------------------*/
360 /* Name : netwib_io_close
361    Description :
362      Close a chain (links are closed only if nobody use them
363      anymore : numusers == 0).
364    Input parameter(s) :
365    Input/output parameter(s) :
366      **ppio : netwib_io to close
367    Output parameter(s) :
368    Normal return values :
369      NETWIB_ERR_OK : ok
370 */
371 netwib_err netwib_io_close(netwib_io **ppio);
372 
373 /*-------------------------------------------------------------*/
374 /***************************************************************
375  * Common control defines                                      *
376  ***************************************************************/
377 
378 /*-------------------------------------------------------------*/
379 typedef enum {
380   NETWIB_IO_RESTYPE_FILE = 1,
381   NETWIB_IO_RESTYPE_FD,
382   NETWIB_IO_RESTYPE_HANDLE,
383   NETWIB_IO_RESTYPE_IPC,
384   NETWIB_IO_RESTYPE_KBD,
385   NETWIB_IO_RESTYPE_SCREEN,
386   NETWIB_IO_RESTYPE_STREAM,
387   NETWIB_IO_RESTYPE_RECORD,
388   NETWIB_IO_RESTYPE_SOCK,
389   NETWIB_IO_RESTYPE_SOCKV,
390   NETWIB_IO_RESTYPE_SNIFF,
391   NETWIB_IO_RESTYPE_SPOOF,
392   NETWIB_IO_RESTYPE_NULL,
393   NETWIB_IO_RESTYPE_MEM,
394   NETWIB_IO_RESTYPE_TLV,
395   NETWIB_IO_RESTYPE_EXEC,
396   NETWIB_IO_RESTYPE_SHELLSERVER,
397   NETWIB_IO_RESTYPE_SHELLCLIENT,
398   NETWIB_IO_RESTYPE_USER_BEGIN = NETWIB_ENUM_USER_BEGIN
399 } netwib_io_restype;
400 /* Obtain the resource type of a netwib_io */
401 /* netwib_err f(netwib_io *pio, netwib_io_waytype way, netwib_io_restype *pres); */
402 #define netwib_io_ctl_get_res(pio,way,pres) netwib_io_ctl_get(pio,way,NETWIB_IO_CTLTYPE_RES,NULL,(netwib_uint32*)pres)
403 
404 /*-------------------------------------------------------------*/
405 /* indicate the end of data */
406 /* netwib_err f(netwib_io *pio, netwib_io_waytype way); */
407 #define netwib_io_ctl_set_end(pio,way) netwib_io_ctl_set(pio,way,NETWIB_IO_CTLTYPE_END,NULL,0)
408 #define netwib_io_ctl_set_end_write(pio) netwib_io_ctl_set_end(pio,NETWIB_IO_WAYTYPE_WRITE)
409 
410 
411 /*-------------------------------------------------------------*/
412 /***************************************************************
413  * Now, a big example ...                                      *
414  ***************************************************************/
415 
416 /*-------------------------------------------------------------*/
417 /*-------------------------------------------------------------*/
418 #if 0
419 /* Complete example :
420 
421   We create a module (named m) having one input (i1) and two
422   outputs (o1, o2) :
423 
424             ############# m #############
425             #                           #
426             #         ooooooooo         #  o1
427         i1  #  ,--.   o       o--------------->
428       >-------->l1 >--o HEART o   ,--.  #
429             #  `--'   o       o--->l2 >------->
430             #         ooooooooo   `--'  #  o2
431             #                           #
432             #############################
433 
434   The module contains 2 ios :
435    - l1 : reads line by line
436    - l2 : converts data to base64
437 
438   The heart of the module reads data from l1's output. If the
439   data starts by 'A', then it is sent to o1. Else, data goes
440   through l2.
441 
442   *** Usage 1 :
443    - i1 is plugged to a file through io l3
444    - o1 is plugged to file2
445    - o2 is plugged to file3 through io l4
446    - l3 reads data and duplicates it (read 'qa', output 'qqaa')
447    - l4 reads data, displays it to screen and sends to output
448                                                    ,-------
449                                #####       ,-------> file2
450       -------.      ,--.       #   >------'        `-------
451        file1  >----->l3 >------> m #     ,--.      ,-------
452       -------'      `--'       #   >----->l4 >-----> file3
453                                #####     `--'      `-------
454 
455   *** Usage 2 :
456    - i1 is plugged to socket soc1
457    - o1 is plugged to null (data is junked)
458    - o2 is plugged back to the same socket
459                                #####               ,------
460       ------.                  #   >---------------> null
461        soc1  >-----------------> m #               `------
462             <-------.          #   >----.
463       ------'        \         #####    |
464                       `-----------------'
465 
466   *** Usage 3 :
467    - i1 is plugged to a socket through io l3
468    - o1 is plugged to null (data is junked)
469    - o2 is plugged back to the same socket through io l4
470                                #####               ,------
471                     ,--.       #   >---------------> null
472       ------.    ,-->l3 >------> m #               `------
473        soc1  >--'   `--'       #   >----.
474             <--.    ,--.       #####    |
475       ------'   `--< l4<----------------'
476                     `--'
477 
478   *** Usage 4 :
479    - l5 is a bi-directional io converting string to uppercase
480    - l5 is plugged to socket soc1
481    - i1 is plugged to l5
482    - o1 is plugged to null (data is junked)
483    - o2 is plugged back to l5
484                                #####               ,------
485                                #   >---------------> null
486       ------.       ,--.    ,--> m #               `------
487        soc1  >------>l5 >--'   #   >----.
488             <------<   <--.    #####    |
489       ------'       `--'   `------------'
490 
491   *** Usage 5 :
492    - i1 is plugged to file1 through l5
493    - o1 is plugged to null (data is junked)
494    - o2 is plugged to file2 through l5
495                                #####               ,------
496      -------.                  #   >---------------> null
497       file1  >--.   ,--.    ,--> m #               `------
498      -------'    `-->l5 >--'   #   >----.
499      -------.   ,--<   <--.    #####    |
500       file2 <--'    `--'   `------------'
501      -------'
502 
503   *** Usage 6 :
504    - i1 is plugged to file1
505    - o1 are o2 are both plugged to file2
506                                #####
507       -------.                 #   >------------.  ,-------
508        file1  >----------------> m #             --> file2
509       -------'                 #   >------------'  `-------
510                                #####
511 
512   *** Usage 7 :
513    - m2 is a module similar to m except it has 2 inputs
514      and one output
515    - i1 is plugged to file1
516    - i2 is plugged to file1
517    - o1 is plugged to null (data is junked)
518    - o2 is plugged to file2
519                                #####
520       -------.   ,------------->   #               ,------
521        file1  >--              # m >---------------> null
522       -------'   `------------->   #               `------
523                                #####
524 
525 */
526 
527 /*-------------------------------------------------------------*/
528 /* l1 is netwib_io_init_read_line */
529 
530 /*-------------------------------------------------------------*/
531 /* l2 : converts data to base64 */
532 netwib_err l2_write(netwib_io *pio,
533                     netwib_constbuf *pbuf);
534 netwib_err l2_write(netwib_io *pio,
535                     netwib_constbuf *pbuf)
536 {
537   netwib_buf bufbase64;
538   netwib_io *pionext;
539   netwib_err ret;
540 
541   /* obtain the next io in the chain */
542   netwib_er(netwib_io_next_write(pio, &pionext));
543 
544   /* converts pbuf to base64 */
545   netwib_er(netwib_buf_init_mallocdefault(&bufbase64));
546   netwib_er(netwib_buf_encode(pbuf, NETWIB_ENCODETYPE_BASE64, &bufbase64));
547 
548   /* write data to the next io */
549   ret = netwib_io_write(pionext, &bufbase64);
550   netwib_er(netwib_buf_close(&bufbase64));
551 
552   return(ret);
553 }
554 
555 netwib_err l2_init(netwib_io **ppio);
556 netwib_err l2_init(netwib_io **ppio)
557 {
558   netwib_er(netwib_io_init(NETWIB_FALSE, NETWIB_TRUE, NULL,
559                            NULL/*read*/, &l2_write,
560                            NULL/*wait*/, NULL/*unread*/,
561                            NULL/*ctlset*/, NULL/*ctlget*/,
562                            NULL/*close*/, ppio));
563   return(NETWIB_ERR_OK);
564 }
565 
566 /*-------------------------------------------------------------*/
567 /* l3 reads data and duplicates it (read 'qa', output 'qqaa') */
568 netwib_err l3_dup(netwib_constbuf *pinbuf,
569                   netwib_buf *poutbuf);
570 netwib_err l3_dup(netwib_constbuf *pinbuf,
571                   netwib_buf *poutbuf)
572 {
573   netwib_data data;
574   netwib_uint32 datasize, i;
575 
576   data = netwib__buf_ref_data_ptr(pinbuf);
577   datasize = netwib__buf_ref_data_size(pinbuf);
578   for (i = 0; i < datasize; i++) {
579     netwib_er(netwib_buf_append_byte(data[i], poutbuf));
580     netwib_er(netwib_buf_append_byte(data[i], poutbuf));
581   }
582 
583   return(NETWIB_ERR_OK);
584 }
585 netwib_err l3_read(netwib_io *pio,
586                    netwib_buf *pbuf);
587 netwib_err l3_read(netwib_io *pio,
588                    netwib_buf *pbuf)
589 {
590   netwib_buf buf;
591   netwib_io *pionext;
592 
593   /* obtain the next io in the chain */
594   netwib_er(netwib_io_next_read(pio, &pionext));
595 
596   /* read data */
597   netwib_er(netwib_buf_init_mallocdefault(&buf));
598   netwib_er(netwib_io_read(pionext, &buf));
599 
600   /* duplicate buf */
601   netwib_er(l3_dup(&buf, pbuf));
602   netwib_er(netwib_buf_close(&buf));
603 
604   return(NETWIB_ERR_OK);
605 }
606 netwib_err l3_init(netwib_io **ppio);
607 netwib_err l3_init(netwib_io **ppio)
608 {
609   netwib_er(netwib_io_init(NETWIB_FALSE, NETWIB_TRUE, NULL,
610                            &l3_read/*read*/, NULL/*write*/,
611                            NULL/*wait*/, NULL/*unread*/,
612                            NULL/*ctlset*/, NULL/*ctlget*/,
613                            NULL/*close*/, ppio));
614 
615   return(NETWIB_ERR_OK);
616 }
617 
618 /*-------------------------------------------------------------*/
619 /* l4 reads data, displays it to screen and sends to output */
620 netwib_err l4_write(netwib_io *pio,
621                     netwib_constbuf *pbuf);
622 netwib_err l4_write(netwib_io *pio,
623                     netwib_constbuf *pbuf)
624 {
625   netwib_buf bufbase64;
626   netwib_io *pionext;
627   netwib_err ret;
628 
629   /* obtain the next io in the chain */
630   netwib_er(netwib_io_next_write(pio, &pionext));
631 
632   /* display it */
633   netwib_er(netwib_buf_display(pbuf, NETWIB_ENCODETYPE_DUMP));
634 
635   /* write data to the next io */
636   ret = netwib_io_write(pionext, pbuf);
637 
638   return(ret);
639 }
640 
641 netwib_err l4_init(netwib_io **ppio);
642 netwib_err l4_init(netwib_io **ppio)
643 {
644   netwib_er(netwib_io_init(NETWIB_FALSE, NETWIB_TRUE, NULL,
645                            NULL/*read*/, &l4_write,
646                            NULL/*wait*/, NULL/*unread*/,
647                            NULL/*ctlset*/, NULL/*ctlget*/,
648                            NULL/*close*/, ppio));
649 
650   return(NETWIB_ERR_OK);
651 }
652 
653 /*-------------------------------------------------------------*/
654 /* l5 convert data to uppercase */
655 netwib_err l5_up(netwib_constbuf *pinbuf,
656                  netwib_buf *poutbuf);
657 netwib_err l5_up(netwib_constbuf *pinbuf,
658                  netwib_buf *poutbuf)
659 {
660   netwib_data data;
661   netwib_uint32 datasize, i;
662   netwib_byte c;
663 
664   data = netwib__buf_ref_data_ptr(pinbuf);
665   datasize = netwib__buf_ref_data_size(pinbuf);
666   for (i = 0; i < datasize; i++) {
667     c = data[i];
668     netwib_c2_upper(c);
669     netwib_er(netwib_buf_append_byte(c, poutbuf));
670   }
671 
672   return(NETWIB_ERR_OK);
673 }
674 netwib_err l5_read(netwib_io *pio,
675                    netwib_buf *pbuf);
676 netwib_err l5_read(netwib_io *pio,
677                    netwib_buf *pbuf)
678 {
679   netwib_buf buf;
680   netwib_io *pionext;
681 
682   netwib_er(netwib_io_next_read(pio, &pionext));
683   netwib_er(netwib_buf_init_mallocdefault(&buf));
684   netwib_er(netwib_io_read(pionext, &buf));
685   netwib_er(l5_up(&buf, pbuf));
686   netwib_er(netwib_buf_close(&buf));
687 
688   return(NETWIB_ERR_OK);
689 }
690 netwib_err l5_write(netwib_io *pio,
691                     netwib_constbuf *pbuf);
692 netwib_err l5_write(netwib_io *pio,
693                     netwib_constbuf *pbuf)
694 {
695   netwib_buf buf;
696   netwib_io *pionext;
697   netwib_err ret;
698 
699   netwib_er(netwib_io_next_write(pio, &pionext));
700   netwib_er(netwib_buf_init_mallocdefault(&buf));
701   netwib_er(l5_up(pbuf, &buf));
702   ret = netwib_io_write(pionext, &buf);
703   netwib_er(netwib_buf_close(&buf));
704 
705   return(ret);
706 }
707 netwib_err l5_init(netwib_io **ppio);
708 netwib_err l5_init(netwib_io **ppio)
709 {
710   netwib_er(netwib_io_init(NETWIB_FALSE, NETWIB_TRUE, NULL,
711                            &l5_read, &l5_write,
712                            NULL/*wait*/, NULL/*unread*/,
713                            NULL/*ctlset*/, NULL/*ctlget*/,
714                            NULL/*close*/, ppio));
715 
716   return(NETWIB_ERR_OK);
717 }
718 
719 /*-------------------------------------------------------------*/
720 /* module m */
721 netwib_err m(netwib_io *pi1,
722              netwib_io *po1,
723              netwib_io *po2);
724 netwib_err m(netwib_io *pi1,
725              netwib_io *po1,
726              netwib_io *po2)
727 {
728   netwib_buf buf;
729   netwib_err ret;
730   netwib_io *pl1, *pl2;
731   netwib_data data;
732   netwib_uint32 datasize;
733 
734   /* create l1 */
735   netwib_er(netwib_io_init_line(&pl1));
736 
737   /* create l2 */
738   netwib_er(l2_init(&pl2));
739 
740   /* add l1 to i1 */
741   netwib_er(netwib_io_plug_read(pl1, pi1));
742 
743   /* add l2 to o2 */
744   netwib_er(netwib_io_plug_read(pl2, po2));
745 
746   /* main loop */
747   netwib_er(netwib_buf_init_mallocdefault(&buf));
748   while (NETWIB_TRUE) {
749     netwib__buf_reinit(&buf);
750     ret = netwib_io_read(pl1, &buf);
751     if (ret == NETWIB_ERR_DATAEND) {
752       ret = NETWIB_ERR_OK;
753       break;
754     } else if (ret != NETWIB_ERR_OK) {
755       break;
756     }
757     data = netwib__buf_ref_data_ptr(&buf);
758     datasize = netwib__buf_ref_data_size(&buf);
759     if (datasize && data[0] == 'A') {
760       ret = netwib_io_write(po1, &buf);
761     } else {
762       ret = netwib_io_write(pl2, &buf);
763     }
764     if (ret != NETWIB_ERR_OK) {
765       break;
766     }
767   }
768   netwib_er(netwib_buf_close(&buf));
769 
770   /* close only l1 and l2 (not the complete chain) */
771   netwib_er(netwib_io_close(&pl1));
772   netwib_er(netwib_io_close(&pl2));
773 
774   return(ret);
775 }
776 
777 /*-------------------------------------------------------------*/
778 /* usage 1 */
779 netwib_err usage1(void);
780 netwib_err usage1(void)
781 {
782   netwib_err ret;
783   netwib_buf filename;
784   netwib_io *pfile1, *pfile2, *pfile3, *pl3 , *pl4;
785 
786   /* open files */
787   netwib_er(netwib_buf_init_ext_string("file1", &filename));
788   netwib_er(netwib_io_init_file_read(&filename, &pfile1));
789   netwib_er(netwib_buf_init_ext_string("file2", &filename));
790   netwib_er(netwib_io_init_file_write(&filename, &pfile2));
791   netwib_er(netwib_buf_init_ext_string("file3", &filename));
792   netwib_er(netwib_io_init_file_write(&filename, &pfile3));
793 
794   /* initialize l3 and l4 */
795   netwib_er(l3_init(&pl3));
796   netwib_er(l4_init(&pl4));
797 
798   /* create chains */
799   netwib_er(netwib_io_plug_read(pl3, pfile1));
800   netwib_er(netwib_io_plug_write(pl4, pfile3));
801 
802   /* core loop */
803   ret = m(pl3, pfile2, pl4);
804 
805   /* close chains */
806   netwib_er(netwib_io_close(&pl3)); /* or close_read */
807   netwib_er(netwib_io_close(&pfile2)); /* or close_write */
808   netwib_er(netwib_io_close(&pl4)); /* or close_write */
809 
810   return(ret);
811 }
812 
813 /*-------------------------------------------------------------*/
814 /* usage 2 */
815 netwib_err usage2(void);
816 netwib_err usage2(void)
817 {
818   netwib_err ret;
819   netwib_io *psock, *pnull;
820   netwib_ip ipad;
821 
822   /* open socket */
823   netwib_er(netwib_ip_init_ip4(0x7F000001, &ipad));
824   netwib_er(netwib_io_init_sock_tcp_cli_easy(&ipad, 1234, &psock));
825 
826   /* open null */
827   netwib_er(netwib_io_init_null(&pnull));
828 
829   /* core loop */
830   ret = m(psock, pnull, psock);
831 
832   /* close chains */
833   netwib_er(netwib_io_close(&psock));
834   netwib_er(netwib_io_close(&pnull)); /* or close_write */
835 
836   return(ret);
837 }
838 
839 /*-------------------------------------------------------------*/
840 /* usage 3 */
841 netwib_err usage3(void);
842 netwib_err usage3(void)
843 {
844   netwib_err ret;
845   netwib_io *psock, *pnull, *pl3 , *pl4;
846   netwib_ip ipad;
847 
848   /* open socket */
849   netwib_er(netwib_ip_init_ip4(0x7F000001, &ipad));
850   netwib_er(netwib_io_init_sock_tcp_cli_easy(&ipad, 1234, &psock));
851 
852   /* open null */
853   netwib_er(netwib_io_init_null(&pnull));
854 
855   /* initialize l3 and l4 */
856   netwib_er(l3_init(&pl3));
857   netwib_er(l4_init(&pl4));
858 
859   /* create chains */
860   netwib_er(netwib_io_plug_read(pl3, psock));
861   netwib_er(netwib_io_plug_write(pl4, psock));
862 
863   /* core loop */
864   ret = m(pl3, pnull, pl4);
865 
866   /* close chains */
867   netwib_er(netwib_io_close(&pl3)); /* or close_read */
868   netwib_er(netwib_io_close(&pnull)); /* or close_write */
869   netwib_er(netwib_io_close(&pl4)); /* or close_write */
870 
871   return(ret);
872 }
873 
874 /*-------------------------------------------------------------*/
875 /* usage 4 */
876 netwib_err usage4(void);
877 netwib_err usage4(void)
878 {
879   netwib_err ret;
880   netwib_io *psock, *pnull, *pl5;
881   netwib_ip ipad;
882 
883   /* open socket */
884   netwib_er(netwib_ip_init_ip4(0x7F000001, &ipad));
885   netwib_er(netwib_io_init_sock_tcp_cli_easy(&ipad, 1234, &psock));
886 
887   /* open null */
888   netwib_er(netwib_io_init_null(&pnull));
889 
890   /* initialize l5 */
891   netwib_er(l5_init(&pl5));
892 
893   /* create chains */
894   netwib_er(netwib_io_plug_read(pl5, psock));
895   netwib_er(netwib_io_plug_write(pl5, psock));
896 
897   /* core loop */
898   ret = m(pl5, pnull, pl5);
899 
900   /* close chains */
901   netwib_er(netwib_io_close(&pl5));
902   netwib_er(netwib_io_close(&pnull)); /* or close_write */
903 
904   return(ret);
905 }
906 
907 /*-------------------------------------------------------------*/
908 /* usage 5 */
909 netwib_err usage5(void);
910 netwib_err usage5(void)
911 {
912   netwib_err ret;
913   netwib_buf filename;
914   netwib_io *pfile1, *pfile2, *pnull, *pl5;
915 
916   /* open files */
917   netwib_er(netwib_buf_init_ext_string("file1", &filename));
918   netwib_er(netwib_io_init_file_read(&filename, &pfile1));
919   netwib_er(netwib_buf_init_ext_string("file2", &filename));
920   netwib_er(netwib_io_init_file_write(&filename, &pfile2));
921 
922   /* open null */
923   netwib_er(netwib_io_init_null(&pnull));
924 
925   /* initialize l5 */
926   netwib_er(l5_init(&pl5));
927 
928   /* create chains */
929   netwib_er(netwib_io_plug_read(pl5, pfile1));
930   netwib_er(netwib_io_plug_write(pl5, pfile2));
931 
932   /* core loop */
933   ret = m(pl5, pnull, pl5);
934 
935   /* close chains */
936   netwib_er(netwib_io_close(&pl5));
937   netwib_er(netwib_io_close(&pnull)); /* or close_write */
938 
939   return(ret);
940 }
941 
942 /*-------------------------------------------------------------*/
943 /* usage 6 */
944 netwib_err usage6(void);
945 netwib_err usage6(void)
946 {
947   netwib_err ret;
948   netwib_buf filename;
949   netwib_io *pfile1, *pfile2;
950 
951   /* open files */
952   netwib_er(netwib_buf_init_ext_string("file1", &filename));
953   netwib_er(netwib_io_init_file_read(&filename, &pfile1));
954   netwib_er(netwib_buf_init_ext_string("file2", &filename));
955   netwib_er(netwib_io_init_file_write(&filename, &pfile2));
956 
957   /* core loop */
958   ret = m(pfile1, pfile2, pfile2);
959 
960   /* close chains */
961   netwib_er(netwib_io_close(&pfile1));
962   netwib_er(netwib_io_close(&pfile2));
963 
964   return(ret);
965 }
966 
967 /*-------------------------------------------------------------*/
968 /* usage 7 */
969 netwib_err usage7(void);
970 netwib_err m2(netwib_io *pi1,
971               netwib_io *pi2,
972               netwib_io *po1);
973 netwib_err usage7(void)
974 {
975   netwib_err ret;
976   netwib_buf filename;
977   netwib_io *pfile1, *pnull;
978 
979   /* open files */
980   netwib_er(netwib_buf_init_ext_string("file1", &filename));
981   netwib_er(netwib_io_init_file_read(&filename, &pfile1));
982 
983   /* open null */
984   netwib_er(netwib_io_init_null(&pnull));
985 
986   /* core loop */
987   ret = m2(pfile1, pfile1, pnull);
988 
989   /* close chains */
990   netwib_er(netwib_io_close(&pfile1));
991   netwib_er(netwib_io_close(&pnull));
992 
993   return(ret);
994 }
995 #endif
996