Annotation of embedaddon/strongswan/src/libstrongswan/networking/streams/stream.c, revision 1.1.1.1
1.1 misho 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: #include "stream.h"
21:
22: typedef struct private_stream_t private_stream_t;
23:
24: /**
25: * Private data of an stream_t object.
26: */
27: struct private_stream_t {
28:
29: /**
30: * Public stream_t interface.
31: */
32: stream_t public;
33:
34: /**
35: * Underlying socket
36: */
37: int fd;
38:
39: /**
40: * Callback if data is ready to read
41: */
42: stream_cb_t read_cb;
43:
44: /**
45: * Data for read-ready callback
46: */
47: void *read_data;
48:
49: /**
50: * Callback if write is non-blocking
51: */
52: stream_cb_t write_cb;
53:
54: /**
55: * Data for write-ready callback
56: */
57: void *write_data;
58: };
59:
60: METHOD(stream_t, read_, ssize_t,
61: private_stream_t *this, void *buf, size_t len, bool block)
62: {
63: while (TRUE)
64: {
65: ssize_t ret;
66:
67: if (block)
68: {
69: ret = recv(this->fd, buf, len, 0);
70: }
71: else
72: {
73: ret = recv(this->fd, buf, len, MSG_DONTWAIT);
74: if (ret == -1 && errno == EAGAIN)
75: {
76: /* unify EGAIN and EWOULDBLOCK */
77: errno = EWOULDBLOCK;
78: }
79: }
80: if (ret == -1 && errno == EINTR)
81: { /* interrupted, try again */
82: continue;
83: }
84: return ret;
85: }
86: }
87:
88: METHOD(stream_t, read_all, bool,
89: private_stream_t *this, void *buf, size_t len)
90: {
91: ssize_t ret;
92:
93: while (len)
94: {
95: ret = read_(this, buf, len, TRUE);
96: if (ret < 0)
97: {
98: return FALSE;
99: }
100: if (ret == 0)
101: {
102: errno = ECONNRESET;
103: return FALSE;
104: }
105: len -= ret;
106: buf += ret;
107: }
108: return TRUE;
109: }
110:
111: METHOD(stream_t, write_, ssize_t,
112: private_stream_t *this, void *buf, size_t len, bool block)
113: {
114: ssize_t ret;
115:
116: while (TRUE)
117: {
118: if (block)
119: {
120: ret = send(this->fd, buf, len, 0);
121: }
122: else
123: {
124: ret = send(this->fd, buf, len, MSG_DONTWAIT);
125: if (ret == -1 && errno == EAGAIN)
126: {
127: /* unify EGAIN and EWOULDBLOCK */
128: errno = EWOULDBLOCK;
129: }
130: }
131: if (ret == -1 && errno == EINTR)
132: { /* interrupted, try again */
133: continue;
134: }
135: return ret;
136: }
137: }
138:
139: METHOD(stream_t, write_all, bool,
140: private_stream_t *this, void *buf, size_t len)
141: {
142: ssize_t ret;
143:
144: while (len)
145: {
146: ret = write_(this, buf, len, TRUE);
147: if (ret < 0)
148: {
149: return FALSE;
150: }
151: if (ret == 0)
152: {
153: errno = ECONNRESET;
154: return FALSE;
155: }
156: len -= ret;
157: buf += ret;
158: }
159: return TRUE;
160: }
161:
162: /**
163: * Watcher callback
164: */
165: static bool watch(private_stream_t *this, int fd, watcher_event_t event)
166: {
167: bool keep = FALSE;
168: stream_cb_t cb;
169:
170: switch (event)
171: {
172: case WATCHER_READ:
173: cb = this->read_cb;
174: this->read_cb = NULL;
175: keep = cb(this->read_data, &this->public);
176: if (keep)
177: {
178: this->read_cb = cb;
179: }
180: break;
181: case WATCHER_WRITE:
182: cb = this->write_cb;
183: this->write_cb = NULL;
184: keep = cb(this->write_data, &this->public);
185: if (keep)
186: {
187: this->write_cb = cb;
188: }
189: break;
190: case WATCHER_EXCEPT:
191: break;
192: }
193: return keep;
194: }
195:
196: /**
197: * Register watcher for stream callbacks
198: */
199: static void add_watcher(private_stream_t *this)
200: {
201: watcher_event_t events = 0;
202:
203: if (this->read_cb)
204: {
205: events |= WATCHER_READ;
206: }
207: if (this->write_cb)
208: {
209: events |= WATCHER_WRITE;
210: }
211: if (events)
212: {
213: lib->watcher->add(lib->watcher, this->fd, events,
214: (watcher_cb_t)watch, this);
215: }
216: }
217:
218: METHOD(stream_t, on_read, void,
219: private_stream_t *this, stream_cb_t cb, void *data)
220: {
221: lib->watcher->remove(lib->watcher, this->fd);
222:
223: this->read_cb = cb;
224: this->read_data = data;
225:
226: add_watcher(this);
227: }
228:
229: METHOD(stream_t, on_write, void,
230: private_stream_t *this, stream_cb_t cb, void *data)
231: {
232: lib->watcher->remove(lib->watcher, this->fd);
233:
234: this->write_cb = cb;
235: this->write_data = data;
236:
237: add_watcher(this);
238: }
239:
240: METHOD(stream_t, get_file, FILE*,
241: private_stream_t *this)
242: {
243: FILE *file;
244: int fd;
245:
246: /* fclose() closes the FD passed to fdopen(), so dup() it */
247: fd = dup(this->fd);
248: if (fd == -1)
249: {
250: return NULL;
251: }
252: file = fdopen(fd, "w+");
253: if (!file)
254: {
255: close(fd);
256: }
257: return file;
258: }
259:
260: METHOD(stream_t, destroy, void,
261: private_stream_t *this)
262: {
263: lib->watcher->remove(lib->watcher, this->fd);
264: close(this->fd);
265: free(this);
266: }
267:
268: /**
269: * See header
270: */
271: stream_t *stream_create_from_fd(int fd)
272: {
273: private_stream_t *this;
274:
275: INIT(this,
276: .public = {
277: .read = _read_,
278: .read_all = _read_all,
279: .on_read = _on_read,
280: .write = _write_,
281: .write_all = _write_all,
282: .on_write = _on_write,
283: .get_file = _get_file,
284: .destroy = _destroy,
285: },
286: .fd = fd,
287: );
288:
289: return &this->public;
290: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>