moonbridge
annotate moonbridge_io.c @ 124:61a2f55b3538
Do not announce socket/listener type when communicating with the child process
(unnecessary because pointer to listener struct is passed)
(unnecessary because pointer to listener struct is passed)
author | jbe |
---|---|
date | Sun Apr 12 00:33:08 2015 +0200 (2015-04-12) |
parents | 3bbcd75eefcd |
children | df08e63dc44b |
rev | line source |
---|---|
jbe@79 | 1 |
jbe@79 | 2 #include <stdlib.h> |
jbe@79 | 3 #include <unistd.h> |
jbe@79 | 4 #include <stdint.h> |
jbe@79 | 5 #include <errno.h> |
jbe@79 | 6 #include <string.h> |
jbe@79 | 7 #include <sys/socket.h> |
jbe@111 | 8 #include <sys/un.h> |
jbe@79 | 9 #include <sys/select.h> |
jbe@81 | 10 #include <fcntl.h> |
jbe@95 | 11 #include <netinet/in.h> |
jbe@95 | 12 #include <netinet/tcp.h> |
jbe@107 | 13 #include <arpa/inet.h> |
jbe@98 | 14 #include <sys/types.h> |
jbe@118 | 15 #include <sys/stat.h> |
jbe@98 | 16 #include <netdb.h> |
jbe@113 | 17 #include <signal.h> |
jbe@115 | 18 #include <time.h> |
jbe@79 | 19 |
jbe@79 | 20 #include <lua.h> |
jbe@79 | 21 #include <lauxlib.h> |
jbe@79 | 22 #include <lualib.h> |
jbe@79 | 23 |
jbe@80 | 24 #define MOONBR_IO_MAXSTRERRORLEN 80 |
jbe@85 | 25 #define MOONBR_IO_READBUFLEN 4096 |
jbe@80 | 26 #define MOONBR_IO_WRITEBUFLEN 4096 |
jbe@80 | 27 |
jbe@108 | 28 #define MOONBR_IO_LISTEN_BACKLOG 1024 |
jbe@108 | 29 |
jbe@80 | 30 #define moonbr_io_errmsg() \ |
jbe@80 | 31 char errmsg[MOONBR_IO_MAXSTRERRORLEN]; \ |
jbe@80 | 32 strerror_r(errno, errmsg, MOONBR_IO_MAXSTRERRORLEN) |
jbe@80 | 33 |
jbe@79 | 34 #define MOONBR_IO_HANDLE_MT_REGKEY "moonbridge_io_handle" |
jbe@79 | 35 #define MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY "moonbridge_io_handle_public" |
jbe@108 | 36 #define MOONBR_IO_LISTENER_MT_REGKEY "moonbridge_io_listener" |
jbe@79 | 37 |
jbe@79 | 38 typedef struct { |
jbe@79 | 39 int fd; |
jbe@107 | 40 int issock; |
jbe@107 | 41 sa_family_t addrfam; |
jbe@94 | 42 int finished; |
jbe@94 | 43 int closed; |
jbe@81 | 44 int nonblocking; |
jbe@95 | 45 int nopush; |
jbe@85 | 46 int readerr; |
jbe@105 | 47 int readbufin; |
jbe@105 | 48 int readbufout; |
jbe@81 | 49 int writeerr; |
jbe@83 | 50 size_t writeleft; |
jbe@83 | 51 #if LUA_VERSION_NUM >= 503 |
jbe@83 | 52 lua_Integer writeqin; |
jbe@83 | 53 lua_Integer writeqout; |
jbe@83 | 54 #else |
jbe@83 | 55 int writeqin; |
jbe@83 | 56 int writeqout; |
jbe@83 | 57 #endif |
jbe@83 | 58 size_t writeqoff; |
jbe@103 | 59 int writebufin; |
jbe@103 | 60 int writebufout; |
jbe@85 | 61 char readbuf[MOONBR_IO_READBUFLEN]; |
jbe@80 | 62 char writebuf[MOONBR_IO_WRITEBUFLEN]; |
jbe@79 | 63 } moonbr_io_handle_t; |
jbe@79 | 64 |
jbe@108 | 65 typedef struct { |
jbe@108 | 66 int fd; |
jbe@118 | 67 sa_family_t addrfam; |
jbe@108 | 68 int nonblocking; |
jbe@108 | 69 } moonbr_io_listener_t; |
jbe@108 | 70 |
jbe@81 | 71 static void moonbr_io_handle_set_nonblocking(lua_State *L, moonbr_io_handle_t *handle, int nonblocking) { |
jbe@95 | 72 int flags; |
jbe@95 | 73 if (handle->nonblocking == nonblocking) return; |
jbe@95 | 74 flags = fcntl(handle->fd, F_GETFL, 0); |
jbe@95 | 75 if (flags == -1) { |
jbe@95 | 76 moonbr_io_errmsg(); |
jbe@96 | 77 close(handle->fd); |
jbe@96 | 78 handle->fd = -1; |
jbe@96 | 79 handle->closed = 1; |
jbe@95 | 80 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg); |
jbe@81 | 81 } |
jbe@95 | 82 if (nonblocking) flags |= O_NONBLOCK; |
jbe@95 | 83 else flags &= ~O_NONBLOCK; |
jbe@95 | 84 if (fcntl(handle->fd, F_SETFL, flags) == -1) { |
jbe@95 | 85 moonbr_io_errmsg(); |
jbe@96 | 86 close(handle->fd); |
jbe@96 | 87 handle->fd = -1; |
jbe@96 | 88 handle->closed = 1; |
jbe@95 | 89 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg); |
jbe@95 | 90 } |
jbe@95 | 91 handle->nonblocking = nonblocking; |
jbe@81 | 92 } |
jbe@81 | 93 |
jbe@87 | 94 static void moonbr_io_handle_set_linger(lua_State *L, moonbr_io_handle_t *handle, int timeout) { |
jbe@87 | 95 struct linger lingerval = { 0, }; |
jbe@107 | 96 if (!handle->issock) return; |
jbe@87 | 97 if (timeout >= 0) { |
jbe@87 | 98 lingerval.l_onoff = 1; |
jbe@87 | 99 lingerval.l_linger = timeout; |
jbe@87 | 100 } |
jbe@87 | 101 if (setsockopt(handle->fd, SOL_SOCKET, SO_LINGER, &lingerval, sizeof(lingerval))) { |
jbe@87 | 102 moonbr_io_errmsg(); |
jbe@96 | 103 close(handle->fd); |
jbe@96 | 104 handle->fd = -1; |
jbe@96 | 105 handle->closed = 1; |
jbe@95 | 106 luaL_error(L, "Unexpected error while setting SO_LINGER with setsockopt: %s", errmsg); |
jbe@87 | 107 } |
jbe@87 | 108 } |
jbe@87 | 109 |
jbe@95 | 110 static void moonbr_io_handle_set_nopush(lua_State *L, moonbr_io_handle_t *handle, int nopush) { |
jbe@96 | 111 #if defined(TCP_NOPUSH) || defined(TCP_CORK) |
jbe@107 | 112 if ( |
jbe@107 | 113 !(handle->addrfam == AF_INET6 || handle->addrfam == AF_INET) || |
jbe@107 | 114 handle->nopush == nopush |
jbe@107 | 115 ) return; |
jbe@96 | 116 #if defined(TCP_NOPUSH) |
jbe@96 | 117 if (setsockopt(handle->fd, IPPROTO_TCP, TCP_NOPUSH, &nopush, sizeof(nopush))) { |
jbe@104 | 118 #elif defined(TCP_CORK) |
jbe@104 | 119 if (setsockopt(handle->fd, IPPROTO_TCP, TCP_CORK, &nopush, sizeof(nopush))) { |
jbe@104 | 120 #endif |
jbe@96 | 121 moonbr_io_errmsg(); |
jbe@96 | 122 close(handle->fd); |
jbe@96 | 123 handle->fd = -1; |
jbe@96 | 124 handle->closed = 1; |
jbe@104 | 125 #if defined(TCP_NOPUSH) |
jbe@96 | 126 luaL_error(L, "Unexpected error while setting TCP_NOPUSH with setsockopt: %s", errmsg); |
jbe@96 | 127 #elif defined(TCP_CORK) |
jbe@95 | 128 luaL_error(L, "Unexpected error while setting TCP_CORK with setsockopt: %s", errmsg); |
jbe@104 | 129 #endif |
jbe@95 | 130 } |
jbe@95 | 131 handle->nopush = nopush; |
jbe@96 | 132 #else |
jbe@96 | 133 #warning Neither TCP_NOPUSH nor TCP_CORK is available |
jbe@96 | 134 #endif |
jbe@95 | 135 } |
jbe@95 | 136 |
jbe@86 | 137 static int moonbr_io_read_impl(lua_State *L, int nonblocking, int drain) { |
jbe@85 | 138 moonbr_io_handle_t *handle; |
jbe@85 | 139 lua_Integer maxread; |
jbe@85 | 140 const char *terminatorstr; |
jbe@85 | 141 size_t terminatorlen; |
jbe@85 | 142 char terminator; |
jbe@85 | 143 luaL_Buffer luabuf; |
jbe@85 | 144 size_t luabufcnt = 0; |
jbe@105 | 145 int remaining; |
jbe@85 | 146 char *terminatorpos; |
jbe@103 | 147 ssize_t bytesread; |
jbe@85 | 148 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); |
jbe@85 | 149 maxread = luaL_optinteger(L, 2, 0); |
jbe@85 | 150 terminatorstr = luaL_optlstring(L, 3, "", &terminatorlen); |
jbe@85 | 151 if (terminatorlen) { |
jbe@85 | 152 luaL_argcheck(L, terminatorlen == 1, 3, "single byte expected"); |
jbe@85 | 153 terminator = terminatorstr[0]; |
jbe@85 | 154 } |
jbe@86 | 155 lua_settop(L, 1); /* return handle on drain, terminator string may be garbage collected */ |
jbe@94 | 156 if (handle->closed) luaL_error(L, "Attempt to read from a closed I/O handle"); |
jbe@85 | 157 if (handle->readerr) { |
jbe@85 | 158 lua_pushnil(L); |
jbe@85 | 159 lua_pushliteral(L, "Previous read error"); |
jbe@85 | 160 return 2; |
jbe@85 | 161 } |
jbe@105 | 162 handle->readerr = 1; |
jbe@104 | 163 if (handle->fd < 0) goto moonbr_io_read_impl_eof; /* fake EOF to simulate shutdown */ |
jbe@85 | 164 moonbr_io_handle_set_nonblocking(L, handle, nonblocking); |
jbe@86 | 165 if (!drain) luaL_buffinit(L, &luabuf); |
jbe@85 | 166 while (1) { |
jbe@105 | 167 remaining = -1; |
jbe@105 | 168 if ( |
jbe@105 | 169 maxread > 0 && |
jbe@105 | 170 handle->readbufin - handle->readbufout >= (size_t)maxread - luabufcnt |
jbe@105 | 171 ) { |
jbe@105 | 172 remaining = maxread - luabufcnt; |
jbe@85 | 173 } else if (terminatorlen) { |
jbe@105 | 174 terminatorpos = memchr( |
jbe@105 | 175 handle->readbuf + handle->readbufout, |
jbe@105 | 176 terminator, |
jbe@105 | 177 handle->readbufin - handle->readbufout |
jbe@105 | 178 ); |
jbe@105 | 179 if (terminatorpos) remaining = 1 + ( |
jbe@105 | 180 terminatorpos - (handle->readbuf + handle->readbufout) |
jbe@105 | 181 ); |
jbe@85 | 182 } |
jbe@105 | 183 if (remaining >= 0) { |
jbe@86 | 184 if (!drain) { |
jbe@105 | 185 luaL_addlstring( |
jbe@105 | 186 &luabuf, |
jbe@105 | 187 handle->readbuf + handle->readbufout, |
jbe@105 | 188 remaining |
jbe@105 | 189 ); |
jbe@86 | 190 luaL_pushresult(&luabuf); |
jbe@90 | 191 } else { |
jbe@105 | 192 luaL_pushresult(&luabuf); |
jbe@105 | 193 lua_pop(L, 1); |
jbe@105 | 194 lua_pushinteger(L, luabufcnt + remaining); |
jbe@86 | 195 } |
jbe@105 | 196 handle->readbufout += remaining; |
jbe@105 | 197 if (handle->readbufout == handle->readbufin) { |
jbe@105 | 198 handle->readbufin = 0; |
jbe@105 | 199 handle->readbufout =0; |
jbe@105 | 200 } |
jbe@104 | 201 handle->readerr = 0; |
jbe@85 | 202 return 1; |
jbe@85 | 203 } |
jbe@105 | 204 if (!drain) luaL_addlstring( |
jbe@105 | 205 &luabuf, |
jbe@105 | 206 handle->readbuf + handle->readbufout, |
jbe@105 | 207 handle->readbufin - handle->readbufout |
jbe@105 | 208 ); |
jbe@105 | 209 luabufcnt += handle->readbufin - handle->readbufout; |
jbe@85 | 210 do { |
jbe@103 | 211 bytesread = read(handle->fd, handle->readbuf, MOONBR_IO_READBUFLEN); |
jbe@103 | 212 } while (bytesread < 0 && (errno == EINTR)); |
jbe@105 | 213 if ( |
jbe@105 | 214 bytesread == 0 || ( |
jbe@105 | 215 nonblocking && |
jbe@105 | 216 bytesread < 0 && (errno == EAGAIN || errno == EWOULDBLOCK) |
jbe@105 | 217 ) |
jbe@105 | 218 ) { |
jbe@105 | 219 handle->readbufin = 0; |
jbe@105 | 220 handle->readbufout = 0; |
jbe@105 | 221 if (!drain) { |
jbe@105 | 222 luaL_pushresult(&luabuf); |
jbe@105 | 223 if (!luabufcnt && bytesread == 0) { |
jbe@105 | 224 lua_pop(L, 1); |
jbe@105 | 225 moonbr_io_read_impl_eof: |
jbe@105 | 226 lua_pushboolean(L, 0); |
jbe@105 | 227 lua_pushliteral(L, "End of file"); |
jbe@105 | 228 handle->readerr = 0; |
jbe@105 | 229 return 2; |
jbe@105 | 230 } |
jbe@105 | 231 } else { |
jbe@105 | 232 if (!luabufcnt && bytesread == 0) lua_pushboolean(L, 1); |
jbe@105 | 233 else lua_pushboolean(L, luabufcnt); |
jbe@105 | 234 } |
jbe@105 | 235 handle->readerr = 0; |
jbe@105 | 236 return 1; |
jbe@105 | 237 } |
jbe@103 | 238 if (bytesread < 0) { |
jbe@85 | 239 moonbr_io_errmsg(); |
jbe@85 | 240 lua_pushnil(L); |
jbe@85 | 241 lua_pushstring(L, errmsg); |
jbe@85 | 242 return 2; |
jbe@85 | 243 } |
jbe@105 | 244 handle->readbufin = bytesread; |
jbe@105 | 245 handle->readbufout = 0; |
jbe@86 | 246 } |
jbe@85 | 247 } |
jbe@85 | 248 |
jbe@85 | 249 static int moonbr_io_read(lua_State *L) { |
jbe@86 | 250 return moonbr_io_read_impl(L, 0, 0); |
jbe@85 | 251 } |
jbe@85 | 252 |
jbe@85 | 253 static int moonbr_io_read_nb(lua_State *L) { |
jbe@86 | 254 return moonbr_io_read_impl(L, 1, 0); |
jbe@86 | 255 } |
jbe@86 | 256 |
jbe@86 | 257 static int moonbr_io_drain(lua_State *L) { |
jbe@86 | 258 return moonbr_io_read_impl(L, 0, 1); |
jbe@86 | 259 } |
jbe@86 | 260 |
jbe@86 | 261 static int moonbr_io_drain_nb(lua_State *L) { |
jbe@86 | 262 return moonbr_io_read_impl(L, 1, 1); |
jbe@85 | 263 } |
jbe@85 | 264 |
jbe@81 | 265 static int moonbr_io_write_impl(lua_State *L, int nonblocking, int flush) { |
jbe@80 | 266 moonbr_io_handle_t *handle; |
jbe@80 | 267 int i, top; |
jbe@80 | 268 const char *str; |
jbe@92 | 269 size_t strlen; |
jbe@103 | 270 ssize_t written; |
jbe@80 | 271 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); |
jbe@94 | 272 if (handle->closed) luaL_error(L, "Attempt to write to a closed I/O handle"); |
jbe@94 | 273 if (handle->finished) luaL_error(L, "Attempt to write to a finished I/O handle"); |
jbe@81 | 274 if (handle->writeerr) { |
jbe@80 | 275 lua_pushnil(L); |
jbe@80 | 276 lua_pushliteral(L, "Previous write error"); |
jbe@80 | 277 return 2; |
jbe@80 | 278 } |
jbe@103 | 279 handle->writeerr = 1; |
jbe@81 | 280 moonbr_io_handle_set_nonblocking(L, handle, nonblocking); |
jbe@84 | 281 top = lua_gettop(L); |
jbe@81 | 282 lua_getuservalue(L, 1); |
jbe@103 | 283 lua_getfield(L, -1, "writequeue"); |
jbe@84 | 284 for (i=2; i<=top; i++) { |
jbe@84 | 285 luaL_checklstring(L, i, &strlen); |
jbe@84 | 286 lua_pushvalue(L, i); |
jbe@84 | 287 lua_rawseti(L, -2, handle->writeqin++); |
jbe@84 | 288 handle->writeleft += strlen; |
jbe@81 | 289 } |
jbe@83 | 290 while (handle->writeqout != handle->writeqin) { |
jbe@83 | 291 lua_rawgeti(L, -1, handle->writeqout); |
jbe@81 | 292 str = lua_tolstring(L, -1, &strlen); |
jbe@92 | 293 while (handle->writeqoff < strlen) { |
jbe@103 | 294 if ( |
jbe@103 | 295 strlen - handle->writeqoff <= |
jbe@103 | 296 MOONBR_IO_WRITEBUFLEN - handle->writebufin |
jbe@103 | 297 ) { |
jbe@103 | 298 memcpy( |
jbe@103 | 299 handle->writebuf + handle->writebufin, |
jbe@103 | 300 str + handle->writeqoff, |
jbe@103 | 301 strlen - handle->writeqoff |
jbe@103 | 302 ); |
jbe@103 | 303 handle->writebufin += strlen - handle->writeqoff; |
jbe@80 | 304 break; |
jbe@80 | 305 } else { |
jbe@97 | 306 moonbr_io_handle_set_nopush(L, handle, 1); |
jbe@103 | 307 memcpy( |
jbe@103 | 308 handle->writebuf + handle->writebufin, |
jbe@103 | 309 str + handle->writeqoff, |
jbe@103 | 310 MOONBR_IO_WRITEBUFLEN - handle->writebufin |
jbe@103 | 311 ); |
jbe@103 | 312 handle->writeqoff += MOONBR_IO_WRITEBUFLEN - handle->writebufin; |
jbe@103 | 313 while (handle->writebufout < MOONBR_IO_WRITEBUFLEN) { |
jbe@103 | 314 written = write( |
jbe@103 | 315 handle->fd, |
jbe@103 | 316 handle->writebuf + handle->writebufout, |
jbe@103 | 317 MOONBR_IO_WRITEBUFLEN - handle->writebufout |
jbe@103 | 318 ); |
jbe@103 | 319 if (written < 0) { |
jbe@81 | 320 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) { |
jbe@81 | 321 goto moonbr_io_write_impl_block; |
jbe@81 | 322 } else if (errno != EINTR) { |
jbe@80 | 323 moonbr_io_errmsg(); |
jbe@80 | 324 lua_pushnil(L); |
jbe@80 | 325 lua_pushstring(L, errmsg); |
jbe@80 | 326 return 2; |
jbe@80 | 327 } |
jbe@103 | 328 } else { |
jbe@103 | 329 handle->writebufout += written; |
jbe@103 | 330 handle->writeleft -= written; |
jbe@80 | 331 } |
jbe@80 | 332 } |
jbe@103 | 333 handle->writebufin = 0; |
jbe@103 | 334 handle->writebufout = 0; |
jbe@80 | 335 } |
jbe@80 | 336 } |
jbe@81 | 337 handle->writeqoff = 0; |
jbe@81 | 338 lua_pop(L, 1); |
jbe@81 | 339 lua_pushnil(L); |
jbe@83 | 340 lua_rawseti(L, -2, handle->writeqout++); |
jbe@80 | 341 } |
jbe@81 | 342 if (flush) { |
jbe@97 | 343 moonbr_io_handle_set_nopush(L, handle, 0); |
jbe@103 | 344 while (handle->writebufout < handle->writebufin) { |
jbe@103 | 345 written = write( |
jbe@103 | 346 handle->fd, |
jbe@103 | 347 handle->writebuf + handle->writebufout, |
jbe@103 | 348 handle->writebufin - handle->writebufout |
jbe@103 | 349 ); |
jbe@103 | 350 if (written < 0) { |
jbe@81 | 351 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) { |
jbe@81 | 352 goto moonbr_io_write_impl_block; |
jbe@81 | 353 } else if (errno != EINTR) { |
jbe@81 | 354 moonbr_io_errmsg(); |
jbe@81 | 355 lua_pushnil(L); |
jbe@81 | 356 lua_pushstring(L, errmsg); |
jbe@81 | 357 return 2; |
jbe@81 | 358 } |
jbe@81 | 359 } else { |
jbe@103 | 360 handle->writebufout += written; |
jbe@103 | 361 handle->writeleft -= written; |
jbe@81 | 362 } |
jbe@81 | 363 } |
jbe@103 | 364 handle->writebufin = 0; |
jbe@103 | 365 handle->writebufout = 0; |
jbe@81 | 366 } |
jbe@103 | 367 if (nonblocking) lua_pushinteger(L, 0); |
jbe@103 | 368 else lua_pushvalue(L, 1); |
jbe@103 | 369 handle->writeerr = 0; |
jbe@80 | 370 return 1; |
jbe@81 | 371 moonbr_io_write_impl_block: |
jbe@91 | 372 lua_pushinteger(L, handle->writeleft); |
jbe@103 | 373 handle->writeerr = 0; |
jbe@81 | 374 return 1; |
jbe@81 | 375 } |
jbe@81 | 376 |
jbe@81 | 377 static int moonbr_io_write(lua_State *L) { |
jbe@81 | 378 return moonbr_io_write_impl(L, 0, 0); |
jbe@81 | 379 } |
jbe@81 | 380 |
jbe@81 | 381 static int moonbr_io_write_nb(lua_State *L) { |
jbe@81 | 382 return moonbr_io_write_impl(L, 1, 0); |
jbe@80 | 383 } |
jbe@80 | 384 |
jbe@80 | 385 static int moonbr_io_flush(lua_State *L) { |
jbe@81 | 386 return moonbr_io_write_impl(L, 0, 1); |
jbe@81 | 387 } |
jbe@81 | 388 |
jbe@81 | 389 static int moonbr_io_flush_nb(lua_State *L) { |
jbe@81 | 390 return moonbr_io_write_impl(L, 1, 1); |
jbe@80 | 391 } |
jbe@80 | 392 |
jbe@88 | 393 static int moonbr_io_finish(lua_State *L) { |
jbe@88 | 394 moonbr_io_handle_t *handle; |
jbe@88 | 395 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); |
jbe@94 | 396 if (handle->closed) luaL_error(L, "Attempt to finish a closed I/O handle"); |
jbe@94 | 397 if (handle->finished) luaL_error(L, "Attempt to finish a finished I/O handle"); |
jbe@94 | 398 if (handle->writeleft) { |
jbe@94 | 399 lua_pushcfunction(L, moonbr_io_flush); |
jbe@94 | 400 lua_pushvalue(L, 1); |
jbe@116 | 401 if (lua_pcall(L, 1, 2, 0)) { |
jbe@116 | 402 handle->finished = 1; |
jbe@116 | 403 lua_error(L); |
jbe@116 | 404 } |
jbe@94 | 405 if (!lua_toboolean(L, -2)) { |
jbe@94 | 406 handle->finished = 1; |
jbe@94 | 407 return 2; |
jbe@88 | 408 } |
jbe@94 | 409 } |
jbe@94 | 410 handle->finished = 1; |
jbe@107 | 411 if (handle->addrfam == AF_INET6 || handle->addrfam == AF_INET) { |
jbe@88 | 412 if (shutdown(handle->fd, SHUT_WR)) { |
jbe@88 | 413 moonbr_io_errmsg(); |
jbe@88 | 414 lua_pushnil(L); |
jbe@88 | 415 lua_pushstring(L, errmsg); |
jbe@88 | 416 return 2; |
jbe@88 | 417 } |
jbe@94 | 418 } else { |
jbe@94 | 419 if (close(handle->fd)) { |
jbe@94 | 420 moonbr_io_errmsg(); |
jbe@94 | 421 handle->fd = -1; |
jbe@94 | 422 lua_pushnil(L); |
jbe@94 | 423 lua_pushstring(L, errmsg); |
jbe@94 | 424 return 2; |
jbe@94 | 425 } |
jbe@94 | 426 handle->fd = -1; /* fake EOF on read */ |
jbe@88 | 427 } |
jbe@88 | 428 lua_pushboolean(L, 1); |
jbe@88 | 429 return 1; |
jbe@88 | 430 } |
jbe@88 | 431 |
jbe@94 | 432 static int moonbr_io_close_impl(lua_State *L, int reset) { |
jbe@83 | 433 moonbr_io_handle_t *handle; |
jbe@83 | 434 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); |
jbe@94 | 435 if (handle->closed) luaL_error(L, "Attempt to close a closed I/O handle"); |
jbe@116 | 436 handle->closed = 1; |
jbe@94 | 437 if (!reset) { |
jbe@87 | 438 if (handle->writeleft) { |
jbe@87 | 439 lua_pushcfunction(L, moonbr_io_flush); |
jbe@87 | 440 lua_pushvalue(L, 1); |
jbe@116 | 441 if (lua_pcall(L, 1, 2, 0)) { |
jbe@116 | 442 close(handle->fd); |
jbe@116 | 443 handle->fd = -1; |
jbe@116 | 444 lua_error(L); |
jbe@116 | 445 } |
jbe@87 | 446 if (!lua_toboolean(L, -2)) { |
jbe@87 | 447 close(handle->fd); |
jbe@87 | 448 handle->fd = -1; |
jbe@87 | 449 return 2; |
jbe@87 | 450 } |
jbe@83 | 451 } |
jbe@94 | 452 moonbr_io_handle_set_linger(L, handle, -1); |
jbe@83 | 453 } |
jbe@94 | 454 if (handle->fd >= 0) { |
jbe@94 | 455 if (close(handle->fd)) { |
jbe@94 | 456 moonbr_io_errmsg(); |
jbe@94 | 457 handle->fd = -1; |
jbe@94 | 458 lua_pushnil(L); |
jbe@94 | 459 lua_pushstring(L, errmsg); |
jbe@94 | 460 return 2; |
jbe@94 | 461 } |
jbe@104 | 462 handle->fd = -1; |
jbe@83 | 463 } |
jbe@83 | 464 lua_pushboolean(L, 1); |
jbe@83 | 465 return 1; |
jbe@84 | 466 |
jbe@83 | 467 } |
jbe@83 | 468 |
jbe@94 | 469 static int moonbr_io_close(lua_State *L) { |
jbe@94 | 470 return moonbr_io_close_impl(L, 0); |
jbe@94 | 471 } |
jbe@94 | 472 |
jbe@84 | 473 static int moonbr_io_reset(lua_State *L) { |
jbe@94 | 474 return moonbr_io_close_impl(L, 1); |
jbe@84 | 475 } |
jbe@84 | 476 |
jbe@108 | 477 static int moonbr_io_handlegc(lua_State *L) { |
jbe@88 | 478 moonbr_io_handle_t *handle; |
jbe@88 | 479 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); |
jbe@88 | 480 if (handle->fd >= 0) { |
jbe@88 | 481 lua_pushcfunction(L, moonbr_io_close); |
jbe@88 | 482 lua_pushvalue(L, 1); |
jbe@88 | 483 lua_pushinteger(L, 0); |
jbe@88 | 484 lua_call(L, 2, 0); |
jbe@88 | 485 } |
jbe@88 | 486 return 0; |
jbe@88 | 487 } |
jbe@88 | 488 |
jbe@100 | 489 void moonbr_io_closehandle(lua_State *L, int idx, int reset) { |
jbe@88 | 490 moonbr_io_handle_t *handle; |
jbe@88 | 491 handle = luaL_checkudata(L, idx, MOONBR_IO_HANDLE_MT_REGKEY); |
jbe@100 | 492 if (!handle->closed) { |
jbe@100 | 493 lua_pushcfunction(L, reset ? moonbr_io_reset : moonbr_io_close); |
jbe@100 | 494 lua_pushvalue(L, idx < 0 ? idx-1 : idx); |
jbe@100 | 495 lua_call(L, 1, 0); |
jbe@88 | 496 } |
jbe@88 | 497 } |
jbe@88 | 498 |
jbe@107 | 499 void moonbr_io_pushhandle(lua_State *L, int fd) { |
jbe@79 | 500 moonbr_io_handle_t *handle; |
jbe@107 | 501 struct sockaddr addr; |
jbe@107 | 502 socklen_t addrlen; |
jbe@79 | 503 handle = lua_newuserdata(L, sizeof(moonbr_io_handle_t)); |
jbe@79 | 504 handle->fd = fd; |
jbe@107 | 505 addrlen = sizeof(addr); |
jbe@107 | 506 if (getsockname(fd, &addr, &addrlen)) { |
jbe@107 | 507 if (errno != ENOTSOCK) { |
jbe@107 | 508 moonbr_io_errmsg(); |
jbe@107 | 509 luaL_error(L, "Unexpected error when examining socket: %s", errmsg); |
jbe@107 | 510 } |
jbe@107 | 511 handle->issock = 0; |
jbe@107 | 512 } else { |
jbe@107 | 513 handle->issock = 1; |
jbe@107 | 514 handle->addrfam = addr.sa_family; |
jbe@107 | 515 } |
jbe@94 | 516 handle->finished = 0; |
jbe@94 | 517 handle->closed = 0; |
jbe@81 | 518 handle->nonblocking = -1; |
jbe@95 | 519 handle->nopush = -1; |
jbe@85 | 520 handle->readerr = 0; |
jbe@105 | 521 handle->readbufin = 0; |
jbe@105 | 522 handle->readbufout = 0; |
jbe@81 | 523 handle->writeerr = 0; |
jbe@81 | 524 handle->writeleft = 0; |
jbe@83 | 525 handle->writeqin = 0; |
jbe@83 | 526 handle->writeqout = 0; |
jbe@81 | 527 handle->writeqoff = 0; |
jbe@103 | 528 handle->writebufin = 0; |
jbe@103 | 529 handle->writebufout = 0; |
jbe@87 | 530 moonbr_io_handle_set_linger(L, handle, 0); |
jbe@79 | 531 luaL_getmetatable(L, MOONBR_IO_HANDLE_MT_REGKEY); |
jbe@79 | 532 lua_setmetatable(L, -2); |
jbe@79 | 533 lua_newtable(L); // uservalue |
jbe@81 | 534 lua_newtable(L); |
jbe@103 | 535 lua_setfield(L, -2, "writequeue"); |
jbe@79 | 536 lua_newtable(L); // public |
jbe@107 | 537 if (handle->addrfam == AF_INET6) { |
jbe@107 | 538 struct sockaddr_in6 addr_in6; |
jbe@107 | 539 char addrstrbuf[INET6_ADDRSTRLEN]; |
jbe@107 | 540 const char *addrstr; |
jbe@107 | 541 addrlen = sizeof(addr_in6); |
jbe@107 | 542 if (getsockname(fd, (struct sockaddr *)&addr_in6, &addrlen)) { |
jbe@107 | 543 moonbr_io_errmsg(); |
jbe@107 | 544 luaL_error(L, "Could not determine local IP address/port: %s", errmsg); |
jbe@107 | 545 } |
jbe@107 | 546 if (addrlen > sizeof(addr_in6)) { |
jbe@107 | 547 luaL_error(L, "Could not determine local IP address/port: buffer size exceeded"); |
jbe@107 | 548 } |
jbe@107 | 549 addrstr = inet_ntop(AF_INET6, addr_in6.sin6_addr.s6_addr, addrstrbuf, sizeof(addrstrbuf)); |
jbe@107 | 550 if (!addrstr) { |
jbe@107 | 551 moonbr_io_errmsg(); |
jbe@107 | 552 luaL_error(L, "Could not format local IP address: %s", errmsg); |
jbe@107 | 553 } else { |
jbe@107 | 554 lua_pushstring(L, addrstr); |
jbe@107 | 555 lua_setfield(L, -2, "local_ip6"); |
jbe@107 | 556 } |
jbe@107 | 557 lua_pushinteger(L, ntohs(addr_in6.sin6_port)); |
jbe@107 | 558 lua_setfield(L, -2, "local_tcpport"); |
jbe@107 | 559 if (getpeername(fd, (struct sockaddr *)&addr_in6, &addrlen)) { |
jbe@107 | 560 moonbr_io_errmsg(); |
jbe@107 | 561 luaL_error(L, "Could not determine remote IP address/port: %s", errmsg); |
jbe@107 | 562 } |
jbe@107 | 563 if (addrlen > sizeof(addr_in6)) { |
jbe@107 | 564 luaL_error(L, "Could not determine remote IP address/port: buffer size exceeded"); |
jbe@107 | 565 } |
jbe@107 | 566 addrstr = inet_ntop(AF_INET6, addr_in6.sin6_addr.s6_addr, addrstrbuf, sizeof(addrstrbuf)); |
jbe@107 | 567 if (!addrstr) { |
jbe@107 | 568 moonbr_io_errmsg(); |
jbe@107 | 569 luaL_error(L, "Could not format remote IP address: %s", errmsg); |
jbe@107 | 570 } else { |
jbe@107 | 571 lua_pushstring(L, addrstr); |
jbe@107 | 572 lua_setfield(L, -2, "remote_ip6"); |
jbe@107 | 573 } |
jbe@107 | 574 lua_pushinteger(L, ntohs(addr_in6.sin6_port)); |
jbe@107 | 575 lua_setfield(L, -2, "remote_tcpport"); |
jbe@107 | 576 } else if (handle->addrfam == AF_INET) { |
jbe@107 | 577 struct sockaddr_in addr_in; |
jbe@107 | 578 char addrstrbuf[INET_ADDRSTRLEN]; |
jbe@107 | 579 const char *addrstr; |
jbe@107 | 580 addrlen = sizeof(addr_in); |
jbe@107 | 581 if (getsockname(fd, (struct sockaddr *)&addr_in, &addrlen)) { |
jbe@107 | 582 moonbr_io_errmsg(); |
jbe@107 | 583 luaL_error(L, "Could not determine local IP address/port: %s", errmsg); |
jbe@107 | 584 } |
jbe@107 | 585 if (addrlen > sizeof(addr_in)) { |
jbe@107 | 586 luaL_error(L, "Could not determine local IP address/port: buffer size exceeded"); |
jbe@107 | 587 } |
jbe@107 | 588 addrstr = inet_ntop(AF_INET, &addr_in.sin_addr.s_addr, addrstrbuf, sizeof(addrstrbuf)); |
jbe@107 | 589 if (!addrstr) { |
jbe@107 | 590 moonbr_io_errmsg(); |
jbe@107 | 591 luaL_error(L, "Could not format local IP address: %s", errmsg); |
jbe@107 | 592 } else { |
jbe@107 | 593 lua_pushstring(L, addrstr); |
jbe@107 | 594 lua_setfield(L, -2, "local_ip4"); |
jbe@107 | 595 } |
jbe@107 | 596 lua_pushinteger(L, ntohs(addr_in.sin_port)); |
jbe@107 | 597 lua_setfield(L, -2, "local_tcpport"); |
jbe@107 | 598 if (getpeername(fd, (struct sockaddr *)&addr_in, &addrlen)) { |
jbe@107 | 599 moonbr_io_errmsg(); |
jbe@107 | 600 luaL_error(L, "Could not determine remote IP address/port: %s", errmsg); |
jbe@107 | 601 } |
jbe@107 | 602 if (addrlen > sizeof(addr_in)) { |
jbe@107 | 603 luaL_error(L, "Could not determine remote IP address/port: buffer size exceeded"); |
jbe@107 | 604 } |
jbe@107 | 605 addrstr = inet_ntop(AF_INET, &addr_in.sin_addr.s_addr, addrstrbuf, sizeof(addrstrbuf)); |
jbe@107 | 606 if (!addrstr) { |
jbe@107 | 607 moonbr_io_errmsg(); |
jbe@107 | 608 luaL_error(L, "Could not format remote IP address: %s", errmsg); |
jbe@107 | 609 } else { |
jbe@107 | 610 lua_pushstring(L, addrstr); |
jbe@107 | 611 lua_setfield(L, -2, "remote_ip4"); |
jbe@107 | 612 } |
jbe@107 | 613 lua_pushinteger(L, ntohs(addr_in.sin_port)); |
jbe@107 | 614 lua_setfield(L, -2, "remote_tcpport"); |
jbe@107 | 615 } |
jbe@79 | 616 luaL_getmetatable(L, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY); |
jbe@79 | 617 lua_setmetatable(L, -2); |
jbe@79 | 618 lua_setfield(L, -2, "public"); |
jbe@79 | 619 lua_setuservalue(L, -2); |
jbe@79 | 620 } |
jbe@79 | 621 |
jbe@79 | 622 static int moonbr_io_handleindex(lua_State *L) { |
jbe@80 | 623 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); |
jbe@79 | 624 lua_getuservalue(L, 1); |
jbe@79 | 625 lua_getfield(L, -1, "public"); |
jbe@79 | 626 lua_pushvalue(L, 2); |
jbe@79 | 627 lua_gettable(L, -2); |
jbe@79 | 628 return 1; |
jbe@79 | 629 } |
jbe@79 | 630 |
jbe@79 | 631 static int moonbr_io_handlenewindex(lua_State *L) { |
jbe@80 | 632 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); |
jbe@79 | 633 lua_getuservalue(L, 1); |
jbe@79 | 634 lua_getfield(L, -1, "public"); |
jbe@79 | 635 lua_pushvalue(L, 2); |
jbe@79 | 636 lua_pushvalue(L, 3); |
jbe@79 | 637 lua_settable(L, -3); |
jbe@79 | 638 return 0; |
jbe@79 | 639 } |
jbe@79 | 640 |
jbe@111 | 641 static int moonbr_io_localconnect_impl(lua_State *L, int nonblocking) { |
jbe@111 | 642 const char *path; |
jbe@111 | 643 struct sockaddr_un sockaddr = { .sun_family = AF_LOCAL }; |
jbe@111 | 644 const int path_maxlen = sizeof(struct sockaddr_un) - ( |
jbe@111 | 645 (void *)sockaddr.sun_path - (void *)&sockaddr |
jbe@111 | 646 ) - 1; /* one byte for termination */ |
jbe@111 | 647 int sock; |
jbe@111 | 648 path = luaL_checkstring(L, 1); |
jbe@111 | 649 if (strlen(path) > path_maxlen) luaL_error(L, "Path too long; only %i characters allowed", path_maxlen); |
jbe@111 | 650 strcpy(sockaddr.sun_path, path); |
jbe@111 | 651 sock = socket( |
jbe@111 | 652 PF_LOCAL, |
jbe@111 | 653 SOCK_STREAM | SOCK_CLOEXEC | (nonblocking ? SOCK_NONBLOCK : 0), |
jbe@111 | 654 0 |
jbe@111 | 655 ); |
jbe@111 | 656 if (sock < 0) { |
jbe@111 | 657 moonbr_io_errmsg(); |
jbe@111 | 658 lua_pushnil(L); |
jbe@111 | 659 lua_pushstring(L, errmsg); |
jbe@111 | 660 return 2; |
jbe@111 | 661 } |
jbe@111 | 662 if (connect(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) { |
jbe@111 | 663 if (!nonblocking && errno == EINTR) { |
jbe@111 | 664 moonbr_io_errmsg(); |
jbe@111 | 665 close(sock); |
jbe@111 | 666 lua_pushnil(L); |
jbe@111 | 667 lua_pushstring(L, errmsg); |
jbe@111 | 668 return 2; |
jbe@111 | 669 } else if (!(nonblocking && (errno == EINPROGRESS || errno == EINTR))) { |
jbe@111 | 670 moonbr_io_errmsg(); |
jbe@111 | 671 lua_pushnil(L); |
jbe@111 | 672 lua_pushstring(L, errmsg); |
jbe@111 | 673 return 2; |
jbe@111 | 674 } |
jbe@111 | 675 } |
jbe@111 | 676 moonbr_io_pushhandle(L, sock); |
jbe@111 | 677 return 1; |
jbe@111 | 678 } |
jbe@111 | 679 |
jbe@111 | 680 static int moonbr_io_localconnect(lua_State *L) { |
jbe@111 | 681 return moonbr_io_localconnect_impl(L, 0); |
jbe@111 | 682 } |
jbe@111 | 683 |
jbe@111 | 684 static int moonbr_io_localconnect_nb(lua_State *L) { |
jbe@111 | 685 return moonbr_io_localconnect_impl(L, 1); |
jbe@111 | 686 } |
jbe@111 | 687 |
jbe@99 | 688 static int moonbr_io_tcpconnect_impl(lua_State *L, int nonblocking) { |
jbe@98 | 689 const char *host, *port; |
jbe@98 | 690 struct addrinfo hints = { 0, }; |
jbe@98 | 691 struct addrinfo *res, *addrinfo; |
jbe@98 | 692 int errcode; |
jbe@98 | 693 int sock; |
jbe@98 | 694 host = luaL_checkstring(L, 1); |
jbe@98 | 695 port = luaL_checkstring(L, 2); |
jbe@98 | 696 hints.ai_family = AF_UNSPEC; |
jbe@98 | 697 hints.ai_socktype = SOCK_STREAM; |
jbe@98 | 698 hints.ai_protocol = IPPROTO_TCP; |
jbe@98 | 699 hints.ai_flags = AI_ADDRCONFIG; |
jbe@98 | 700 errcode = getaddrinfo(host, port, &hints, &res); |
jbe@98 | 701 if (errcode) { |
jbe@102 | 702 freeaddrinfo(res); |
jbe@98 | 703 if (errcode == EAI_SYSTEM) { |
jbe@98 | 704 moonbr_io_errmsg(); |
jbe@98 | 705 lua_pushnil(L); |
jbe@98 | 706 lua_pushfstring(L, "%s: %s", gai_strerror(errcode), errmsg); |
jbe@98 | 707 } else { |
jbe@98 | 708 lua_pushnil(L); |
jbe@98 | 709 lua_pushstring(L, gai_strerror(errcode)); |
jbe@98 | 710 } |
jbe@98 | 711 return 2; |
jbe@98 | 712 } |
jbe@98 | 713 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) { |
jbe@98 | 714 if (addrinfo->ai_family == PF_INET6) goto moonbr_io_tcpconnect_found; |
jbe@98 | 715 } |
jbe@98 | 716 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) { |
jbe@98 | 717 if (addrinfo->ai_family == PF_INET) goto moonbr_io_tcpconnect_found; |
jbe@98 | 718 } |
jbe@98 | 719 addrinfo = res; |
jbe@98 | 720 moonbr_io_tcpconnect_found: |
jbe@99 | 721 sock = socket( |
jbe@99 | 722 addrinfo->ai_family, |
jbe@99 | 723 addrinfo->ai_socktype | SOCK_CLOEXEC | (nonblocking ? SOCK_NONBLOCK : 0), |
jbe@99 | 724 addrinfo->ai_protocol |
jbe@99 | 725 ); |
jbe@98 | 726 if (sock < 0) { |
jbe@98 | 727 moonbr_io_errmsg(); |
jbe@108 | 728 freeaddrinfo(res); |
jbe@98 | 729 lua_pushnil(L); |
jbe@98 | 730 lua_pushstring(L, errmsg); |
jbe@108 | 731 return 2; |
jbe@98 | 732 } |
jbe@98 | 733 if (connect(sock, addrinfo->ai_addr, addrinfo->ai_addrlen)) { |
jbe@108 | 734 freeaddrinfo(res); |
jbe@99 | 735 if (!nonblocking && errno == EINTR) { |
jbe@99 | 736 moonbr_io_errmsg(); |
jbe@99 | 737 close(sock); |
jbe@99 | 738 lua_pushnil(L); |
jbe@99 | 739 lua_pushstring(L, errmsg); |
jbe@99 | 740 return 2; |
jbe@99 | 741 } else if (!(nonblocking && (errno == EINPROGRESS || errno == EINTR))) { |
jbe@99 | 742 moonbr_io_errmsg(); |
jbe@99 | 743 lua_pushnil(L); |
jbe@99 | 744 lua_pushstring(L, errmsg); |
jbe@99 | 745 return 2; |
jbe@99 | 746 } |
jbe@108 | 747 } else { |
jbe@108 | 748 freeaddrinfo(res); |
jbe@98 | 749 } |
jbe@107 | 750 moonbr_io_pushhandle(L, sock); |
jbe@98 | 751 return 1; |
jbe@98 | 752 } |
jbe@98 | 753 |
jbe@99 | 754 static int moonbr_io_tcpconnect(lua_State *L) { |
jbe@99 | 755 return moonbr_io_tcpconnect_impl(L, 0); |
jbe@99 | 756 } |
jbe@99 | 757 |
jbe@99 | 758 static int moonbr_io_tcpconnect_nb(lua_State *L) { |
jbe@99 | 759 return moonbr_io_tcpconnect_impl(L, 1); |
jbe@99 | 760 } |
jbe@99 | 761 |
jbe@112 | 762 static int moonbr_io_locallisten(lua_State *L) { |
jbe@112 | 763 moonbr_io_listener_t *listener; |
jbe@112 | 764 const char *path; |
jbe@118 | 765 struct stat sb; |
jbe@112 | 766 struct sockaddr_un sockaddr = { .sun_family = AF_LOCAL }; |
jbe@112 | 767 const int path_maxlen = sizeof(struct sockaddr_un) - ( |
jbe@112 | 768 (void *)sockaddr.sun_path - (void *)&sockaddr |
jbe@112 | 769 ) - 1; /* one byte for termination */ |
jbe@112 | 770 int sock; |
jbe@112 | 771 path = luaL_checkstring(L, 1); |
jbe@112 | 772 if (strlen(path) > path_maxlen) luaL_error(L, "Path too long; only %i characters allowed", path_maxlen); |
jbe@112 | 773 strcpy(sockaddr.sun_path, path); |
jbe@118 | 774 if (stat(path, &sb) == 0) { |
jbe@118 | 775 if (S_ISSOCK(sb.st_mode)) unlink(path); |
jbe@118 | 776 } |
jbe@112 | 777 listener = lua_newuserdata(L, sizeof(moonbr_io_listener_t)); |
jbe@117 | 778 listener->fd = -1; |
jbe@112 | 779 luaL_setmetatable(L, MOONBR_IO_LISTENER_MT_REGKEY); |
jbe@112 | 780 sock = socket( |
jbe@112 | 781 PF_LOCAL, |
jbe@112 | 782 SOCK_STREAM | SOCK_CLOEXEC, |
jbe@112 | 783 0 |
jbe@112 | 784 ); |
jbe@112 | 785 if (sock < 0) { |
jbe@112 | 786 moonbr_io_errmsg(); |
jbe@112 | 787 lua_pushnil(L); |
jbe@112 | 788 lua_pushstring(L, errmsg); |
jbe@112 | 789 return 2; |
jbe@112 | 790 } |
jbe@112 | 791 if (bind(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) { |
jbe@112 | 792 moonbr_io_errmsg(); |
jbe@112 | 793 close(sock); |
jbe@112 | 794 lua_pushnil(L); |
jbe@112 | 795 lua_pushstring(L, errmsg); |
jbe@112 | 796 return 2; |
jbe@112 | 797 } |
jbe@112 | 798 if (listen(sock, MOONBR_IO_LISTEN_BACKLOG)) { |
jbe@112 | 799 moonbr_io_errmsg(); |
jbe@112 | 800 close(sock); |
jbe@112 | 801 lua_pushnil(L); |
jbe@112 | 802 lua_pushstring(L, errmsg); |
jbe@112 | 803 return 2; |
jbe@112 | 804 } |
jbe@112 | 805 listener->fd = sock; |
jbe@118 | 806 listener->addrfam = AF_LOCAL; |
jbe@112 | 807 listener->nonblocking = -1; |
jbe@112 | 808 return 1; |
jbe@112 | 809 } |
jbe@112 | 810 |
jbe@108 | 811 static int moonbr_io_tcplisten(lua_State *L) { |
jbe@108 | 812 moonbr_io_listener_t *listener; |
jbe@108 | 813 const char *host, *port; |
jbe@108 | 814 struct addrinfo hints = { 0, }; |
jbe@108 | 815 struct addrinfo *res, *addrinfo; |
jbe@108 | 816 int errcode; |
jbe@108 | 817 int sock; |
jbe@108 | 818 host = luaL_optstring(L, 1, NULL); |
jbe@108 | 819 port = luaL_checkstring(L, 2); |
jbe@108 | 820 listener = lua_newuserdata(L, sizeof(moonbr_io_listener_t)); |
jbe@117 | 821 listener->fd = -1; |
jbe@108 | 822 luaL_setmetatable(L, MOONBR_IO_LISTENER_MT_REGKEY); |
jbe@108 | 823 hints.ai_family = AF_UNSPEC; |
jbe@108 | 824 hints.ai_socktype = SOCK_STREAM; |
jbe@108 | 825 hints.ai_protocol = IPPROTO_TCP; |
jbe@108 | 826 hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE; |
jbe@108 | 827 errcode = getaddrinfo(host, port, &hints, &res); |
jbe@108 | 828 if (errcode) { |
jbe@108 | 829 freeaddrinfo(res); |
jbe@108 | 830 if (errcode == EAI_SYSTEM) { |
jbe@108 | 831 moonbr_io_errmsg(); |
jbe@108 | 832 lua_pushnil(L); |
jbe@108 | 833 lua_pushfstring(L, "%s: %s", gai_strerror(errcode), errmsg); |
jbe@108 | 834 } else { |
jbe@108 | 835 lua_pushnil(L); |
jbe@108 | 836 lua_pushstring(L, gai_strerror(errcode)); |
jbe@108 | 837 } |
jbe@108 | 838 return 2; |
jbe@108 | 839 } |
jbe@108 | 840 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) { |
jbe@108 | 841 if (addrinfo->ai_family == PF_INET6) goto moonbr_io_tcpconnect_found; |
jbe@108 | 842 } |
jbe@108 | 843 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) { |
jbe@108 | 844 if (addrinfo->ai_family == PF_INET) goto moonbr_io_tcpconnect_found; |
jbe@108 | 845 } |
jbe@108 | 846 addrinfo = res; |
jbe@108 | 847 moonbr_io_tcpconnect_found: |
jbe@118 | 848 listener->addrfam = addrinfo->ai_family; |
jbe@108 | 849 sock = socket( |
jbe@108 | 850 addrinfo->ai_family, |
jbe@108 | 851 addrinfo->ai_socktype | SOCK_CLOEXEC, |
jbe@108 | 852 addrinfo->ai_protocol |
jbe@108 | 853 ); |
jbe@108 | 854 if (sock < 0) { |
jbe@108 | 855 moonbr_io_errmsg(); |
jbe@108 | 856 freeaddrinfo(res); |
jbe@108 | 857 lua_pushnil(L); |
jbe@108 | 858 lua_pushstring(L, errmsg); |
jbe@108 | 859 return 2; |
jbe@108 | 860 } |
jbe@120 | 861 { |
jbe@120 | 862 static const int reuseval = 1; |
jbe@120 | 863 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseval, sizeof(reuseval))) { |
jbe@120 | 864 moonbr_io_errmsg(); |
jbe@120 | 865 freeaddrinfo(res); |
jbe@120 | 866 close(sock); |
jbe@120 | 867 lua_pushnil(L); |
jbe@120 | 868 lua_pushfstring(L, "Error while setting SO_REUSEADDR with setsockopt: %s", errmsg); |
jbe@120 | 869 return 2; |
jbe@120 | 870 } |
jbe@120 | 871 } |
jbe@108 | 872 if (bind(sock, addrinfo->ai_addr, addrinfo->ai_addrlen)) { |
jbe@108 | 873 moonbr_io_errmsg(); |
jbe@108 | 874 freeaddrinfo(res); |
jbe@108 | 875 close(sock); |
jbe@108 | 876 lua_pushnil(L); |
jbe@108 | 877 lua_pushstring(L, errmsg); |
jbe@108 | 878 return 2; |
jbe@108 | 879 } |
jbe@108 | 880 freeaddrinfo(res); |
jbe@108 | 881 if (listen(sock, MOONBR_IO_LISTEN_BACKLOG)) { |
jbe@108 | 882 moonbr_io_errmsg(); |
jbe@108 | 883 close(sock); |
jbe@108 | 884 lua_pushnil(L); |
jbe@108 | 885 lua_pushstring(L, errmsg); |
jbe@108 | 886 return 2; |
jbe@108 | 887 } |
jbe@108 | 888 listener->fd = sock; |
jbe@108 | 889 listener->nonblocking = -1; |
jbe@108 | 890 return 1; |
jbe@108 | 891 } |
jbe@108 | 892 |
jbe@108 | 893 static int moonbr_io_accept_impl(lua_State *L, int nonblocking) { |
jbe@108 | 894 moonbr_io_listener_t *listener; |
jbe@108 | 895 int fd; |
jbe@108 | 896 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY); |
jbe@108 | 897 if (listener->fd < 0) luaL_error(L, "Attempt to use a closed listener"); |
jbe@108 | 898 if (listener->nonblocking != nonblocking) { |
jbe@108 | 899 int flags; |
jbe@108 | 900 flags = fcntl(listener->fd, F_GETFL, 0); |
jbe@108 | 901 if (flags == -1) { |
jbe@108 | 902 moonbr_io_errmsg(); |
jbe@108 | 903 close(listener->fd); |
jbe@108 | 904 listener->fd = -1; |
jbe@108 | 905 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg); |
jbe@108 | 906 } |
jbe@108 | 907 if (nonblocking) flags |= O_NONBLOCK; |
jbe@108 | 908 else flags &= ~O_NONBLOCK; |
jbe@108 | 909 if (fcntl(listener->fd, F_SETFL, flags) == -1) { |
jbe@108 | 910 moonbr_io_errmsg(); |
jbe@108 | 911 close(listener->fd); |
jbe@108 | 912 listener->fd = -1; |
jbe@108 | 913 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg); |
jbe@108 | 914 } |
jbe@108 | 915 listener->nonblocking = nonblocking; |
jbe@108 | 916 } |
jbe@108 | 917 while (1) { |
jbe@108 | 918 fd = accept4(listener->fd, NULL, NULL, SOCK_CLOEXEC); |
jbe@108 | 919 if (fd < 0) { |
jbe@108 | 920 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) { |
jbe@108 | 921 lua_pushboolean(L, 0); |
jbe@108 | 922 lua_pushliteral(L, "No incoming connection pending"); |
jbe@108 | 923 return 2; |
jbe@108 | 924 } else if (errno != EINTR) { |
jbe@108 | 925 moonbr_io_errmsg(); |
jbe@108 | 926 lua_pushnil(L); |
jbe@108 | 927 lua_pushstring(L, errmsg); |
jbe@108 | 928 return 2; |
jbe@108 | 929 } |
jbe@108 | 930 } else { |
jbe@108 | 931 moonbr_io_pushhandle(L, fd); |
jbe@108 | 932 return 1; |
jbe@108 | 933 } |
jbe@108 | 934 } |
jbe@108 | 935 } |
jbe@108 | 936 |
jbe@108 | 937 static int moonbr_io_accept(lua_State *L) { |
jbe@108 | 938 return moonbr_io_accept_impl(L, 0); |
jbe@108 | 939 } |
jbe@108 | 940 |
jbe@108 | 941 static int moonbr_io_accept_nb(lua_State *L) { |
jbe@108 | 942 return moonbr_io_accept_impl(L, 1); |
jbe@108 | 943 } |
jbe@108 | 944 |
jbe@108 | 945 static int moonbr_io_unlisten(lua_State *L) { |
jbe@108 | 946 moonbr_io_listener_t *listener; |
jbe@118 | 947 struct sockaddr_un addr; |
jbe@118 | 948 socklen_t addrlen; |
jbe@118 | 949 struct stat sb; |
jbe@108 | 950 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY); |
jbe@108 | 951 if (listener->fd < 0) luaL_error(L, "Attempt to close a closed listener"); |
jbe@118 | 952 addrlen = sizeof(addr); |
jbe@118 | 953 if (getsockname(listener->fd, (struct sockaddr *)&addr, &addrlen)) addrlen = 0; |
jbe@108 | 954 if (close(listener->fd)) { |
jbe@108 | 955 moonbr_io_errmsg(); |
jbe@108 | 956 listener->fd = -1; |
jbe@118 | 957 if (addrlen && addrlen <= sizeof(addr)) { |
jbe@118 | 958 if (stat(addr.sun_path, &sb) == 0) { |
jbe@118 | 959 if (S_ISSOCK(sb.st_mode)) unlink(addr.sun_path); |
jbe@118 | 960 } |
jbe@118 | 961 } |
jbe@108 | 962 lua_pushnil(L); |
jbe@108 | 963 lua_pushstring(L, errmsg); |
jbe@108 | 964 return 2; |
jbe@108 | 965 } |
jbe@108 | 966 listener->fd = -1; |
jbe@118 | 967 if (addrlen && addrlen <= sizeof(addr)) { |
jbe@118 | 968 if (stat(addr.sun_path, &sb) == 0) { |
jbe@118 | 969 if (S_ISSOCK(sb.st_mode)) unlink(addr.sun_path); |
jbe@118 | 970 } |
jbe@118 | 971 } |
jbe@108 | 972 lua_pushboolean(L, 1); |
jbe@108 | 973 return 1; |
jbe@108 | 974 } |
jbe@108 | 975 |
jbe@108 | 976 static int moonbr_io_listenergc(lua_State *L) { |
jbe@108 | 977 moonbr_io_listener_t *listener; |
jbe@108 | 978 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY); |
jbe@117 | 979 if (listener->fd >= 0) close(listener->fd); |
jbe@108 | 980 listener->fd = -1; |
jbe@108 | 981 return 0; |
jbe@108 | 982 } |
jbe@108 | 983 |
jbe@106 | 984 static int moonbr_io_poll(lua_State *L) { |
jbe@106 | 985 moonbr_io_handle_t *handle; |
jbe@108 | 986 moonbr_io_listener_t *listener; |
jbe@106 | 987 int fd, isnum; |
jbe@106 | 988 int nfds = 0; |
jbe@106 | 989 fd_set readfds, writefds, exceptfds; |
jbe@106 | 990 struct timeval timeout = {0, }; |
jbe@106 | 991 int status; |
jbe@106 | 992 FD_ZERO(&readfds); |
jbe@106 | 993 FD_ZERO(&writefds); |
jbe@106 | 994 FD_ZERO(&exceptfds); |
jbe@106 | 995 if (!lua_isnoneornil(L, 1)) { |
jbe@106 | 996 luaL_checktype(L, 1, LUA_TTABLE); |
jbe@106 | 997 for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) { |
jbe@106 | 998 if (lua_toboolean(L, -1)) { |
jbe@106 | 999 handle = luaL_testudata(L, -2, MOONBR_IO_HANDLE_MT_REGKEY); |
jbe@106 | 1000 if (handle) { |
jbe@109 | 1001 if (handle->closed) luaL_error(L, "Attempt to poll a closed connection"); |
jbe@106 | 1002 fd = handle->fd; |
jbe@122 | 1003 if ( |
jbe@122 | 1004 fd < 0 || /* fake EOF to simulate shutdown if fd < 0 */ |
jbe@122 | 1005 handle->readbufin != handle->readbufout /* data pending in buffer */ |
jbe@122 | 1006 ) { |
jbe@109 | 1007 lua_pushboolean(L, 1); |
jbe@109 | 1008 return 1; |
jbe@109 | 1009 } |
jbe@106 | 1010 } else { |
jbe@108 | 1011 listener = luaL_testudata(L, -2, MOONBR_IO_LISTENER_MT_REGKEY); |
jbe@108 | 1012 if (listener) { |
jbe@108 | 1013 fd = listener->fd; |
jbe@108 | 1014 if (fd < 0) luaL_error(L, "Attempt to poll a closed listener"); |
jbe@108 | 1015 } else { |
jbe@108 | 1016 fd = lua_tointegerx(L, -2, &isnum); |
jbe@108 | 1017 if (!isnum) luaL_error(L, "Expected integer (file descriptor), I/O handle, or listener in table key"); |
jbe@108 | 1018 } |
jbe@106 | 1019 } |
jbe@106 | 1020 FD_SET(fd, &readfds); |
jbe@106 | 1021 if (fd+1 > nfds) nfds = fd+1; |
jbe@106 | 1022 } |
jbe@106 | 1023 } |
jbe@106 | 1024 } |
jbe@106 | 1025 if (!lua_isnoneornil(L, 2)) { |
jbe@106 | 1026 luaL_checktype(L, 2, LUA_TTABLE); |
jbe@106 | 1027 for (lua_pushnil(L); lua_next(L, 2); lua_pop(L, 1)) { |
jbe@106 | 1028 if (lua_toboolean(L, -1)) { |
jbe@106 | 1029 handle = luaL_testudata(L, -2, MOONBR_IO_HANDLE_MT_REGKEY); |
jbe@106 | 1030 if (handle) { |
jbe@109 | 1031 if (handle->closed) luaL_error(L, "Attempt to poll a closed connection"); |
jbe@109 | 1032 if (handle->finished) luaL_error(L, "Attempt to write-poll a finished connection"); |
jbe@106 | 1033 fd = handle->fd; |
jbe@106 | 1034 } else { |
jbe@108 | 1035 listener = luaL_testudata(L, -2, MOONBR_IO_LISTENER_MT_REGKEY); |
jbe@109 | 1036 if (listener) luaL_error(L, "Attempt to write-poll a listener"); |
jbe@109 | 1037 fd = lua_tointegerx(L, -2, &isnum); |
jbe@109 | 1038 if (!isnum) luaL_error(L, "Expected integer (file descriptor) or I/O handle in table key"); |
jbe@106 | 1039 } |
jbe@106 | 1040 FD_SET(fd, &writefds); |
jbe@106 | 1041 if (fd+1 > nfds) nfds = fd+1; |
jbe@106 | 1042 } |
jbe@106 | 1043 } |
jbe@106 | 1044 } |
jbe@106 | 1045 if (!lua_isnoneornil(L, 3)) { |
jbe@106 | 1046 lua_Number n; |
jbe@106 | 1047 n = lua_tonumberx(L, 3, &isnum); |
jbe@106 | 1048 if (isnum && n>=0 && n<100000000) { |
jbe@106 | 1049 timeout.tv_sec = n; |
jbe@106 | 1050 timeout.tv_usec = 1e6 * (n - timeout.tv_sec); |
jbe@106 | 1051 } else { |
jbe@106 | 1052 luaL_argcheck(L, 0, 3, "not a valid timeout"); |
jbe@106 | 1053 } |
jbe@106 | 1054 status = select(nfds, &readfds, &writefds, &exceptfds, &timeout); |
jbe@106 | 1055 } else { |
jbe@106 | 1056 status = select(nfds, &readfds, &writefds, &exceptfds, NULL); |
jbe@106 | 1057 } |
jbe@106 | 1058 if (status == -1) { |
jbe@106 | 1059 if (errno == EINTR) { |
jbe@106 | 1060 lua_pushboolean(L, 0); |
jbe@106 | 1061 lua_pushliteral(L, "Signal received while polling file descriptors"); |
jbe@106 | 1062 return 2; |
jbe@106 | 1063 } else { |
jbe@106 | 1064 moonbr_io_errmsg(); |
jbe@106 | 1065 return luaL_error(L, "Unexpected error during \"select\" system call: %s", errmsg); |
jbe@106 | 1066 } |
jbe@106 | 1067 } else if (status == 0) { |
jbe@106 | 1068 lua_pushboolean(L, 0); |
jbe@106 | 1069 lua_pushliteral(L, "Timeout while polling file descriptors"); |
jbe@106 | 1070 return 2; |
jbe@106 | 1071 } else { |
jbe@106 | 1072 lua_pushboolean(L, 1); |
jbe@106 | 1073 return 1; |
jbe@106 | 1074 } |
jbe@106 | 1075 } |
jbe@106 | 1076 |
jbe@115 | 1077 static int moonbr_io_timeref(lua_State *L) { |
jbe@115 | 1078 lua_Number sub; |
jbe@115 | 1079 struct timespec tp; |
jbe@115 | 1080 sub = luaL_optnumber(L, 1, 0); |
jbe@115 | 1081 if (clock_gettime(CLOCK_MONOTONIC, &tp)) { |
jbe@115 | 1082 return luaL_error(L, "Could not access CLOCK_MONOTONIC"); |
jbe@115 | 1083 } |
jbe@115 | 1084 lua_pushnumber(L, tp.tv_sec + tp.tv_nsec / 1.0e9 - sub); |
jbe@115 | 1085 return 1; |
jbe@115 | 1086 } |
jbe@115 | 1087 |
jbe@79 | 1088 static const struct luaL_Reg moonbr_io_handle_methods[] = { |
jbe@85 | 1089 {"read", moonbr_io_read}, |
jbe@85 | 1090 {"read_nb", moonbr_io_read_nb}, |
jbe@86 | 1091 {"drain", moonbr_io_drain}, |
jbe@86 | 1092 {"drain_nb", moonbr_io_drain_nb}, |
jbe@80 | 1093 {"write", moonbr_io_write}, |
jbe@81 | 1094 {"write_nb", moonbr_io_write_nb}, |
jbe@80 | 1095 {"flush", moonbr_io_flush}, |
jbe@81 | 1096 {"flush_nb", moonbr_io_flush_nb}, |
jbe@88 | 1097 {"finish", moonbr_io_finish}, |
jbe@87 | 1098 {"close", moonbr_io_close}, |
jbe@85 | 1099 {"reset", moonbr_io_reset}, |
jbe@79 | 1100 {NULL, NULL} |
jbe@79 | 1101 }; |
jbe@79 | 1102 |
jbe@79 | 1103 static const struct luaL_Reg moonbr_io_handle_metamethods[] = { |
jbe@79 | 1104 {"__index", moonbr_io_handleindex}, |
jbe@79 | 1105 {"__newindex", moonbr_io_handlenewindex}, |
jbe@108 | 1106 {"__gc", moonbr_io_handlegc}, |
jbe@108 | 1107 {NULL, NULL} |
jbe@108 | 1108 }; |
jbe@108 | 1109 |
jbe@108 | 1110 static const struct luaL_Reg moonbr_io_listener_methods[] = { |
jbe@108 | 1111 {"accept", moonbr_io_accept}, |
jbe@108 | 1112 {"accept_nb", moonbr_io_accept_nb}, |
jbe@108 | 1113 {"close", moonbr_io_unlisten}, |
jbe@108 | 1114 {NULL, NULL} |
jbe@108 | 1115 }; |
jbe@108 | 1116 |
jbe@108 | 1117 static const struct luaL_Reg moonbr_io_listener_metamethods[] = { |
jbe@108 | 1118 {"__gc", moonbr_io_listenergc}, |
jbe@79 | 1119 {NULL, NULL} |
jbe@79 | 1120 }; |
jbe@79 | 1121 |
jbe@79 | 1122 static const struct luaL_Reg moonbr_io_module_funcs[] = { |
jbe@111 | 1123 {"localconnect", moonbr_io_localconnect}, |
jbe@111 | 1124 {"localconnect_nb", moonbr_io_localconnect_nb}, |
jbe@98 | 1125 {"tcpconnect", moonbr_io_tcpconnect}, |
jbe@99 | 1126 {"tcpconnect_nb", moonbr_io_tcpconnect_nb}, |
jbe@112 | 1127 {"locallisten", moonbr_io_locallisten}, |
jbe@108 | 1128 {"tcplisten", moonbr_io_tcplisten}, |
jbe@106 | 1129 {"poll", moonbr_io_poll}, |
jbe@115 | 1130 {"timeref", moonbr_io_timeref}, |
jbe@79 | 1131 {NULL, NULL} |
jbe@79 | 1132 }; |
jbe@79 | 1133 |
jbe@79 | 1134 int luaopen_moonbridge_io(lua_State *L) { |
jbe@79 | 1135 |
jbe@113 | 1136 signal(SIGPIPE, SIG_IGN); /* generate I/O errors instead of signal 13 */ |
jbe@113 | 1137 |
jbe@80 | 1138 lua_newtable(L); // module |
jbe@80 | 1139 |
jbe@79 | 1140 lua_newtable(L); // public metatable |
jbe@79 | 1141 lua_newtable(L); // handle methods |
jbe@79 | 1142 luaL_setfuncs(L, moonbr_io_handle_methods, 0); |
jbe@80 | 1143 lua_pushvalue(L, -1); |
jbe@108 | 1144 lua_setfield(L, -4, "prototype_handle"); |
jbe@79 | 1145 lua_setfield(L, -2, "__index"); |
jbe@79 | 1146 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY); |
jbe@79 | 1147 |
jbe@79 | 1148 lua_newtable(L); // handle metatable |
jbe@79 | 1149 luaL_setfuncs(L, moonbr_io_handle_metamethods, 0); |
jbe@79 | 1150 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_MT_REGKEY); |
jbe@79 | 1151 |
jbe@108 | 1152 lua_newtable(L); // listener metatable |
jbe@108 | 1153 luaL_setfuncs(L, moonbr_io_listener_metamethods, 0); |
jbe@108 | 1154 lua_newtable(L); // listener methods |
jbe@108 | 1155 luaL_setfuncs(L, moonbr_io_listener_methods, 0); |
jbe@108 | 1156 lua_pushvalue(L, -1); |
jbe@108 | 1157 lua_setfield(L, -4, "prototype_listener"); |
jbe@108 | 1158 lua_setfield(L, -2, "__index"); |
jbe@108 | 1159 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_LISTENER_MT_REGKEY); |
jbe@108 | 1160 |
jbe@79 | 1161 luaL_setfuncs(L, moonbr_io_module_funcs, 0); |
jbe@79 | 1162 return 1; |
jbe@79 | 1163 |
jbe@79 | 1164 } |
jbe@79 | 1165 |