stream: add printf()-style covenience functions
[strongswan.git] / src / libstrongswan / networking / streams / stream.c
1 /*
2 * Copyright (C) 2013 Martin Willi
3 * Copyright (C) 2013 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include <library.h>
17 #include <errno.h>
18 #include <unistd.h>
19
20 typedef struct private_stream_t private_stream_t;
21
22 /**
23 * Private data of an stream_t object.
24 */
25 struct private_stream_t {
26
27 /**
28 * Public stream_t interface.
29 */
30 stream_t public;
31
32 /**
33 * Underlying socket
34 */
35 int fd;
36
37 /**
38 * FILE* for convenience functions, or NULL
39 */
40 FILE *file;
41 };
42
43 METHOD(stream_t, read_, ssize_t,
44 private_stream_t *this, void *buf, size_t len, bool block)
45 {
46 while (TRUE)
47 {
48 ssize_t ret;
49
50 if (block)
51 {
52 ret = read(this->fd, buf, len);
53 }
54 else
55 {
56 ret = recv(this->fd, buf, len, MSG_DONTWAIT);
57 if (ret == -1 && errno == EAGAIN)
58 {
59 /* unify EGAIN and EWOULDBLOCK */
60 errno = EWOULDBLOCK;
61 }
62 }
63 if (ret == -1 && errno == EINTR)
64 { /* interrupted, try again */
65 continue;
66 }
67 return ret;
68 }
69 }
70
71 METHOD(stream_t, write_, ssize_t,
72 private_stream_t *this, void *buf, size_t len, bool block)
73 {
74 ssize_t ret;
75
76 while (TRUE)
77 {
78 if (block)
79 {
80 ret = write(this->fd, buf, len);
81 }
82 else
83 {
84 ret = send(this->fd, buf, len, MSG_DONTWAIT);
85 if (ret == -1 && errno == EAGAIN)
86 {
87 /* unify EGAIN and EWOULDBLOCK */
88 errno = EWOULDBLOCK;
89 }
90 }
91 if (ret == -1 && errno == EINTR)
92 { /* interrupted, try again */
93 continue;
94 }
95 return ret;
96 }
97 }
98
99 METHOD(stream_t, vprint, int,
100 private_stream_t *this, char *format, va_list ap)
101 {
102 if (!this->file)
103 {
104 this->file = fdopen(this->fd, "w+");
105 if (!this->file)
106 {
107 return -1;
108 }
109 }
110 return vfprintf(this->file, format, ap);
111 }
112
113 METHOD(stream_t, print, int,
114 private_stream_t *this, char *format, ...)
115 {
116 va_list ap;
117 int ret;
118
119 va_start(ap, format);
120 ret = vprint(this, format, ap);
121 va_end(ap);
122
123 return ret;
124 }
125
126 METHOD(stream_t, destroy, void,
127 private_stream_t *this)
128 {
129 if (this->file)
130 {
131 fclose(this->file);
132 }
133 else
134 {
135 close(this->fd);
136 }
137 free(this);
138 }
139
140 /**
141 * See header
142 */
143 stream_t *stream_create_from_fd(int fd)
144 {
145 private_stream_t *this;
146
147 INIT(this,
148 .public = {
149 .read = _read_,
150 .write = _write_,
151 .print = _print,
152 .vprint = _vprint,
153 .destroy = _destroy,
154 },
155 .fd = fd,
156 );
157
158 return &this->public;
159 }