avoid installing internal header files
[project/ustream-ssl.git] / ustream-ssl.c
1 /*
2 * ustream-ssl - library for SSL over ustream
3 *
4 * Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <errno.h>
20 #include <libubox/ustream.h>
21
22 #include "ustream-ssl.h"
23 #include "ustream-internal.h"
24
25 static void ustream_ssl_error_cb(struct uloop_timeout *t)
26 {
27 struct ustream_ssl *us = container_of(t, struct ustream_ssl, error_timer);
28 static char buffer[128];
29 int error = us->error;
30
31 if (us->notify_error)
32 us->notify_error(us, error, __ustream_ssl_strerror(us->error, buffer, sizeof(buffer)));
33 }
34
35 static void ustream_ssl_check_conn(struct ustream_ssl *us)
36 {
37 if (us->connected || us->error)
38 return;
39
40 if (__ustream_ssl_connect(us) == U_SSL_OK) {
41 us->connected = true;
42 if (us->notify_connected)
43 us->notify_connected(us);
44 }
45 }
46
47 static bool __ustream_ssl_poll(struct ustream *s)
48 {
49 struct ustream_ssl *us = container_of(s->next, struct ustream_ssl, stream);
50 char *buf;
51 int len, ret;
52 bool more = false;
53
54 ustream_ssl_check_conn(us);
55 if (!us->connected || us->error)
56 return false;
57
58 do {
59 buf = ustream_reserve(&us->stream, 1, &len);
60 if (!len)
61 break;
62
63 ret = __ustream_ssl_read(us, buf, len);
64 switch (ret) {
65 case U_SSL_PENDING:
66 return more;
67 case U_SSL_ERROR:
68 return false;
69 case 0:
70 us->stream.eof = true;
71 ustream_state_change(&us->stream);
72 return false;
73 default:
74 ustream_fill_read(&us->stream, ret);
75 more = true;
76 continue;
77 }
78 } while (1);
79
80 return more;
81 }
82
83 static void ustream_ssl_notify_read(struct ustream *s, int bytes)
84 {
85 __ustream_ssl_poll(s);
86 }
87
88 static void ustream_ssl_notify_write(struct ustream *s, int bytes)
89 {
90 struct ustream_ssl *us = container_of(s->next, struct ustream_ssl, stream);
91
92 ustream_ssl_check_conn(us);
93 ustream_write_pending(s->next);
94 }
95
96 static void ustream_ssl_notify_state(struct ustream *s)
97 {
98 s->next->write_error = true;
99 ustream_state_change(s->next);
100 }
101
102 static int ustream_ssl_write(struct ustream *s, const char *buf, int len, bool more)
103 {
104 struct ustream_ssl *us = container_of(s, struct ustream_ssl, stream);
105
106 if (!us->connected || us->error)
107 return 0;
108
109 if (us->conn->w.data_bytes)
110 return 0;
111
112 return __ustream_ssl_write(us, buf, len);
113 }
114
115 static void ustream_ssl_set_read_blocked(struct ustream *s)
116 {
117 struct ustream_ssl *us = container_of(s, struct ustream_ssl, stream);
118
119 ustream_set_read_blocked(us->conn, !!s->read_blocked);
120 }
121
122 static void ustream_ssl_free(struct ustream *s)
123 {
124 struct ustream_ssl *us = container_of(s, struct ustream_ssl, stream);
125
126 if (us->conn) {
127 us->conn->next = NULL;
128 us->conn->notify_read = NULL;
129 us->conn->notify_write = NULL;
130 us->conn->notify_state = NULL;
131 }
132
133 uloop_timeout_cancel(&us->error_timer);
134 __ustream_ssl_session_free(us->ssl);
135 us->ctx = NULL;
136 us->ssl = NULL;
137 us->conn = NULL;
138 us->connected = false;
139 us->error = false;
140 }
141
142 static bool ustream_ssl_poll(struct ustream *s)
143 {
144 struct ustream_ssl *us = container_of(s, struct ustream_ssl, stream);
145 bool fd_poll;
146
147 fd_poll = ustream_poll(us->conn);
148 return __ustream_ssl_poll(s) || fd_poll;
149 }
150
151 static void ustream_ssl_stream_init(struct ustream_ssl *us)
152 {
153 struct ustream *conn = us->conn;
154 struct ustream *s = &us->stream;
155
156 conn->notify_read = ustream_ssl_notify_read;
157 conn->notify_write = ustream_ssl_notify_write;
158 conn->notify_state = ustream_ssl_notify_state;
159
160 s->free = ustream_ssl_free;
161 s->write = ustream_ssl_write;
162 s->poll = ustream_ssl_poll;
163 s->set_read_blocked = ustream_ssl_set_read_blocked;
164 ustream_init_defaults(s);
165 }
166
167 static int _ustream_ssl_init(struct ustream_ssl *us, struct ustream *conn, void *ctx, bool server)
168 {
169 us->error_timer.cb = ustream_ssl_error_cb;
170 us->server = server;
171 us->conn = conn;
172 us->ctx = ctx;
173
174 us->ssl = __ustream_ssl_session_new(us->ctx);
175 if (!us->ssl)
176 return -ENOMEM;
177
178 conn->next = &us->stream;
179 ustream_set_io(ctx, us->ssl, conn);
180 ustream_ssl_stream_init(us);
181
182 return 0;
183 }
184
185 const struct ustream_ssl_ops ustream_ssl_ops = {
186 .context_new = __ustream_ssl_context_new,
187 .context_set_crt_file = __ustream_ssl_set_crt_file,
188 .context_set_key_file = __ustream_ssl_set_key_file,
189 .context_free = __ustream_ssl_context_free,
190 .init = _ustream_ssl_init,
191 };