aboutsummaryrefslogtreecommitdiff
path: root/jim-aio.c
diff options
context:
space:
mode:
authoroharboe <oharboe>2008-07-14 13:29:24 +0000
committeroharboe <oharboe>2008-07-14 13:29:24 +0000
commitec16a897b19c1cebd1b6babdf107e59a14efdd45 (patch)
tree377c6d5117ab43ca790b834bb19b6679726e8d6b /jim-aio.c
parentdbbb7b6eafc60d62e944d134bc41a8ea41185c62 (diff)
downloadjimtcl-ec16a897b19c1cebd1b6babdf107e59a14efdd45.zip
jimtcl-ec16a897b19c1cebd1b6babdf107e59a14efdd45.tar.gz
jimtcl-ec16a897b19c1cebd1b6babdf107e59a14efdd45.tar.bz2
2008-07-13 Uwe Klein <uklein@klein-messgeraete.de>
* This adds open async, fileevents and sockets ( tcp server, client ) to jim-aio, using fileevents requires the jim-eventloop package .
Diffstat (limited to 'jim-aio.c')
-rw-r--r--jim-aio.c393
1 files changed, 383 insertions, 10 deletions
diff --git a/jim-aio.c b/jim-aio.c
index 203dc63..748eb2c 100644
--- a/jim-aio.c
+++ b/jim-aio.c
@@ -17,9 +17,16 @@
* limitations under the License.
*/
+#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
+#include <fcntl.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
#ifdef __ECOS
#include <pkgconf/jimtcl.h>
@@ -32,15 +39,51 @@
#else
#include "jim.h"
#endif
+#include "jim-eventloop.h"
#define AIO_CMD_LEN 128
#define AIO_BUF_LEN 1024
+#define AIO_KEEPOPEN 1
+#define AIO_FDOPEN 2
+
+
typedef struct AioFile {
FILE *fp;
- int keepOpen; /* If set, the file is not fclosed on cleanup (stdin, ...) */
+ int type;
+ int OpenFlags; /* AIO_KEEPOPEN? keep FILE*, AIO_FDOPEN? FILE* created via fdopen */
+ int fd;
+ int flags;
+ Jim_Obj *rEvent;
+ Jim_Obj *wEvent;
+ Jim_Obj *eEvent;
+ struct sockaddr sa;
+ struct hostent *he;
} AioFile;
+static int JimAioAcceptHelper(Jim_Interp *interp, AioFile *serv_af );
+
+static void JimAioFileEventFinalizer(Jim_Interp *interp, void *clientData)
+{
+ Jim_Obj *objPtr = clientData;
+
+ Jim_DecrRefCount(interp, objPtr);
+}
+
+static int JimAioFileEventHandler(Jim_Interp *interp, void *clientData, int mask)
+{
+ Jim_Obj *objPtr = clientData;
+ Jim_Obj *scrPtr = NULL ;
+ if ( mask == (JIM_EVENT_READABLE | JIM_EVENT_FEOF)) {
+ Jim_ListIndex(interp, objPtr, 1, &scrPtr, 0);
+ } else {
+ Jim_ListIndex(interp, objPtr, 0, &scrPtr, 0);
+ }
+ // fprintf(stderr,"mask:%d\n",mask);
+ Jim_EvalObjBackground(interp, scrPtr);
+ return 0;
+}
+
static void JimAioSetError(Jim_Interp *interp)
{
Jim_SetResultString(interp, strerror(errno), -1);
@@ -51,8 +94,25 @@ static void JimAioDelProc(Jim_Interp *interp, void *privData)
AioFile *af = privData;
JIM_NOTUSED(interp);
- if (!af->keepOpen)
+ if (!(af->OpenFlags & AIO_KEEPOPEN))
fclose(af->fp);
+ if (!af->OpenFlags == AIO_FDOPEN) // fp = fdopen(fd) !!
+ close(af->fd);
+ if (af->rEvent) { // remove existing EventHandlers
+ fprintf(stderr,"deleting ReadEvent\n");
+ Jim_DeleteFileHandler(interp,af->fp);
+ Jim_DecrRefCount(interp,af->rEvent);
+ }
+ if (af->wEvent) {
+ fprintf(stderr,"deleting WriteEvent\n");
+ Jim_DeleteFileHandler(interp,af->fp);
+ Jim_DecrRefCount(interp,af->wEvent);
+ }
+ if (af->eEvent) {
+ fprintf(stderr,"deleting ExceptionEvent\n");
+ Jim_DeleteFileHandler(interp,af->fp);
+ Jim_DecrRefCount(interp,af->eEvent);
+ }
Jim_Free(af);
}
@@ -64,10 +124,23 @@ static int JimAioHandlerCommand(Jim_Interp *interp, int argc,
AioFile *af = Jim_CmdPrivData(interp);
int option;
const char *options[] = {
- "close", "seek", "tell", "gets", "read", "puts", "flush", "eof", NULL
+ "close",
+ "seek", "tell",
+ "gets", "read", "puts",
+ "flush", "eof",
+ "ndelay",
+ "readable", "writable", "onexception",
+ "accept",
+ NULL
+ };
+ enum {OPT_CLOSE,
+ OPT_SEEK, OPT_TELL,
+ OPT_GETS, OPT_READ, OPT_PUTS,
+ OPT_FLUSH, OPT_EOF,
+ OPT_NDELAY,
+ OPT_READABLE, OPT_WRITABLE, OPT_EXCEPTION,
+ OPT_ACCEPT
};
- enum {OPT_CLOSE, OPT_SEEK, OPT_TELL, OPT_GETS, OPT_READ, OPT_PUTS,
- OPT_FLUSH, OPT_EOF};
if (argc < 2) {
Jim_WrongNumArgs(interp, 1, argv, "method ?args ...?");
@@ -152,7 +225,7 @@ static int JimAioHandlerCommand(Jim_Interp *interp, int argc,
if (!more)
break;
}
- if (ferror(af->fp)) {
+ if (ferror(af->fp) && (errno != EAGAIN)) {
/* I/O error */
Jim_IncrRefCount(objPtr);
Jim_DecrRefCount(interp, objPtr);
@@ -283,6 +356,101 @@ static int JimAioHandlerCommand(Jim_Interp *interp, int argc,
}
Jim_SetResult(interp, Jim_NewIntObj(interp, feof(af->fp)));
return JIM_OK;
+ } else if (option == OPT_NDELAY) {
+ int fmode = af->flags;
+
+ if (argc == 3) {
+ jim_wide wideValue;
+
+ if (Jim_GetWide(interp, argv[2], &wideValue) != JIM_OK)
+ return JIM_ERR;
+ switch (wideValue) {
+ case 0:
+ fmode &= ~O_NDELAY; break ;
+ case 1:
+ fmode |= O_NDELAY; break ;
+ }
+ fcntl(af->fd,F_SETFL,fmode);
+ af->flags = fmode;
+ }
+ Jim_SetResult(interp, Jim_NewIntObj(interp, (fmode & O_NONBLOCK)?1:0));
+ return JIM_OK;
+ } else if ( (option == OPT_READABLE)
+ || (option == OPT_WRITABLE)
+ || (option == OPT_EXCEPTION)
+ ) {
+ int mask = 0;
+ Jim_Obj **scrListObjpp = NULL;
+ Jim_Obj *listObj;
+ const char *dummy = NULL;
+ int scrlen = 0;
+
+ if (!(Jim_CreateFileHandler && Jim_DeleteFileHandler)) {
+ Jim_SetResultString(interp, "Eventloop not present ( or loaded too late ) !", -1);
+ return JIM_ERR;
+ }
+ switch (option) {
+ case OPT_READABLE: mask = JIM_EVENT_READABLE; scrListObjpp = &af->rEvent;
+ if (argc == 4) mask |= JIM_EVENT_FEOF ; break;
+ case OPT_WRITABLE: mask = JIM_EVENT_WRITABLE; scrListObjpp = &af->wEvent; break;
+ case OPT_EXCEPTION: mask = JIM_EVENT_EXCEPTION; scrListObjpp = &af->eEvent; break;
+ }
+ switch (argc) {
+ case 4:
+ case 3:
+ if (*scrListObjpp) {
+ Jim_DeleteFileHandler(interp, af->fp); //,mask);
+ Jim_DecrRefCount(interp, *scrListObjpp);
+ *scrListObjpp = NULL;
+ }
+ if ( dummy = Jim_GetString(argv[2],&scrlen),(scrlen == 0)) {
+ break;
+ } else {
+ *scrListObjpp = Jim_NewListObj(interp, NULL, 0);
+ Jim_IncrRefCount(*scrListObjpp);
+ // fprintf(stderr,"0 %p \n",*scrListObjpp);
+ listObj = argv[2];
+ if (Jim_IsShared(listObj))
+ listObj = Jim_DuplicateObj(interp, listObj);
+ // Jim_IncrRefCount(listObj);
+ // fprintf(stderr,"script:\"%s\" argp: %p objp1: %p\n", Jim_GetString(argv[2], NULL),argv[2],listObj);
+ // fprintf(stderr,"1");
+ Jim_ListAppendElement(interp,*scrListObjpp,listObj);
+ // fprintf(stderr,"2");
+ if (mask & JIM_EVENT_FEOF) {
+ listObj = argv[3];
+ if (Jim_IsShared(listObj))
+ listObj = Jim_DuplicateObj(interp, listObj);
+ // Jim_IncrRefCount(listObj);
+ // fprintf(stderr,"script:\"%s\" argp: %p objp2: %p\n", Jim_GetString(argv[3], NULL),argv[3],listObj);
+ // fprintf(stderr,"3");
+ Jim_ListAppendElement(interp,*scrListObjpp,listObj);
+ // fprintf(stderr,"4");
+ }
+ // fprintf(stderr,"event readable fd: %d, script:\"%s\" objp3: %p\n",af->fd, Jim_GetString(argv[2], NULL),argv[2]);
+ Jim_IncrRefCount(*scrListObjpp);
+ // fprintf(stderr,"6 %p \n",Jim_CreateFileHandler);
+ Jim_CreateFileHandler(interp, af->fp, mask,
+ JimAioFileEventHandler,
+ *scrListObjpp,
+ JimAioFileEventFinalizer);
+ // fprintf(stderr,"7");
+ }
+ break;
+ case 2:
+ if (*scrListObjpp)
+ Jim_SetResult(interp,*scrListObjpp);
+ return JIM_OK;
+ default:
+ Jim_WrongNumArgs(interp, 2, argv, "");
+ return JIM_ERR;
+ }
+ } else if (option == OPT_ACCEPT) {
+ int ret;
+ fprintf(stderr,"ACCEPT\n");
+ ret = JimAioAcceptHelper(interp,af);
+ fprintf(stderr,"ret %d\n",ret);
+ return (ret);
}
return JIM_OK;
}
@@ -296,9 +464,10 @@ static int JimAioOpenCommand(Jim_Interp *interp, int argc,
const char *mode = "r";
Jim_Obj *objPtr;
long fileId;
- const char *options[] = {"input", "output", "error"};
+ const char *options[] = {"input", "output", "error", NULL};
enum {OPT_INPUT, OPT_OUTPUT, OPT_ERROR};
- int keepOpen = 0, modeLen;
+ int OpenFlags = 0;
+ int modeLen;
if (argc != 2 && argc != 3) {
Jim_WrongNumArgs(interp, 1, argv, "filename ?mode?");
@@ -312,7 +481,7 @@ static int JimAioOpenCommand(Jim_Interp *interp, int argc,
if (Jim_GetEnum(interp, argv[2], options, &option, "standard channel",
JIM_ERRMSG) != JIM_OK)
return JIM_ERR;
- keepOpen = 1;
+ OpenFlags |= AIO_KEEPOPEN;
switch (option) {
case OPT_INPUT: fp = stdin; break;
case OPT_OUTPUT: fp = stdout; break;
@@ -338,13 +507,212 @@ static int JimAioOpenCommand(Jim_Interp *interp, int argc,
/* Create the file command */
af = Jim_Alloc(sizeof(*af));
af->fp = fp;
- af->keepOpen = keepOpen;
+ af->fd = fileno(fp);
+ af->flags = fcntl(af->fd,F_GETFL);
+ af->OpenFlags = OpenFlags;
+ // fprintf(stderr,"hallo\n");
+ af->rEvent = NULL;
+ af->wEvent = NULL;
+ af->eEvent = NULL;
sprintf(buf, "aio.handle%ld", fileId);
Jim_CreateCommand(interp, buf, JimAioHandlerCommand, af, JimAioDelProc);
Jim_SetResultString(interp, buf, -1);
return JIM_OK;
}
+static int JimAioSockCommand(Jim_Interp *interp, int argc,
+ Jim_Obj *const *argv)
+{
+ FILE *fp;
+ AioFile *af;
+ char buf[AIO_CMD_LEN];
+ char *hdlfmt;
+ // const char *mode = "r";
+ Jim_Obj *objPtr;
+ long fileId;
+ const char *socktypes[] = {
+ "file",
+ "pipe",
+ "tty",
+ "domain",
+ "dgram",
+ "stream",
+ "stream.server",
+
+ NULL
+ };
+ enum {
+ FILE_FILE,
+ FILE_PIPE,
+ FILE_TTY,
+ SOCK_DOMAIN,
+ SOCK_DGRAM_CL,
+ SOCK_STREAM_CL,
+ SOCK_STREAM_SERV
+ };
+ int modeLen;
+ int socktype;
+ int sock;
+ FILE *fsock;
+ const char *hostportarg;
+ int hostportlen;
+ char a[0x20];
+ char b[0x20];
+ char c[0x20];
+ char np[] = "0";
+ char nh[] = "0.0.0.0";
+ char* stsrcport;
+ char* sthost;
+ char* stport;
+ unsigned int srcport;
+ unsigned int port;
+ int elemcnt;
+ struct sockaddr_in sa;
+ struct hostent *he;
+ int res;
+
+ if (argc <= 2 ) {
+ Jim_WrongNumArgs(interp, 1, argv, "sockspec ?script?");
+ return JIM_ERR;
+ }
+
+ if (Jim_GetEnum(interp, argv[1], socktypes, &socktype, "socket type",
+ JIM_ERRMSG) != JIM_OK)
+ return JIM_ERR;
+ fprintf(stderr,"socktype: %s \n",socktypes[socktype]);
+ hostportarg = Jim_GetString(argv[2], &hostportlen);
+ fprintf(stderr,"hostportarg: %s %d \n",hostportarg,hostportlen);
+ switch (sscanf(hostportarg,"%[^:]:%[^:]:%[^:]",a,b,c)) {
+ case 3: stsrcport = a; sthost = b; stport = c; break;
+ case 2: stsrcport = np; sthost = a; stport = b; break;
+ case 1: stsrcport = np; sthost = nh; stport = a; break;
+ default:
+ return JIM_ERR;
+ }
+ fprintf(stderr,"socktype: %d srcport: %s host:%s port %s \n",
+ socktype,stsrcport,sthost,stport);
+ if (0 == strncmp(sthost,"ANY",3))
+ sthost = "0.0.0.0";
+ srcport = atol(stsrcport);
+ port = atol(stport);
+ he = gethostbyname(sthost);
+ if (!he)
+ herror("gethostbyname");
+ fprintf(stderr,"Official name is: %s\n", he->h_name);
+ fprintf(stderr,"IP address: %s\n", inet_ntoa(*(struct in_addr*)he->h_addr));
+
+ sock = socket(PF_INET,SOCK_STREAM,0);
+ fprintf(stderr,"srcp: %x port: %x IP: %x sock: %d type: %d\n",srcport,port,he->h_addr,sock,socktype);
+ switch (socktype) {
+ case SOCK_DGRAM_CL:
+ hdlfmt = "aio.sockdgram%ld" ;
+ break;
+ case SOCK_STREAM_CL:
+ fprintf(stderr,"setting up client socket\n");
+ sa.sin_family= he->h_addrtype;
+ bcopy(he->h_addr,(char *)&sa.sin_addr,he->h_length); /* set address */
+ sa.sin_port = htons(port);
+ res = connect(sock,(struct sockaddr*)&sa,sizeof(sa));
+ if (res) {
+ close(sock);
+ JimAioSetError(interp);
+ return JIM_ERR;
+ }
+ hdlfmt = "aio.sockstrm%ld" ;
+ break;
+ case SOCK_STREAM_SERV:
+ fprintf(stderr,"setting up listening socket\n");
+ sa.sin_family= he->h_addrtype;
+ bcopy(he->h_addr,(char *)&sa.sin_addr,he->h_length); /* set address */
+ sa.sin_port = htons(port);
+ res = bind(sock,(struct sockaddr*)&sa,sizeof(sa));
+ if (res) {
+ close(sock);
+ JimAioSetError(interp);
+ return JIM_ERR;
+ }
+ res = listen(sock,5);
+ if (res) {
+ close(sock);
+ JimAioSetError(interp);
+ return JIM_ERR;
+ }
+ hdlfmt = "aio.socksrv%ld" ;
+ break;
+ }
+ fp = fdopen(sock, "r+" );
+ fprintf(stderr,"fp: %p \n",fp);
+ if (fp == NULL) {
+ close(sock);
+ JimAioSetError(interp);
+ return JIM_ERR;
+ }
+ /* Get the next file id */
+ if (Jim_EvalGlobal(interp,
+ "if {[catch {incr aio.fileId}]} {set aio.fileId 0}") != JIM_OK)
+ return JIM_ERR;
+ objPtr = Jim_GetGlobalVariableStr(interp, "aio.fileId", JIM_ERRMSG);
+ if (objPtr == NULL) return JIM_ERR;
+ if (Jim_GetLong(interp, objPtr, &fileId) != JIM_OK) return JIM_ERR;
+
+ /* Create the file command */
+ af = Jim_Alloc(sizeof(*af));
+ af->fp = fp;
+ af->fd = sock;
+ af->OpenFlags = AIO_FDOPEN;
+ af->flags = fcntl(af->fd,F_GETFL);
+ fprintf(stderr,"hallo\n");
+ af->rEvent = NULL;
+ af->wEvent = NULL;
+ af->eEvent = NULL;
+ sprintf(buf, hdlfmt, fileId);
+ fprintf(stderr,"hallo:%s\n",buf);
+ Jim_CreateCommand(interp, buf, JimAioHandlerCommand, af, JimAioDelProc);
+ Jim_SetResultString(interp, buf, -1);
+ return JIM_OK;
+}
+
+static int JimAioAcceptHelper(Jim_Interp *interp, AioFile *serv_af )
+{
+ int sock;
+ int addrlen = sizeof(struct sockaddr_in);
+ AioFile *af;
+ char buf[AIO_CMD_LEN];
+ Jim_Obj *objPtr;
+ long fileId;
+ fprintf(stderr,"accepting connection for %d \n",serv_af->fd);
+ sock = accept(serv_af->fd,(struct sockaddr*)&serv_af->sa,&addrlen);
+ fprintf(stderr,"done, got %d \n",sock);
+ if (sock < 0)
+ return JIM_ERR;
+
+ /* Get the next file id */
+ fprintf(stderr,"getting fileid:");
+ if (Jim_EvalGlobal(interp,
+ "if {[catch {incr aio.fileId}]} {set aio.fileId 0}") != JIM_OK)
+ return JIM_ERR;
+ objPtr = Jim_GetGlobalVariableStr(interp, "aio.fileId", JIM_ERRMSG);
+ if (objPtr == NULL) return JIM_ERR;
+ if (Jim_GetLong(interp, objPtr, &fileId) != JIM_OK) return JIM_ERR;
+ fprintf(stderr," %ld\n", fileId);
+
+ /* Create the file command */
+ af = Jim_Alloc(sizeof(*af));
+ af->fd = sock;
+ af->fp = fdopen(sock,"r+");
+ af->OpenFlags = AIO_FDOPEN;
+ af->flags = fcntl(af->fd,F_GETFL);
+ // fprintf(stderr,"hallo\n");
+ af->rEvent = NULL;
+ af->wEvent = NULL;
+ af->eEvent = NULL;
+ sprintf(buf, "aio.sockstream%ld", fileId);
+ Jim_CreateCommand(interp, buf, JimAioHandlerCommand, af, JimAioDelProc);
+ Jim_SetResultString(interp, buf, -1);
+ fprintf(stderr,"returning\n");
+ return JIM_OK;
+}
+
DLLEXPORT int
#ifndef JIM_STATICEXT
Jim_OnLoad(Jim_Interp *interp)
@@ -355,8 +723,13 @@ Jim_AioInit(Jim_Interp *interp)
#ifndef JIM_STATICEXT
Jim_InitExtension(interp);
#endif
+ Jim_ImportEventloopAPI(interp);
if (Jim_PackageProvide(interp, "aio", "1.0", JIM_ERRMSG) != JIM_OK)
return JIM_ERR;
Jim_CreateCommand(interp, "aio.open", JimAioOpenCommand, NULL, NULL);
+ Jim_CreateCommand(interp, "aio.socket", JimAioSockCommand, NULL, NULL);
return JIM_OK;
}
+
+// end
+