mirror of
https://github.com/lunarmodules/luasocket.git
synced 2024-12-26 12:28:21 +01:00
Add support for serial devices as socket streams on unix.
This commit is contained in:
parent
3b19f2a7ed
commit
b1f7c349b5
1
config
1
config
@ -11,6 +11,7 @@ MIME_V=1.0.2
|
|||||||
SOCKET_SO=socket.$(EXT).$(SOCKET_V)
|
SOCKET_SO=socket.$(EXT).$(SOCKET_V)
|
||||||
MIME_SO=mime.$(EXT).$(MIME_V)
|
MIME_SO=mime.$(EXT).$(MIME_V)
|
||||||
UNIX_SO=unix.$(EXT)
|
UNIX_SO=unix.$(EXT)
|
||||||
|
SERIAL_SO=serial.$(EXT)
|
||||||
|
|
||||||
#------
|
#------
|
||||||
# Lua includes and libraries
|
# Lua includes and libraries
|
||||||
|
1
makefile
1
makefile
@ -48,6 +48,7 @@ install: all
|
|||||||
|
|
||||||
install-unix: install all-unix
|
install-unix: install all-unix
|
||||||
cd src; $(INSTALL_EXEC) $(UNIX_SO) $(INSTALL_SOCKET_LIB)/$(UNIX_SO)
|
cd src; $(INSTALL_EXEC) $(UNIX_SO) $(INSTALL_SOCKET_LIB)/$(UNIX_SO)
|
||||||
|
cd src; $(INSTALL_EXEC) $(SERIAL_SO) $(INSTALL_SOCKET_LIB)/$(SERIAL_SO)
|
||||||
|
|
||||||
#------
|
#------
|
||||||
# End of makefile
|
# End of makefile
|
||||||
|
18
src/makefile
18
src/makefile
@ -47,6 +47,17 @@ UNIX_OBJS:=\
|
|||||||
usocket.o \
|
usocket.o \
|
||||||
unix.o
|
unix.o
|
||||||
|
|
||||||
|
#------
|
||||||
|
# Modules belonging to serial (device streams)
|
||||||
|
#
|
||||||
|
SERIAL_OBJS:=\
|
||||||
|
buffer.o \
|
||||||
|
auxiliar.o \
|
||||||
|
timeout.o \
|
||||||
|
io.o \
|
||||||
|
usocket.o \
|
||||||
|
serial.o
|
||||||
|
|
||||||
all: $(SOCKET_SO) $(MIME_SO)
|
all: $(SOCKET_SO) $(MIME_SO)
|
||||||
|
|
||||||
$(SOCKET_SO): $(SOCKET_OBJS)
|
$(SOCKET_SO): $(SOCKET_OBJS)
|
||||||
@ -55,11 +66,14 @@ $(SOCKET_SO): $(SOCKET_OBJS)
|
|||||||
$(MIME_SO): $(MIME_OBJS)
|
$(MIME_SO): $(MIME_OBJS)
|
||||||
$(LD) $(LDFLAGS) -o $@ $(MIME_OBJS)
|
$(LD) $(LDFLAGS) -o $@ $(MIME_OBJS)
|
||||||
|
|
||||||
all-unix: all $(UNIX_SO)
|
all-unix: all $(UNIX_SO) $(SERIAL_SO)
|
||||||
|
|
||||||
$(UNIX_SO): $(UNIX_OBJS)
|
$(UNIX_SO): $(UNIX_OBJS)
|
||||||
$(LD) $(LDFLAGS) -o $@ $(UNIX_OBJS)
|
$(LD) $(LDFLAGS) -o $@ $(UNIX_OBJS)
|
||||||
|
|
||||||
|
$(SERIAL_SO): $(SERIAL_OBJS)
|
||||||
|
$(LD) $(LDFLAGS) -o $@ $(SERIAL_OBJS)
|
||||||
|
|
||||||
#------
|
#------
|
||||||
# List of dependencies
|
# List of dependencies
|
||||||
#
|
#
|
||||||
@ -74,6 +88,8 @@ mime.o: mime.c mime.h
|
|||||||
options.o: options.c auxiliar.h options.h socket.h io.h timeout.h \
|
options.o: options.c auxiliar.h options.h socket.h io.h timeout.h \
|
||||||
usocket.h inet.h
|
usocket.h inet.h
|
||||||
select.o: select.c socket.h io.h timeout.h usocket.h select.h
|
select.o: select.c socket.h io.h timeout.h usocket.h select.h
|
||||||
|
serial.o: serial.c auxiliar.h socket.h io.h timeout.h usocket.h \
|
||||||
|
unix.h buffer.h
|
||||||
tcp.o: tcp.c auxiliar.h socket.h io.h timeout.h usocket.h inet.h \
|
tcp.o: tcp.c auxiliar.h socket.h io.h timeout.h usocket.h inet.h \
|
||||||
options.h tcp.h buffer.h
|
options.h tcp.h buffer.h
|
||||||
timeout.o: timeout.c auxiliar.h timeout.h
|
timeout.o: timeout.c auxiliar.h timeout.h
|
||||||
|
183
src/serial.c
Normal file
183
src/serial.c
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
/*=========================================================================*\
|
||||||
|
* Serial stream
|
||||||
|
* LuaSocket toolkit
|
||||||
|
\*=========================================================================*/
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "lua.h"
|
||||||
|
#include "lauxlib.h"
|
||||||
|
|
||||||
|
#include "auxiliar.h"
|
||||||
|
#include "socket.h"
|
||||||
|
#include "options.h"
|
||||||
|
#include "unix.h"
|
||||||
|
#include <sys/un.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
Reuses userdata definition from unix.h, since it is useful for all
|
||||||
|
stream-like objects.
|
||||||
|
|
||||||
|
If we stored the serial path for use in error messages or userdata
|
||||||
|
printing, we might need our own userdata definition.
|
||||||
|
|
||||||
|
Group usage is semi-inherited from unix.c, but unnecessary since we
|
||||||
|
have only one object type.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*=========================================================================*\
|
||||||
|
* Internal function prototypes
|
||||||
|
\*=========================================================================*/
|
||||||
|
static int global_create(lua_State *L);
|
||||||
|
static int meth_send(lua_State *L);
|
||||||
|
static int meth_receive(lua_State *L);
|
||||||
|
static int meth_close(lua_State *L);
|
||||||
|
static int meth_settimeout(lua_State *L);
|
||||||
|
static int meth_getfd(lua_State *L);
|
||||||
|
static int meth_setfd(lua_State *L);
|
||||||
|
static int meth_dirty(lua_State *L);
|
||||||
|
static int meth_getstats(lua_State *L);
|
||||||
|
static int meth_setstats(lua_State *L);
|
||||||
|
|
||||||
|
/* serial object methods */
|
||||||
|
static luaL_reg un[] = {
|
||||||
|
{"__gc", meth_close},
|
||||||
|
{"__tostring", auxiliar_tostring},
|
||||||
|
{"close", meth_close},
|
||||||
|
{"dirty", meth_dirty},
|
||||||
|
{"getfd", meth_getfd},
|
||||||
|
{"getstats", meth_getstats},
|
||||||
|
{"setstats", meth_setstats},
|
||||||
|
{"receive", meth_receive},
|
||||||
|
{"send", meth_send},
|
||||||
|
{"setfd", meth_setfd},
|
||||||
|
{"settimeout", meth_settimeout},
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* our socket creation function */
|
||||||
|
static luaL_reg func[] = {
|
||||||
|
{"serial", global_create},
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* Initializes module
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
int luaopen_socket_serial(lua_State *L) {
|
||||||
|
/* create classes */
|
||||||
|
auxiliar_newclass(L, "serial{client}", un);
|
||||||
|
/* create class groups */
|
||||||
|
auxiliar_add2group(L, "serial{client}", "serial{any}");
|
||||||
|
/* make sure the function ends up in the package table */
|
||||||
|
luaL_openlib(L, "socket", func, 0);
|
||||||
|
/* return the function instead of the 'socket' table */
|
||||||
|
lua_pushstring(L, "serial");
|
||||||
|
lua_gettable(L, -2);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*=========================================================================*\
|
||||||
|
* Lua methods
|
||||||
|
\*=========================================================================*/
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* Just call buffered IO methods
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
static int meth_send(lua_State *L) {
|
||||||
|
p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
|
||||||
|
return buffer_meth_send(L, &un->buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int meth_receive(lua_State *L) {
|
||||||
|
p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
|
||||||
|
return buffer_meth_receive(L, &un->buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int meth_getstats(lua_State *L) {
|
||||||
|
p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
|
||||||
|
return buffer_meth_getstats(L, &un->buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int meth_setstats(lua_State *L) {
|
||||||
|
p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
|
||||||
|
return buffer_meth_setstats(L, &un->buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* Select support methods
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
static int meth_getfd(lua_State *L) {
|
||||||
|
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
|
||||||
|
lua_pushnumber(L, (int) un->sock);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this is very dangerous, but can be handy for those that are brave enough */
|
||||||
|
static int meth_setfd(lua_State *L) {
|
||||||
|
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
|
||||||
|
un->sock = (t_socket) luaL_checknumber(L, 2);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int meth_dirty(lua_State *L) {
|
||||||
|
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
|
||||||
|
lua_pushboolean(L, !buffer_isempty(&un->buf));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* Closes socket used by object
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
static int meth_close(lua_State *L)
|
||||||
|
{
|
||||||
|
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
|
||||||
|
socket_destroy(&un->sock);
|
||||||
|
lua_pushnumber(L, 1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* Just call tm methods
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
static int meth_settimeout(lua_State *L) {
|
||||||
|
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
|
||||||
|
return timeout_meth_settimeout(L, &un->tm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*=========================================================================*\
|
||||||
|
* Library functions
|
||||||
|
\*=========================================================================*/
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* Creates a serial object
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
static int global_create(lua_State *L) {
|
||||||
|
const char* path = luaL_checkstring(L, 1);
|
||||||
|
|
||||||
|
/* allocate unix object */
|
||||||
|
p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix));
|
||||||
|
|
||||||
|
/* open serial device */
|
||||||
|
t_socket sock = open(path, O_NOCTTY|O_RDWR);
|
||||||
|
|
||||||
|
/*printf("open %s on %d\n", path, sock);*/
|
||||||
|
|
||||||
|
if (sock < 0) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, socket_strerror(errno));
|
||||||
|
lua_pushnumber(L, errno);
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
/* set its type as client object */
|
||||||
|
auxiliar_setclass(L, "serial{client}", -1);
|
||||||
|
/* initialize remaining structure fields */
|
||||||
|
socket_setnonblocking(&sock);
|
||||||
|
un->sock = sock;
|
||||||
|
io_init(&un->io, (p_send) socket_write, (p_recv) socket_read,
|
||||||
|
(p_error) socket_ioerror, &un->sock);
|
||||||
|
timeout_init(&un->tm, -1, -1);
|
||||||
|
buffer_init(&un->buf, &un->io, &un->tm);
|
||||||
|
return 1;
|
||||||
|
}
|
@ -68,6 +68,9 @@ const char *socket_strerror(int err);
|
|||||||
int socket_send(p_socket ps, const char *data, size_t count,
|
int socket_send(p_socket ps, const char *data, size_t count,
|
||||||
size_t *sent, p_timeout tm);
|
size_t *sent, p_timeout tm);
|
||||||
int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm);
|
int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm);
|
||||||
|
int socket_write(p_socket ps, const char *data, size_t count,
|
||||||
|
size_t *sent, p_timeout tm);
|
||||||
|
int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm);
|
||||||
const char *socket_ioerror(p_socket ps, int err);
|
const char *socket_ioerror(p_socket ps, int err);
|
||||||
|
|
||||||
int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp);
|
int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp);
|
||||||
|
@ -300,6 +300,66 @@ int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got,
|
|||||||
return IO_UNKNOWN;
|
return IO_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* Write with timeout
|
||||||
|
*
|
||||||
|
* socket_read and socket_write are cut-n-paste of socket_send and socket_recv,
|
||||||
|
* with send/recv replaced with write/read. We can't just use write/read
|
||||||
|
* in the socket version, because behaviour when size is zero is different.
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
int socket_write(p_socket ps, const char *data, size_t count,
|
||||||
|
size_t *sent, p_timeout tm)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
*sent = 0;
|
||||||
|
/* avoid making system calls on closed sockets */
|
||||||
|
if (*ps == SOCKET_INVALID) return IO_CLOSED;
|
||||||
|
/* loop until we send something or we give up on error */
|
||||||
|
for ( ;; ) {
|
||||||
|
long put = (long) write(*ps, data, count);
|
||||||
|
/* if we sent anything, we are done */
|
||||||
|
if (put >= 0) {
|
||||||
|
*sent = put;
|
||||||
|
return IO_DONE;
|
||||||
|
}
|
||||||
|
err = errno;
|
||||||
|
/* EPIPE means the connection was closed */
|
||||||
|
if (err == EPIPE) return IO_CLOSED;
|
||||||
|
/* we call was interrupted, just try again */
|
||||||
|
if (err == EINTR) continue;
|
||||||
|
/* if failed fatal reason, report error */
|
||||||
|
if (err != EAGAIN) return err;
|
||||||
|
/* wait until we can send something or we timeout */
|
||||||
|
if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
|
||||||
|
}
|
||||||
|
/* can't reach here */
|
||||||
|
return IO_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* Read with timeout
|
||||||
|
* See note for socket_write
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm) {
|
||||||
|
int err;
|
||||||
|
*got = 0;
|
||||||
|
if (*ps == SOCKET_INVALID) return IO_CLOSED;
|
||||||
|
for ( ;; ) {
|
||||||
|
long taken = (long) read(*ps, data, count);
|
||||||
|
if (taken > 0) {
|
||||||
|
*got = taken;
|
||||||
|
return IO_DONE;
|
||||||
|
}
|
||||||
|
err = errno;
|
||||||
|
if (taken == 0) return IO_CLOSED;
|
||||||
|
if (err == EINTR) continue;
|
||||||
|
if (err != EAGAIN) return err;
|
||||||
|
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
|
||||||
|
}
|
||||||
|
return IO_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Put socket into blocking mode
|
* Put socket into blocking mode
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
|
Loading…
Reference in New Issue
Block a user