4 * tuntap-socket create-ptp <local-addr> <peer-addr> <mtu> [<ifname>]
6 * tuntap-socket close <sockid>
7 * tuntap-socket ifname <sockid>
8 * tuntap-socket receive <sockid> <data>
9 * tuntap-socket on-transmit <sockid> [<script>]
10 * calls, effectively, eval <script> [list <data> <socket>]
11 * if script not supplied, cancel
17 typedef struct TunSocket {
18 int ix, fd, script_llength;
26 IdDataTable tuntap_socks= { "tuntap" };
28 static int sockfail(Tcl_Interp *ip, int fd, const char *m) {
32 return posixerr(ip,e,m);
35 int do_tuntap_socket_create_ptp(ClientData cd, Tcl_Interp *ip,
36 SockAddr_Value local, SockAddr_Value peer,
37 long mtu, const char *ifname,
39 int fd, local_al, peer_al, r;
42 const struct sockaddr *local_sa, *peer_sa;
44 local_sa= sockaddr_addr(&local);
45 local_al= sockaddr_len(&local);
47 peer_sa= sockaddr_addr(&peer);
48 peer_al= sockaddr_len(&peer);
50 if (local_sa != AF_INET || local_al != sizeof(struct in_addr) ||
51 peer_sa != AF_INET || peer_al != sizeof(struct in_addr))
52 return staticerr(ip,"tuntap not IPv4");
54 memset(&ifr,0,sizeof(ifr));
55 ifr.ifr_flags= IFF_TUN | IFF_NO_PI;
58 if (strlen(ifname) > IFNAMSIZ-1)
59 return staticerr(ip,"tun interface name too long");
60 strcpy(ifr.ifr_name, ifname);
63 fd= open("/dev/net/tun", O_RDWR);
64 if (fd<0) return posixerr(ip,errno,"open /dev/net/tun");
66 r= ioctl(fd, TUNSETIFF, (void*)&ifr);
67 if (r) return posixerr(ip,errno,"ioctl TUNSETIFF");
72 r= bind(fd, sa, al); if (r) return sockfail(ip,fd,"bind");
73 r= setnonblock(fd, 1); if (r) return sockfail(ip,fd,"setnonblock");
75 sock= TALLOC(sizeof(DgramSocket));
79 sock->addr_buflen= al+1;
80 sock->addr_buf= TALLOC(sock->addr_buflen);
88 int do_tuntap_socket_transmit(ClientData cd, Tcl_Interp *ip,
89 TuntapSocket *sock, HBytes_Value data,
90 SockAddr_Value remote) {
94 hbytes_data(&data), l=hbytes_len(&data),
96 sockaddr_addr(&remote), sockaddr_len(&remote));
97 if (r==-1) return posixerr(ip,errno,"sendto");
98 else if (r!=l) return staticerr(ip,"sendto gave wrong answer",0);
102 static void cancel(TuntapSocket *sock) {
104 Tcl_DeleteFileHandler(sock->fd);
105 Tcl_DecrRefCount(sock->script);
110 static void recv_call(ClientData sock_cd, int mask) {
111 TuntapSocket *sock= (void*)sock_cd;
112 Tcl_Interp *ip= sock->ip;
114 HBytes_Value message_val;
115 SockAddr_Value peer_val;
116 Tcl_Obj *args[3], *invoke;
120 hbytes_empty(&message_val);
121 sockaddr_clear(&peer_val);
122 invoke=0; for (i=0; i<3; i++) args[i]=0;
127 mh.msg_controllen= 0;
133 mh.msg_name= sock->addr_buf;
134 mh.msg_namelen= sock->addr_buflen;
136 iov.iov_base= sock->msg_buf;
137 iov.iov_len= sock->msg_buflen;
139 sz= recvmsg(sock->fd, &mh, peek);
140 if (sz==-1) { rc=0; goto x_rc; }
142 assert(mh.msg_namelen < sock->addr_buflen);
144 if (!(mh.msg_flags & MSG_TRUNC)) {
150 TFREE(sock->msg_buf);
151 sock->msg_buflen *= 2;
152 sock->msg_buflen += 100;
153 sock->msg_buf= TALLOC(sock->msg_buflen);
156 hbytes_array(&message_val, iov.iov_base, sz);
157 sockaddr_create(&peer_val, mh.msg_name, mh.msg_namelen);
159 args[0]= ret_hb(ip, message_val); hbytes_empty(&message_val);
160 args[1]= ret_sockaddr(ip, peer_val); sockaddr_clear(&peer_val);
161 args[2]= ret_sockid(ip, sock);
162 for (i=0; i<3; i++) Tcl_IncrRefCount(args[i]);
164 invoke= Tcl_DuplicateObj(sock->script);
165 Tcl_IncrRefCount(invoke);
167 rc= Tcl_ListObjReplace(ip,invoke,sock->script_llength,0,3,args);
168 for (i=0; i<3; i++) { Tcl_DecrRefCount(args[i]); args[i]= 0; }
171 rc= Tcl_EvalObjEx(ip,invoke,TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT);
174 if (invoke) Tcl_DecrRefCount(invoke);
177 Tcl_BackgroundError(ip);
180 int do_tuntap_socket_on_receive(ClientData cd, Tcl_Interp *ip,
181 TuntapSocket *sock, Tcl_Obj *script) {
185 rc= Tcl_ListObjLength(ip, script, &sock->script_llength);
191 Tcl_IncrRefCount(script);
192 sock->script= script;
195 Tcl_CreateFileHandler(sock->fd, TCL_READABLE, recv_call, sock);
199 int do_tuntap_socket_close(ClientData cd, Tcl_Interp *ip, TuntapSocket *sock) {
202 close(sock->fd); /* nothing useful to be done with errors */
204 TFREE(sock->addr_buf);
205 TFREE(sock->msg_buf);
213 int pat_sockid(Tcl_Interp *ip, Tcl_Obj *o, TuntapSocket **val) {
217 rc= Tcl_ConvertToType(ip,o,&tuntapsockid_type);
220 sockix= o->internalRep.longValue;
221 if (sockix >= n_socks || !(sock= socks[sockix]))
222 return staticerr(ip,"tuntap socket not open",0);
224 assert(socks[sockix]->ix == sockix);
230 Tcl_Obj *ret_sockid(Tcl_Interp *ip, TuntapSocket *val) {
234 Tcl_InvalidateStringRep(o);
235 o->internalRep.longValue= val->ix;
236 o->typePtr= &tuntapsockid_type;
240 static void sockid_t_free(Tcl_Obj *o) { }
242 static void sockid_t_dup(Tcl_Obj *src, Tcl_Obj *dup) {
243 dup->internalRep= src->internalRep;
244 dup->typePtr= &tuntapsockid_type;
247 static void sockid_t_ustr(Tcl_Obj *o) {
250 snprintf(buf,sizeof(buf), "%d", (int)o->internalRep.longValue);
251 obj_updatestr_vstringls(o,
257 static int sockid_t_sfa(Tcl_Interp *ip, Tcl_Obj *o) {
261 str= Tcl_GetStringFromObj(o,0);
262 if (memcmp(str,"tuntapsock",9)) return staticerr(ip,"bad tuntap socket id",0);
263 errno=0; ul=strtoul(str+9,&ep,10);
264 if (errno || *ep) return staticerr(ip,"bad tuntap socket id number",0);
265 if (ul > INT_MAX) return staticerr(ip,"out of range tuntap socket id",0);
268 o->internalRep.longValue= ul;
269 o->typePtr= &tuntapsockid_type;
273 Tcl_ObjType tuntapsockid_type = {
275 sockid_t_free, sockid_t_dup, sockid_t_ustr, sockid_t_sfa