* dgram-socket create <local> => <sockid>
* dgram-socket close <sockid>
* dgram-socket transmit <sockid> <data> <remote>
- * dgram-socket on-receive <sockid> <script>
+ * dgram-socket on-receive <sockid> [<script>]
* calls, effectively, eval <script> [list <data> <remote-addr> <socket>]
+ * if script not supplied, cancel
*/
#include "tables.h"
#include "hbytes.h"
+typedef struct DgramSocket {
+ int fd;
+} DgramSocket;
+
+static int n_socks;
+static DgramSocket *socks;
+
static int sockfail(Tcl_Interp *ip, int fd, const char *m) {
int e;
e= errno;
}
int do_dgram_socket_create(ClientData cd, Tcl_Interp *ip,
- SockAddr_Value local, int *result) {
- int fd, al, r;
+ SockAddr_Value local, int *sock_r) {
+ int fd, al, r, sock;
const struct sockaddr *sa;
+ for (sock=0; sock<n_socks && socks[sock].fd>=0; sock++);
+ if (sock>=n_socks) {
+ n_socks += 2;
+ n_socks *= 2;
+ socks= (void*)Tcl_Realloc((void*)socks, n_socks*sizeof(*socks));
+ while (sock<n_socks) socks[sock++].fd=-1;
+ sock--;
+ }
+
sa= sockaddr_addr(&local);
al= sockaddr_len(&local);
if (fd<0) return posixerr(ip,errno,"socket");
r= bind(fd, sa, al); if (r) return sockfail(ip,fd,"bind");
r= setnonblock(fd, 1); if (r) return sockfail(ip,fd,"setnonblock");
- *result= fd;
+
+ socks[sock].fd= fd;
+ *sock_r= sock;
+ return TCL_OK;
+}
+
+int do_dgram_socket_transmit(ClientData cd, Tcl_Interp *ip,
+ int sock, HBytes_Value data,
+ SockAddr_Value remote) {
+ int l, r;
+
+ r= sendto(socks[sock].fd,
+ hbytes_data(&data), l=hbytes_len(&data),
+ 0,
+ sockaddr_addr(&remote), sockaddr_len(&remote));
+ if (r==-1) return posixerr(ip,errno,"sendto");
+ else if (r!=l) return staticerr(ip,"sendto gave wrong answer");
+ return TCL_OK;
+}
+
+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;
return TCL_OK;
}
/* Arg parsing */
int pat_sockid(Tcl_Interp *ip, Tcl_Obj *o, int *val) {
- int rc;
+ int rc, sock;
rc= Tcl_ConvertToType(ip,o,&sockid_type);
if (rc) return rc;
- *val= o->internalRep.longValue;
+ sock= o->internalRep.longValue;
+ if (sock >= n_socks || socks[sock].fd==-1)
+ return staticerr(ip,"dgram socket not open");
+
+ *val= sock;
return TCL_OK;
}