From ceb4860abfe091be1ff68795d820ea4c9afc4f4a Mon Sep 17 00:00:00 2001 From: ian Date: Sat, 7 Sep 2002 03:13:26 +0000 Subject: [PATCH] Sockets all seem to work now erm. --- base/chiark-tcl.h | 4 +- base/tables-examples.tct | 6 +- dgram/dgram.c | 162 ++++++++++++++++++++++++++++++++++----- dgram/sockaddr.c | 24 +++--- hbytes/hbytes.h | 4 +- 5 files changed, 166 insertions(+), 34 deletions(-) diff --git a/base/chiark-tcl.h b/base/chiark-tcl.h index 951ae12..37697bb 100644 --- a/base/chiark-tcl.h +++ b/base/chiark-tcl.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -113,6 +114,7 @@ void sockaddr_free(const SockAddr_Value*); /* from dgram.c */ extern Tcl_ObjType sockid_type; +typedef struct DgramSocket *DgramSockID; /* from hook.c */ @@ -168,7 +170,7 @@ typedef struct { int pad, use_algname; } PadMethod; -Tcl_ObjType blockcipherkey_type; +extern Tcl_ObjType blockcipherkey_type; /* from algtables.c */ diff --git a/base/tables-examples.tct b/base/tables-examples.tct index f402a4c..71cb4bf 100644 --- a/base/tables-examples.tct +++ b/base/tables-examples.tct @@ -8,8 +8,7 @@ Fini hbv fini_hbv(ip, rc, &@); Type sockaddr: SockAddr_Value @ Init sockaddr sockaddr_clear(&@); -Type sockid: int @ -Init sockid @=-1; +Type sockid: DgramSockID @ H-Include "hbytes.h" @@ -95,3 +94,6 @@ Table dgram_socket DgramSocket_SubCommand sock sockid data hb remote sockaddr + on-receive + sock sockid + ?script obj diff --git a/dgram/dgram.c b/dgram/dgram.c index 7e98df2..a2a2f97 100644 --- a/dgram/dgram.c +++ b/dgram/dgram.c @@ -13,11 +13,15 @@ #include "hbytes.h" typedef struct DgramSocket { - int fd; + int ix, fd, script_llength; + Tcl_Interp *ip; + Tcl_Obj *script; + void *addr_buf, *msg_buf; + int addr_buflen, msg_buflen; } DgramSocket; static int n_socks; -static DgramSocket *socks; +static DgramSocket **socks; static int sockfail(Tcl_Interp *ip, int fd, const char *m) { int e; @@ -27,17 +31,18 @@ static int sockfail(Tcl_Interp *ip, int fd, const char *m) { } int do_dgram_socket_create(ClientData cd, Tcl_Interp *ip, - SockAddr_Value local, int *sock_r) { - int fd, al, r, sock; + SockAddr_Value local, DgramSockID *sock_r) { + int fd, al, r, sockix; + DgramSocket *sock; const struct sockaddr *sa; - for (sock=0; sock=0; sock++); - if (sock>=n_socks) { + for (sockix=0; sockix=n_socks) { n_socks += 2; n_socks *= 2; socks= (void*)Tcl_Realloc((void*)socks, n_socks*sizeof(*socks)); - while (sockfd= fd; + sock->ix= sockix; + sock->script= 0; + sock->addr_buflen= al+1; + sock->addr_buf= TALLOC(sock->addr_buflen); + sock->msg_buflen= 0; + sock->msg_buf= 0; + *sock_r= sock; return TCL_OK; } int do_dgram_socket_transmit(ClientData cd, Tcl_Interp *ip, - int sock, HBytes_Value data, + DgramSocket *sock, HBytes_Value data, SockAddr_Value remote) { int l, r; - r= sendto(socks[sock].fd, + r= sendto(sock->fd, hbytes_data(&data), l=hbytes_len(&data), 0, sockaddr_addr(&remote), sockaddr_len(&remote)); @@ -66,35 +79,144 @@ int do_dgram_socket_transmit(ClientData cd, Tcl_Interp *ip, else if (r!=l) return staticerr(ip,"sendto gave wrong answer"); return TCL_OK; } + +static void cancel(DgramSocket *sock) { + if (sock->script) { + Tcl_DeleteFileHandler(sock->fd); + Tcl_DecrRefCount(sock->script); + sock->script= 0; + } +} + +static void recv_call(ClientData sock_cd, int mask) { + DgramSocket *sock= (void*)sock_cd; + Tcl_Interp *ip= sock->ip; + int sz, rc, i, peek; + HBytes_Value message_val; + SockAddr_Value peer_val; + Tcl_Obj *args[3], *invoke; + struct msghdr mh; + struct iovec iov; + + hbytes_empty(&message_val); + sockaddr_clear(&peer_val); + invoke=0; for (i=0; i<3; i++) args[i]=0; + + mh.msg_iov= &iov; + mh.msg_iovlen= 1; + mh.msg_control= 0; + mh.msg_controllen= 0; + mh.msg_flags= 0; + + peek= MSG_PEEK; + + for (;;) { + mh.msg_name= sock->addr_buf; + mh.msg_namelen= sock->addr_buflen; + + iov.iov_base= sock->msg_buf; + iov.iov_len= sock->msg_buflen; + + sz= recvmsg(sock->fd, &mh, peek); + if (sz==-1) { rc=0; goto x_rc; } + + assert(mh.msg_namelen < sock->addr_buflen); + + if (!(mh.msg_flags & MSG_TRUNC)) { + if (!peek) break; + peek= 0; + continue; + } + + TFREE(sock->msg_buf); + sock->msg_buflen *= 2; + sock->msg_buflen += 100; + sock->msg_buf= TALLOC(sock->msg_buflen); + } + + hbytes_array(&message_val, iov.iov_base, sz); + sockaddr_create(&peer_val, mh.msg_name, mh.msg_namelen); + + args[0]= ret_hb(ip, message_val); hbytes_empty(&message_val); + args[1]= ret_sockaddr(ip, peer_val); sockaddr_clear(&peer_val); + args[2]= ret_sockid(ip, sock); + for (i=0; i<3; i++) Tcl_IncrRefCount(args[i]); + + invoke= Tcl_DuplicateObj(sock->script); + Tcl_IncrRefCount(invoke); + + rc= Tcl_ListObjReplace(ip,invoke,sock->script_llength,0,3,args); + if (rc) goto x_rc; + + rc= Tcl_EvalObjEx(ip,invoke,TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT); + + for (i=0; i<3; i++) Tcl_DecrRefCount(args[i]); + Tcl_DecrRefCount(invoke); + + hbytes_free(&message_val); + sockaddr_free(&peer_val); + +x_rc: + if (rc) + Tcl_BackgroundError(ip); +} + +int do_dgram_socket_on_receive(ClientData cd, Tcl_Interp *ip, + DgramSocket *sock, Tcl_Obj *script) { + int rc; + + if (script) { + rc= Tcl_ListObjLength(ip, script, &sock->script_llength); + if (rc) return rc; + } -int do_dgram_socket_close(ClientData cd, Tcl_Interp *ip, int sock) { - close(socks[sock].fd); /* nothing useful to be done with errors */ - socks[sock].fd= -1; + cancel(sock); + if (script) { + Tcl_IncrRefCount(script); + sock->script= script; + sock->ip= ip; + } + Tcl_CreateFileHandler(sock->fd, TCL_READABLE, recv_call, sock); + return TCL_OK; +} + +int do_dgram_socket_close(ClientData cd, Tcl_Interp *ip, DgramSocket *sock) { + int sockix; + cancel(sock); + close(sock->fd); /* nothing useful to be done with errors */ + sockix= sock->ix; + TFREE(sock->addr_buf); + TFREE(sock->msg_buf); + TFREE(sock); + socks[sockix]= 0; return TCL_OK; } /* Arg parsing */ -int pat_sockid(Tcl_Interp *ip, Tcl_Obj *o, int *val) { - int rc, sock; +int pat_sockid(Tcl_Interp *ip, Tcl_Obj *o, DgramSocket **val) { + int rc, sockix; + DgramSocket *sock; rc= Tcl_ConvertToType(ip,o,&sockid_type); if (rc) return rc; - sock= o->internalRep.longValue; - if (sock >= n_socks || socks[sock].fd==-1) + sockix= o->internalRep.longValue; + if (sockix >= n_socks || !(sock= socks[sockix])) return staticerr(ip,"dgram socket not open"); + assert(socks[sockix]->ix == sockix); + *val= sock; return TCL_OK; } -Tcl_Obj *ret_sockid(Tcl_Interp *ip, int val) { +Tcl_Obj *ret_sockid(Tcl_Interp *ip, DgramSocket *val) { Tcl_Obj *o; o= Tcl_NewObj(); Tcl_InvalidateStringRep(o); - o->internalRep.longValue= val; + o->internalRep.longValue= val->ix; o->typePtr= &sockid_type; return o; } diff --git a/dgram/sockaddr.c b/dgram/sockaddr.c index bedc109..4df9aa0 100644 --- a/dgram/sockaddr.c +++ b/dgram/sockaddr.c @@ -74,7 +74,8 @@ static void sockaddr_t_free(Tcl_Obj *o) { static void sockaddr_t_ustr(Tcl_Obj *o) { const struct sockaddr *sa; - char i46buf[INET6_ADDRSTRLEN]; + char i46buf[INET6_ADDRSTRLEN], portbuf[50]; + const struct sockaddr_in *sin; int al, sl, pl; const char *string, *prepend; @@ -86,17 +87,19 @@ static void sockaddr_t_ustr(Tcl_Obj *o) { case AF_INET6: assert(sizeof(i46buf) >= INET_ADDRSTRLEN); assert(al >= sizeof(struct sockaddr_in)); - inet_ntop(sa->sa_family, sa, i46buf, al); - string= i46buf; - prepend= ""; + sin= (const void*)sa; + inet_ntop(sa->sa_family, &sin->sin_addr, i46buf, al); + snprintf(portbuf,sizeof(portbuf),",%d",(int)ntohs(sin->sin_port)); + prepend= i46buf; + string= portbuf; break; case AF_UNIX: - assert(al >= sizeof(struct sockaddr_un)); string= ((const struct sockaddr_un*)sa)->sun_path; prepend= ""; if (!string[0]) string="//"; - else if (string[0] != '/' || string[1] == '/') prepend= "./"; + else if (string[0] != '/' || string[1] == '/') prepend= "./"; + break; default: /* ouch ! */ obj_updatestr_array_prefix(o,(const void*)sa,al,"?"); @@ -105,7 +108,8 @@ static void sockaddr_t_ustr(Tcl_Obj *o) { pl= strlen(prepend); sl= strlen(string); - o->bytes= TALLOC(sl+1); + o->length= pl+sl; + o->bytes= TALLOC(pl+sl+1); memcpy(o->bytes, prepend, pl); memcpy(o->bytes+pl, string, sl+1); } @@ -130,14 +134,14 @@ static int sockaddr_t_sfa(Tcl_Interp *ip, Tcl_Obj *o) { sl= sizeof(s.sun); s.sun.sun_family= AF_UNIX; - if (strcmp(str,"//")) path= ""; - else if (memcmp(str,"./",2) && str[2]) path= str+2; + if (!strcmp(str,"//")) path= ""; + else if (!memcmp(str,"./",2) && str[2]) path= str+2; else { assert(str[0]=='/' && str[1]!='/'); path=str; } if (strlen(str) >= sizeof(s.sun.sun_path)) return staticerr(ip, "AF_UNIX path too long"); - strcpy(s.sun.sun_path, str); + strcpy(s.sun.sun_path, path); } else if ((comma= strchr(str, ','))) { diff --git a/hbytes/hbytes.h b/hbytes/hbytes.h index 951ae12..37697bb 100644 --- a/hbytes/hbytes.h +++ b/hbytes/hbytes.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -113,6 +114,7 @@ void sockaddr_free(const SockAddr_Value*); /* from dgram.c */ extern Tcl_ObjType sockid_type; +typedef struct DgramSocket *DgramSockID; /* from hook.c */ @@ -168,7 +170,7 @@ typedef struct { int pad, use_algname; } PadMethod; -Tcl_ObjType blockcipherkey_type; +extern Tcl_ObjType blockcipherkey_type; /* from algtables.c */ -- 2.30.2