diff options
author | oharboe <oharboe> | 2008-07-14 13:29:24 +0000 |
---|---|---|
committer | oharboe <oharboe> | 2008-07-14 13:29:24 +0000 |
commit | ec16a897b19c1cebd1b6babdf107e59a14efdd45 (patch) | |
tree | 377c6d5117ab43ca790b834bb19b6679726e8d6b /jim-aio.c | |
parent | dbbb7b6eafc60d62e944d134bc41a8ea41185c62 (diff) | |
download | jimtcl-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.c | 393 |
1 files changed, 383 insertions, 10 deletions
@@ -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 + |