stream: add a stream class abstracting BSD sockets
[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 "stream.h"
17
18 #include <errno.h>
19 #include <unistd.h>
20
21 typedef struct private_stream_t private_stream_t;
22
23 /**
24 * Private data of an stream_t object.
25 */
26 struct private_stream_t {
27
28 /**
29 * Public stream_t interface.
30 */
31 stream_t public;
32
33 /**
34 * Underlying socket
35 */
36 int fd;
37 };
38
39 METHOD(stream_t, read_, ssize_t,
40 private_stream_t *this, void *buf, size_t len, bool block)
41 {
42 while (TRUE)
43 {
44 ssize_t ret;
45
46 if (block)
47 {
48 ret = read(this->fd, buf, len);
49 }
50 else
51 {
52 ret = recv(this->fd, buf, len, MSG_DONTWAIT);
53 if (ret == -1 && errno == EAGAIN)
54 {
55 /* unify EGAIN and EWOULDBLOCK */
56 errno = EWOULDBLOCK;
57 }
58 }
59 if (ret == -1 && errno == EINTR)
60 { /* interrupted, try again */
61 continue;
62 }
63 return ret;
64 }
65 }
66
67 METHOD(stream_t, write_, ssize_t,
68 private_stream_t *this, void *buf, size_t len, bool block)
69 {
70 ssize_t ret;
71
72 while (TRUE)
73 {
74 if (block)
75 {
76 ret = write(this->fd, buf, len);
77 }
78 else
79 {
80 ret = send(this->fd, buf, len, MSG_DONTWAIT);
81 if (ret == -1 && errno == EAGAIN)
82 {
83 /* unify EGAIN and EWOULDBLOCK */
84 errno = EWOULDBLOCK;
85 }
86 }
87 if (ret == -1 && errno == EINTR)
88 { /* interrupted, try again */
89 continue;
90 }
91 return ret;
92 }
93 }
94
95 METHOD(stream_t, destroy, void,
96 private_stream_t *this)
97 {
98 close(this->fd);
99 free(this);
100 }
101
102 /**
103 * See header
104 */
105 stream_t *stream_create_from_fd(int fd)
106 {
107 private_stream_t *this;
108
109 INIT(this,
110 .public = {
111 .read = _read_,
112 .write = _write_,
113 .destroy = _destroy,
114 },
115 .fd = fd,
116 );
117
118 return &this->public;
119 }