source: sources/src/ioPipe.cc @ 1464:3f6711617be1

Revision 1464:3f6711617be1, 17.2 KB checked in by niam, 22 months ago (diff)

{issue #58[resolved]} support for non-c++ exceptions

Line 
1/***************************************************************************
2 *            ioPipe.cc
3 *
4 *  Tue Jul 1 2008
5 *  Copyright  2008  Dmytro Milinevskyy
6 *  milinevskyy@gmail.com
7 ****************************************************************************/
8
9/*
10 *  This program is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU Lesser General Public License version 2.1 as published by
12 *  the Free Software Foundation;
13 *
14 *  This program is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU Library General Public License for more details.
18 *
19 *  You should have received a copy of the GNU Lesser General Public License
20 *  along with this program; if not, write to the Free Software
21 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24/**
25 * vim indentation settings
26 * set tabstop=4
27 * set shiftwidth=4
28 */
29
30#include <libdodo/directives.h>
31
32#include <stdio.h>
33#include <sys/socket.h>
34#include <arpa/inet.h>
35#include <netinet/in.h>
36#include <fcntl.h>
37#include <errno.h>
38#include <string.h>
39#include <unistd.h>
40
41#include "ioFile.inline"
42
43#include <libdodo/ioPipe.h>
44#include <libdodo/ioPipeEx.h>
45#include <libdodo/ioChannel.h>
46#include <libdodo/ioStreamChannel.h>
47#include <libdodo/ioNetworkConnection.h>
48#include <libdodo/pcSyncStack.h>
49
50using namespace dodo;
51
52io::pipe::pipe(bool  open,
53               short protection) : stream::channel(protection),
54                                   in(new io::__file__),
55                                   out(new io::__file__),
56                                   blocked(true)
57{
58#ifndef IO_WO_XEXEC
59    collectedData.setExecObject(xexec::OBJECT_IOPIPE);
60#endif
61
62    if (open) {
63        int pipefd[2];
64
65        if (::pipe(pipefd) != 0)
66            dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_PIPE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
67
68        in->file = fdopen(pipefd[0], "r");
69        if (in->file == NULL)
70            dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_PIPE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
71
72        out->file = fdopen(pipefd[1], "w");
73        if (out->file == NULL)
74            dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_PIPE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
75    }
76}
77
78//-------------------------------------------------------------------
79
80io::pipe::pipe(const pipe &fd) : stream::channel(protection),
81                                 in(new io::__file__),
82                                 out(new io::__file__),
83                                 blocked(fd.blocked)
84{
85#ifndef IO_WO_XEXEC
86    collectedData.setExecObject(xexec::OBJECT_IOPIPE);
87#endif
88
89    bs = fd.bs;
90
91    if (fd.in->file != NULL && fd.out->file != NULL) {
92        int oldDesc, newDesc;
93
94        oldDesc = fileno(fd.in->file);
95        if (oldDesc == -1)
96            dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_PIPE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
97
98        newDesc = dup(oldDesc);
99        if (newDesc == -1)
100            dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_PIPE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
101
102        in->file = fdopen(newDesc, "r");
103        if (in->file == NULL)
104            dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_PIPE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
105
106        oldDesc = fileno(fd.out->file);
107        if (oldDesc == -1)
108            dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_PIPE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
109
110        newDesc = dup(oldDesc);
111        if (newDesc == -1)
112            dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_PIPE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
113
114        out->file = fdopen(newDesc, "w");
115        if (out->file == NULL)
116            dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_PIPE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
117    }
118}
119
120//-------------------------------------------------------------------
121
122io::pipe::~pipe()
123{
124    if (in->file != NULL)
125        fclose(in->file);
126
127    if (out->file != NULL)
128        fclose(out->file);
129
130    delete in;
131    delete out;
132}
133
134//-------------------------------------------------------------------
135
136void
137io::pipe::clone(const pipe &fd)
138{
139    pc::sync::stack pg(keeper);
140
141    if (in->file != NULL) {
142        if (fclose(in->file) != 0)
143            dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_CLONE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
144
145        in->file = NULL;
146    }
147
148    if (out->file != NULL) {
149        if (fclose(out->file) != 0)
150            dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_CLONE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
151
152        out->file = NULL;
153    }
154
155    blocked = fd.blocked;
156    bs = fd.bs;
157
158    if (fd.in->file != NULL && fd.out->file != NULL) {
159        int oldDesc, newDesc;
160
161        oldDesc = fileno(fd.in->file);
162        if (oldDesc == -1)
163            dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_CLONE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
164
165        newDesc = dup(oldDesc);
166        if (newDesc == -1)
167            dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_CLONE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
168
169        in->file = fdopen(newDesc, "r");
170        if (in->file == NULL)
171            dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_CLONE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
172
173        oldDesc = fileno(fd.out->file);
174        if (oldDesc == -1)
175            dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_CLONE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
176
177        newDesc = dup(oldDesc);
178        if (newDesc == -1)
179            dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_CLONE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
180
181        out->file = fdopen(newDesc, "w");
182        if (out->file == NULL)
183            dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_CLONE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
184    }
185}
186
187//-------------------------------------------------------------------
188
189int
190io::pipe::inDescriptor() const
191{
192    pc::sync::stack pg(keeper);
193
194    if (in->file == NULL)
195        dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_INDESCRIPTOR, exception::ERRNO_LIBDODO, PIPEEX_PIPENOTOPENED, IOPIPEEX_NOTOPENED_STR, __LINE__, __FILE__);
196
197    return fileno(in->file);
198}
199
200//-------------------------------------------------------------------
201
202int
203io::pipe::outDescriptor() const
204{
205    pc::sync::stack pg(keeper);
206
207    if (out->file == NULL)
208        dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_OUTDESCRIPTOR, exception::ERRNO_LIBDODO, PIPEEX_PIPENOTOPENED, IOPIPEEX_NOTOPENED_STR, __LINE__, __FILE__);
209
210    return fileno(out->file);
211}
212
213//-------------------------------------------------------------------
214
215void
216io::pipe::close()
217{
218    pc::sync::stack pg(keeper);
219
220#ifndef IO_WO_XEXEC
221    performPreExec(OPERATION_CLOSE);
222#endif
223
224    if (in->file != NULL) {
225        if (fclose(in->file) != 0)
226            dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_CLOSE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
227
228        in->file = NULL;
229    }
230
231    if (out->file != NULL) {
232        if (fclose(out->file) != 0)
233            dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_CLOSE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
234
235        out->file = NULL;
236    }
237
238#ifndef IO_WO_XEXEC
239    performPostExec(OPERATION_CLOSE);
240#endif
241}
242
243//-------------------------------------------------------------------
244
245void
246io::pipe::open()
247{
248    pc::sync::stack pg(keeper);
249
250#ifndef IO_WO_XEXEC
251    performPreExec(OPERATION_OPEN);
252#endif
253
254    if (in->file != NULL) {
255        if (fclose(in->file) != 0)
256            dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_OPEN, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
257
258        in->file = NULL;
259    }
260
261    if (out->file != NULL) {
262        if (fclose(out->file) != 0)
263            dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_OPEN, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
264
265        out->file = NULL;
266    }
267
268    int pipefd[2];
269
270    if (::pipe(pipefd) != 0)
271        dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_OPEN, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
272
273    in->file = fdopen(pipefd[0], "r");
274    if (in->file == NULL)
275        dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_OPEN, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
276
277    out->file = fdopen(pipefd[1], "w");
278    if (out->file == NULL)
279        dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_OPEN, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
280
281#ifndef IO_WO_XEXEC
282    performPostExec(OPERATION_OPEN);
283#endif
284}
285
286//-------------------------------------------------------------------
287
288unsigned long
289io::pipe::_read(char * const data) const
290{
291    if (in->file == NULL)
292        dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX__READ, exception::ERRNO_LIBDODO, PIPEEX_PIPENOTOPENED, IOPIPEEX_NOTOPENED_STR, __LINE__, __FILE__);
293
294    char *s = data;
295
296    unsigned long batch = bs, n;
297
298    while (batch > 0) {
299        while (true) {
300            if ((n = fread(s, 1, batch, in->file)) == 0) {
301                if (feof(in->file) != 0 || errno == EAGAIN)
302                    return bs - batch;
303
304                if (errno == EINTR)
305                    continue;
306
307                if (ferror(in->file) != 0)
308                    dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX__READ, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
309            }
310
311            break;
312        }
313
314        batch -= n;
315        s += n;
316    }
317
318    return bs;
319}
320
321//-------------------------------------------------------------------
322
323unsigned long
324io::pipe::_write(const char *const data) const
325{
326    if (out->file == NULL)
327        dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX__WRITE, exception::ERRNO_LIBDODO, PIPEEX_PIPENOTOPENED, IOPIPEEX_NOTOPENED_STR, __LINE__, __FILE__);
328
329    const char *s = data;
330
331    unsigned long batch = bs, n;
332
333    while (batch != 0) {
334        while (true) {
335            if ((n = fwrite(s, 1, batch, out->file)) == 0) {
336                if (errno == EINTR)
337                    continue;
338
339                if (errno == EAGAIN)
340                    return bs - batch;
341
342                if (ferror(out->file) != 0)
343                    dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX__WRITE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
344            }
345
346            break;
347        }
348
349        batch -= n;
350        s += n;
351    }
352
353    return bs;
354}
355
356//-------------------------------------------------------------------
357
358void
359io::pipe::flush() const
360{
361    pc::sync::stack pg(keeper);
362
363    if (out->file == NULL)
364        dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_FLUSH, exception::ERRNO_LIBDODO, PIPEEX_PIPENOTOPENED, IOPIPEEX_NOTOPENED_STR, __LINE__, __FILE__);
365
366    if (fflush(out->file) != 0)
367        dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_FLUSH, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
368}
369
370//-------------------------------------------------------------------
371
372io::network::exchange::__peer__
373io::pipe::peer()
374{
375    pc::sync::stack pg(keeper);
376
377    if (in->file == NULL)
378        dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_PEERINFO, exception::ERRNO_LIBDODO, PIPEEX_PIPENOTOPENED, IOPIPEEX_NOTOPENED_STR, __LINE__, __FILE__);
379
380    network::exchange::__peer__ info;
381
382    struct sockaddr sa;
383
384    socklen_t len = sizeof(sockaddr_in6);
385
386    int desc = fileno(in->file);
387    if (desc == -1)
388        dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_PEERINFO, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
389
390    if (::getpeername(desc, &sa, &len) == 1) {
391        if (errno != ENOTSOCK)
392            dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_PEERINFO, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
393        else
394            return info;
395    }
396
397    switch (len) {
398        case sizeof(sockaddr_in):
399
400        {
401            char temp[15];
402            sockaddr_in *sa4;
403            sa4 = (sockaddr_in *)&sa;
404            if (inet_ntop(AF_INET, &(sa4->sin_addr), temp, 15) != NULL)
405                info.host = temp;
406            info.port = ntohs(sa4->sin_port);
407
408            return info;
409        }
410
411        case sizeof(sockaddr_in6):
412
413        {
414            char temp[INET6_ADDRSTRLEN];
415            sockaddr_in6 *sa6;
416            sa6 = (sockaddr_in6 *)&sa6;
417            if (inet_ntop(AF_INET6, &(sa6->sin6_addr), temp, INET6_ADDRSTRLEN) != NULL)
418                info.host = temp;
419            info.port = ntohs(sa6->sin6_port);
420
421            return info;
422        }
423
424        default:
425
426            return info;
427    }
428}
429
430//-------------------------------------------------------------------
431
432bool
433io::pipe::isBlocked()
434{
435    pc::sync::stack pg(keeper);
436
437    return blocked;
438}
439
440//-------------------------------------------------------------------
441
442void
443io::pipe::block(bool flag)
444{
445    pc::sync::stack pg(keeper);
446
447    if (in->file == NULL && out->file == NULL)
448        dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_BLOCK, exception::ERRNO_LIBDODO, PIPEEX_PIPENOTOPENED, IOPIPEEX_NOTOPENED_STR, __LINE__, __FILE__);
449
450    if (blocked == flag)
451        return;
452
453    int blockFlag;
454    int desc;
455
456    desc = fileno(in->file);
457    if (desc == -1)
458        dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_BLOCK, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
459
460    blockFlag = fcntl(desc, F_GETFL);
461    if (blockFlag == -1)
462        dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_BLOCK, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
463
464    if (flag)
465        blockFlag &= ~O_NONBLOCK;
466    else
467        blockFlag |= O_NONBLOCK;
468
469    if (fcntl(desc, F_SETFL, blockFlag) == -1)
470        dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_BLOCK, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
471
472    desc = fileno(out->file);
473    if (desc == -1)
474        dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_BLOCK, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
475
476    blockFlag = fcntl(desc, F_GETFL);
477    if (blockFlag == -1)
478        dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_BLOCK, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
479
480    if (flag)
481        blockFlag &= ~O_NONBLOCK;
482    else
483        blockFlag |= O_NONBLOCK;
484
485    if (fcntl(desc, F_SETFL, blockFlag) == -1)
486        dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX_BLOCK, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
487
488    blocked = flag;
489}
490
491//-------------------------------------------------------------------
492
493unsigned long
494io::pipe::_readString(char * const data) const
495{
496    if (in->file == NULL)
497        dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX__READSTRING, exception::ERRNO_LIBDODO, PIPEEX_PIPENOTOPENED, IOPIPEEX_NOTOPENED_STR, __LINE__, __FILE__);
498
499    unsigned long readSize = bs + 1;
500
501    while (true) {
502        if (fgets(data, readSize, in->file) == NULL) {
503            if (errno == EINTR)
504                continue;
505
506            if (errno == EAGAIN)
507                return 0;
508
509            if (ferror(in->file) != 0)
510                dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX__READSTRING, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
511        }
512
513        break;
514    }
515
516    return strlen(data);
517}
518
519//-------------------------------------------------------------------
520
521unsigned long
522io::pipe::_writeString(const char * const data) const
523{
524    if (out->file == NULL)
525        dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX__READSTRING, exception::ERRNO_LIBDODO, PIPEEX_PIPENOTOPENED, IOPIPEEX_NOTOPENED_STR, __LINE__, __FILE__);
526
527    unsigned long _bs = bs;
528    unsigned long written;
529
530    dodo_try {
531        bs = strnlen(data, bs);
532
533        written = _write(data);
534
535        if (data[bs - 1] != '\n') {
536            while (true) {
537                if (fputc('\n', out->file) == EOF) {
538                    if (errno == EINTR)
539                        continue;
540
541                    if (errno == EAGAIN)
542                        break;
543
544                    if (ferror(out->file) != 0)
545                        dodo_throw exception::basic(exception::MODULE_IOPIPE, PIPEEX__WRITESTRING, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
546                }
547
548                break;
549            }
550        }
551
552        bs = _bs;
553    } dodo_catch (exception::basic *e UNUSED) {
554        bs = _bs;
555
556        dodo_rethrow;
557    }
558
559    return written;
560}
561
562//-------------------------------------------------------------------
563
Note: See TracBrowser for help on using the repository browser.