chiark / gitweb /
e6df127ab79bae33afa345d9268193f17f70c7eb
[chiark-tcl.git] / dgram / dgram.c
1 /*
2  */
3 /*
4  * dgram-socket create <local>                        => <sockid>
5  * dgram-socket close <sockid>
6  * dgram-socket transmit <sockid> <data> <remote>
7  * dgram-socket on-receive <sockid> <script>
8  *    calls, effectively,  eval <script> [list <data> <remote-addr> <socket>]
9  */
10
11 #include "tables.h"
12 #include "hbytes.h"
13
14 typedef struct DgramSocket {
15   int fd;
16 } DgramSocket;
17
18 static int n_socks;
19 static DgramSocket *socks;
20
21 static int sockfail(Tcl_Interp *ip, int fd, const char *m) {
22   int e;
23   e= errno;
24   close(fd);
25   return posixerr(ip,e,m);
26 }
27
28 int do_dgram_socket_create(ClientData cd, Tcl_Interp *ip,
29                           SockAddr_Value local, int *sock_r) {
30   int fd, al, r, sock;
31   const struct sockaddr *sa;
32
33   for (sock=0; sock<n_socks && socks[sock].fd>=0; sock++);
34   if (sock>=n_socks) {
35     n_socks += 2;
36     n_socks *= 2;
37     socks= (void*)Tcl_Realloc((void*)socks, n_socks*sizeof(*socks));
38     while (sock<n_socks) socks[sock++].fd=-1;
39     sock--;
40   }
41
42   sa= sockaddr_addr(&local);
43   al= sockaddr_len(&local);
44
45   fd= socket(sa->sa_family, SOCK_DGRAM, 0);
46   if (fd<0) return posixerr(ip,errno,"socket");
47   r= bind(fd, sa, al);  if (r) return sockfail(ip,fd,"bind");
48   r= setnonblock(fd, 1);  if (r) return sockfail(ip,fd,"setnonblock");
49
50   socks[sock].fd= fd;
51   *sock_r= sock;
52   return TCL_OK;
53 }
54
55 int do_dgram_socket_close(ClientData cd, Tcl_Interp *ip, int sock) {
56   close(socks[sock].fd); /* nothing useful to be done with errors */
57   socks[sock].fd= -1;
58   return TCL_OK;
59 }
60
61 /* Arg parsing */
62
63 int pat_sockid(Tcl_Interp *ip, Tcl_Obj *o, int *val) {
64   int rc, sock;
65   
66   rc= Tcl_ConvertToType(ip,o,&sockid_type);
67   if (rc) return rc;
68
69   sock= o->internalRep.longValue;
70   if (sock >= n_socks || socks[sock].fd==-1)
71     return staticerr(ip,"dgram socket not open");
72
73   *val= sock;
74   return TCL_OK;
75 }
76
77 Tcl_Obj *ret_sockid(Tcl_Interp *ip, int val) {
78   Tcl_Obj *o;
79
80   o= Tcl_NewObj();
81   Tcl_InvalidateStringRep(o);
82   o->internalRep.longValue= val;
83   o->typePtr= &sockid_type;
84   return o;
85 }
86
87 static void sockid_t_free(Tcl_Obj *o) { }
88
89 static void sockid_t_dup(Tcl_Obj *src, Tcl_Obj *dup) {
90   dup->internalRep= src->internalRep;
91 }
92
93 static void sockid_t_ustr(Tcl_Obj *o) {
94   char buf[100];
95   int l;
96
97   snprintf(buf,sizeof(buf),"dgramsock%d", (int)o->internalRep.longValue);
98   l= o->length= strlen(buf);
99   o->bytes= TALLOC(l+1);
100   strcpy(o->bytes, buf);
101 }
102
103 static int sockid_t_sfa(Tcl_Interp *ip, Tcl_Obj *o) {
104   unsigned long ul;
105   char *ep, *str;
106   
107   str= Tcl_GetStringFromObj(o,0);
108   if (memcmp(str,"dgramsock",9)) return staticerr(ip,"bad dgram socket id");
109   errno=0; ul=strtoul(str+9,&ep,10);
110   if (errno || *ep) return staticerr(ip,"bad dgram socket id number");
111   if (ul > INT_MAX) return staticerr(ip,"out of range dgram socket id");
112   o->internalRep.longValue= ul;
113   return TCL_OK;
114 }
115
116 Tcl_ObjType sockid_type = {
117   "sockid-nearly",
118   sockid_t_free, sockid_t_dup, sockid_t_ustr, sockid_t_sfa
119 };