a305518cd1e1f2ec00a282664d95481286463325
[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.h"
20 #include "string.h"
21
22 #ifndef WITHOUT_OPENSSL
23 #include <openssl/ssl.h>
24 #endif
25
26 static int nixio__tls_sock_perror(lua_State *L, SSL *sock, int code) {
27         lua_pushnil(L);
28         lua_pushinteger(L, code);
29         lua_pushinteger(L, SSL_get_error(sock, code));
30         return 3;
31 }
32
33 static int nixio__tls_sock_pstatus(lua_State *L, SSL *sock, int code) {
34         if (code == 1) {
35                 lua_pushboolean(L, 1);
36                 return 1;
37         } else {
38                 return nixio__tls_sock_perror(L, sock, code);
39         }
40 }
41
42 static SSL* nixio__checktlssock(lua_State *L) {
43         SSL **sock = (SSL **)luaL_checkudata(L, 1, NIXIO_TLS_SOCK_META);
44         luaL_argcheck(L, *sock, 1, "invalid context");
45         return *sock;
46 }
47
48 static int nixio_tls_sock_recv(lua_State *L) {
49         SSL *sock = nixio__checktlssock(L);
50         int req = luaL_checkinteger(L, 2);
51
52         luaL_argcheck(L, req >= 0, 2, "out of range");
53
54         /* We limit the readsize to NIXIO_BUFFERSIZE */
55         req = (req > NIXIO_BUFFERSIZE) ? NIXIO_BUFFERSIZE : req;
56 #ifndef WITH_AXTLS
57         char buffer[NIXIO_BUFFERSIZE];
58         int readc = SSL_read(sock, buffer, req);
59
60         if (readc < 0) {
61                 return nixio__tls_sock_pstatus(L, sock, readc);
62         } else {
63                 lua_pushlstring(L, buffer, readc);
64                 return 1;
65         }
66 #else
67         if (!req) {
68                 lua_pushliteral(L, "");
69                 return 1;
70         }
71
72         /* AXTLS doesn't handle buffering for us, so we have to hack around*/
73         int buflen = 0;
74         lua_getmetatable(L, 1);
75         lua_getfield(L, -1, "_axbuffer");
76
77         if (lua_isstring(L, -1)) {
78                 buflen = lua_objlen(L, -1);
79         }
80
81         if (req < buflen) {
82                 const char *axbuf = lua_tostring(L, -1);
83                 lua_pushlstring(L, axbuf, req);
84                 lua_pushlstring(L, axbuf + req, buflen - req);
85                 lua_setfield(L, -4, "_axbuffer");
86                 return 1;
87         } else {
88                 if (!lua_isstring(L, -1)) {
89                         lua_pop(L, 1);
90                         lua_pushliteral(L, "");
91                 }
92
93                 char *axbuf;
94                 int axread;
95
96                 /* while handshake pending */
97                 while ((axread = ssl_read(sock, (uint8_t**)&axbuf)) == SSL_OK);
98
99                 if (axread < 0) {
100                         /* There is an error */
101
102                         if (axread != SSL_ERROR_CONN_LOST) {
103                                 lua_pushliteral(L, "");
104                                 lua_setfield(L, -3, "_axbuffer");
105                                 return nixio__tls_sock_perror(L, sock, axread);
106                         } else {
107                                 lua_pushliteral(L, "");
108                         }
109                 } else {
110                         int stillwant = req - buflen;
111                         if (stillwant < axread) {
112                                 /* we got more data than we need */
113                                 lua_pushlstring(L, axbuf, stillwant);
114                                 lua_concat(L, 2);
115
116                                 /* remaining data goes into the buffer */
117                                 lua_pushlstring(L, axbuf + stillwant, axread - stillwant);
118                         } else {
119                                 lua_pushlstring(L, axbuf, axread);
120                                 lua_concat(L, 2);
121                                 lua_pushliteral(L, "");
122                         }
123                 }
124                 lua_setfield(L, -3, "_axbuffer");
125                 return 1;
126         }
127
128 #endif
129 }
130
131 static int nixio_tls_sock_send(lua_State *L) {
132         SSL *sock = nixio__checktlssock(L);
133         size_t len;
134         ssize_t sent;
135         const char *data = luaL_checklstring(L, 2, &len);
136         sent = SSL_write(sock, data, len);
137         if (sent > 0) {
138                 lua_pushinteger(L, sent);
139                 return 1;
140         } else {
141                 return nixio__tls_sock_pstatus(L, sock, len);
142         }
143 }
144
145 static int nixio_tls_sock_accept(lua_State *L) {
146         SSL *sock = nixio__checktlssock(L);
147         return nixio__tls_sock_pstatus(L, sock, SSL_accept(sock));
148 }
149
150 static int nixio_tls_sock_connect(lua_State *L) {
151         SSL *sock = nixio__checktlssock(L);
152         return nixio__tls_sock_pstatus(L, sock, SSL_connect(sock));
153 }
154
155 static int nixio_tls_sock_shutdown(lua_State *L) {
156         SSL *sock = nixio__checktlssock(L);
157         return nixio__tls_sock_pstatus(L, sock, SSL_shutdown(sock));
158 }
159
160 static int nixio_tls_sock__gc(lua_State *L) {
161         SSL **sock = (SSL **)luaL_checkudata(L, 1, NIXIO_TLS_SOCK_META);
162         if (*sock) {
163                 SSL_free(*sock);
164                 *sock = NULL;
165         }
166         return 0;
167 }
168
169 static int nixio_tls_sock__tostring(lua_State *L) {
170         SSL *sock = nixio__checktlssock(L);
171         lua_pushfstring(L, "nixio TLS socket: %p", sock);
172         return 1;
173 }
174
175
176 /* ctx function table */
177 static const luaL_reg M[] = {
178         {"recv",                nixio_tls_sock_recv},
179         {"send",                nixio_tls_sock_send},
180         {"accept",              nixio_tls_sock_accept},
181         {"connect",     nixio_tls_sock_connect},
182         {"shutdown",    nixio_tls_sock_shutdown},
183         {"__gc",                nixio_tls_sock__gc},
184         {"__tostring",  nixio_tls_sock__tostring},
185         {NULL,                  NULL}
186 };
187
188
189 void nixio_open_tls_socket(lua_State *L) {
190         /* create socket metatable */
191         luaL_newmetatable(L, NIXIO_TLS_SOCK_META);
192         luaL_register(L, NULL, M);
193         lua_pushvalue(L, -1);
194         lua_setfield(L, -2, "__index");
195         lua_setfield(L, -2, "tls_socket_meta");
196 }