+WRAP(setsockopt) {
+ fdinfo *ent=lookup(fd);
+ if (!ent) return old_setsockopt(fd,level,optname,optval,optlen);
+ if (ent->af==AF_INET6 && level==IPPROTO_IPV6 && optname==IPV6_V6ONLY
+ && optlen==sizeof(int) && *(int*)optval==1) {
+ return 0;
+ }
+ errno=ENOTTY;
+ return -1;
+}
+
+WRAP(getsockname) {
+ fdinfo *ent=lookup(fd);
+ if (!ent) return old_getsockname(fd,addr,addrlen);
+ struct sockaddr_un sun;
+ socklen_t sunlen=sizeof(sun);
+ if (old_getsockname(fd,(void*)&sun,&sunlen)) return -1;
+ if (sun.sun_family!=AF_UNIX || sunlen>sizeof(sun)) {
+//fprintf(stderr,"old_getsockname af=%lu sunlen=%lu\n",
+// (unsigned long)sun.sun_family,
+// (unsigned long)sunlen);
+ errno=EDOM; return -1;
+ }
+ char *slash=strrchr(sun.sun_path,'/');
+ if (str2addrport(slash ? slash+1 : sun.sun_path,
+ addr,addrlen)) return -1;
+ return 0;
+}
+
+ssize_t TWRAP(sendto) {
+ fdinfo *ent=lookup(fd);
+ if (!ent) return old_sendto(fd,buf,len,flags,addr,addrlen);
+
+ if (flags) { errno=ENOEXEC; return -1; }
+
+ const char *leaf=getenv("UDP_PRELOAD_SERVER");
+ if (!leaf) leaf="udp";
+ if (strlen(leaf) > ADDRPORTSTRLEN) { errno=ENAMETOOLONG; return -1; }
+ struct sockaddr_un sun;
+ char *p=sun_prep(&sun);
+ strcpy(p,leaf);
+
+ char tbuf[ADDRPORTSTRLEN+1];
+ memset(tbuf,0,sizeof(tbuf));
+ if (addrport2str(tbuf,addr,addrlen)) return -1;
+
+ struct iovec iov[2];
+ iov[0].iov_base=tbuf;
+ iov[0].iov_len=sizeof(tbuf);
+ iov[1].iov_base=(void*)buf;
+ iov[1].iov_len=len;
+
+ struct msghdr m;
+ memset(&m,0,sizeof(m));
+ m.msg_name=&sun;
+ m.msg_namelen=sizeof(sun);
+ m.msg_iov=iov;
+ m.msg_iovlen=2;
+
+ return sendmsg(fd,&m,0);
+}