nixio:
[project/luci.git] / libs / nixio / src / tls-socket.c
1 /*
2  * nixio - Linux I/O library for lua
3  *
4  *   Copyright (C) 2009 Steven Barth <steven@midlink.org>
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  */
18
19 #include "nixio-tls.h"
20 #include <string.h>
21 #include <stdlib.h>
22
23 static int nixio__tls_sock_perror(lua_State *L, SSL *sock, int code) {
24         lua_pushnil(L);
25         lua_pushinteger(L, code);
26         lua_pushinteger(L, SSL_get_error(sock, code));
27         return 3;
28 }
29
30 static int nixio__tls_sock_pstatus(lua_State *L, SSL *sock, int code) {
31         if (code == 1) {
32                 lua_pushboolean(L, 1);
33                 return 1;
34         } else {
35                 return nixio__tls_sock_perror(L, sock, code);
36         }
37 }
38
39 static SSL* nixio__checktlssock(lua_State *L) {
40         nixio_tls_sock *sock = luaL_checkudata(L, 1, NIXIO_TLS_SOCK_META);
41         luaL_argcheck(L, sock->socket, 1, "invalid context");
42         return sock->socket;
43 }
44
45 static int nixio_tls_sock_recv(lua_State *L) {
46         SSL *sock = nixio__checktlssock(L);
47         int req = luaL_checkinteger(L, 2);
48
49         luaL_argcheck(L, req >= 0, 2, "out of range");
50
51         /* We limit the readsize to NIXIO_BUFFERSIZE */
52         req = (req > NIXIO_BUFFERSIZE) ? NIXIO_BUFFERSIZE : req;
53
54 #ifndef WITH_AXTLS
55
56         char buffer[NIXIO_BUFFERSIZE];
57         int readc = SSL_read(sock, buffer, req);
58
59         if (readc < 0) {
60                 return nixio__tls_sock_pstatus(L, sock, readc);
61         } else {
62                 lua_pushlstring(L, buffer, readc);
63                 return 1;
64         }
65
66 #else
67
68         if (!req) {
69                 lua_pushliteral(L, "");
70                 return 1;
71         }
72
73         nixio_tls_sock *t = lua_touserdata(L, 1);
74
75         /* AXTLS doesn't handle buffering for us, so we have to hack around*/
76         if (req < t->pbufsiz) {
77                 lua_pushlstring(L, t->pbufpos, req);
78                 t->pbufpos += req;
79                 t->pbufsiz -= req;
80                 return 1;
81         } else {
82                 char *axbuf;
83                 int axread;
84
85                 /* while handshake pending */
86                 while ((axread = ssl_read(sock, (uint8_t**)&axbuf)) == SSL_OK);
87
88                 if (t->pbufsiz) {
89                         lua_pushlstring(L, t->pbufpos, t->pbufsiz);
90                 }
91
92                 if (axread < 0) {
93                         /* There is an error */
94                         free(t->pbuffer);
95                         t->pbuffer = t->pbufpos = NULL;
96                         t->pbufsiz = 0;
97
98                         if (axread != SSL_ERROR_CONN_LOST) {
99                                 return nixio__tls_sock_perror(L, sock, axread);
100                         } else {
101                                 if (!t->pbufsiz) {
102                                         lua_pushliteral(L, "");
103                                 }
104                         }
105                 } else {
106                         int stillwant = req - t->pbufsiz;
107                         if (stillwant < axread) {
108                                 /* we got more data than we need */
109                                 lua_pushlstring(L, axbuf, stillwant);
110                                 if(t->pbufsiz) {
111                                         lua_concat(L, 2);
112                                 }
113
114                                 /* remaining data goes into the buffer */
115                                 t->pbufpos = t->pbuffer;
116                                 t->pbufsiz = axread - stillwant;
117                                 t->pbuffer = realloc(t->pbuffer, t->pbufsiz);
118                                 if (!t->pbuffer) {
119                                         free(t->pbufpos);
120                                         t->pbufpos = NULL;
121                                         t->pbufsiz = 0;
122                                         return luaL_error(L, "out of memory");
123                                 }
124
125                                 t->pbufpos = t->pbuffer;
126                                 memcpy(t->pbufpos, axbuf + stillwant, t->pbufsiz);
127                         } else {
128                                 lua_pushlstring(L, axbuf, axread);
129                                 if(t->pbufsiz) {
130                                         lua_concat(L, 2);
131                                 }
132
133                                 /* free buffer */
134                                 free(t->pbuffer);
135                                 t->pbuffer = t->pbufpos = NULL;
136                                 t->pbufsiz = 0;
137                         }
138                 }
139                 return 1;
140         }
141
142 #endif /* WITH_AXTLS */
143
144 }
145
146 static int nixio_tls_sock_send(lua_State *L) {
147         SSL *sock = nixio__checktlssock(L);
148         size_t len;
149         ssize_t sent;
150         const char *data = luaL_checklstring(L, 2, &len);
151         sent = SSL_write(sock, data, len);
152         if (sent > 0) {
153                 lua_pushinteger(L, sent);
154                 return 1;
155         } else {
156                 return nixio__tls_sock_pstatus(L, sock, len);
157         }
158 }
159
160 static int nixio_tls_sock_accept(lua_State *L) {
161         SSL *sock = nixio__checktlssock(L);
162         return nixio__tls_sock_pstatus(L, sock, SSL_accept(sock));
163 }
164
165 static int nixio_tls_sock_connect(lua_State *L) {
166         SSL *sock = nixio__checktlssock(L);
167         return nixio__tls_sock_pstatus(L, sock, SSL_connect(sock));
168 }
169
170 static int nixio_tls_sock_shutdown(lua_State *L) {
171         SSL *sock = nixio__checktlssock(L);
172         return nixio__tls_sock_pstatus(L, sock, SSL_shutdown(sock));
173 }
174
175 static int nixio_tls_sock__gc(lua_State *L) {
176         nixio_tls_sock *sock = luaL_checkudata(L, 1, NIXIO_TLS_SOCK_META);
177         if (sock->socket) {
178                 SSL_free(sock->socket);
179                 sock->socket = NULL;
180 #ifdef WITH_AXTLS
181                 free(sock->pbuffer);
182 #endif
183         }
184         return 0;
185 }
186
187 static int nixio_tls_sock__tostring(lua_State *L) {
188         SSL *sock = nixio__checktlssock(L);
189         lua_pushfstring(L, "nixio TLS socket: %p", sock);
190         return 1;
191 }
192
193
194 /* ctx function table */
195 static const luaL_reg M[] = {
196         {"recv",                nixio_tls_sock_recv},
197         {"send",                nixio_tls_sock_send},
198         {"accept",              nixio_tls_sock_accept},
199         {"connect",     nixio_tls_sock_connect},
200         {"shutdown",    nixio_tls_sock_shutdown},
201         {"__gc",                nixio_tls_sock__gc},
202         {"__tostring",  nixio_tls_sock__tostring},
203         {NULL,                  NULL}
204 };
205
206
207 void nixio_open_tls_socket(lua_State *L) {
208         /* create socket metatable */
209         luaL_newmetatable(L, NIXIO_TLS_SOCK_META);
210         luaL_register(L, NULL, M);
211         lua_pushvalue(L, -1);
212         lua_setfield(L, -2, "__index");
213         lua_setfield(L, -2, "tls_socket_meta");
214 }