int getsockname(int fd, struct sockaddr *addr, int *alen) { Rock *r; int i; struct sockaddr_in *lip; struct sockaddr_un *lunix; r = _sock_findrock(fd, 0); if(r == 0){ errno = ENOTSOCK; return -1; } switch(r->domain){ case PF_INET: lip = (struct sockaddr_in*)addr; _sock_ingetaddr(r, lip, alen, "local"); break; case PF_UNIX: lunix = (struct sockaddr_un*)&r->addr; i = &lunix->sun_path[strlen(lunix->sun_path)] - (char*)lunix; memmove(addr, lunix, i); *alen = i; break; default: errno = EAFNOSUPPORT; return -1; } return 0; }
/* Give the socket FD the local address ADDR (which is LEN bytes long). */ int __bind(int fd, __CONST_SOCKADDR_ARG addr, socklen_t alen) { int n, cfd; socklen_t len; Rock *r; char msg[128]; struct sockaddr_in *lip; /* assign the address */ r = _sock_findrock(fd, 0); if (r == 0) { errno = ENOTSOCK; return -1; } if (alen > sizeof(r->addr_stor)) { errno = ENAMETOOLONG; return -1; } memmove(&r->addr, addr.__sockaddr__, alen); /* the rest is IP sepecific */ if (r->domain != PF_INET) return 0; cfd = open(r->ctl, O_RDWR); if (cfd < 0) { errno = EBADF; return -1; } lip = (struct sockaddr_in *)&r->addr; if (lip->sin_port > 0) snprintf(msg, sizeof msg, "bind %d", ntohs(lip->sin_port)); else strcpy(msg, "bind *"); n = write(cfd, msg, strlen(msg)); if (n < 0) { errno = EOPNOTSUPP; /* Improve error reporting!!! */ close(cfd); return -1; } if (lip->sin_port <= 0) _sock_ingetaddr(r, lip, &len, "local"); /* UDP sockets are in headers mode, and need to be announced. This isn't a * full announce, in that the kernel UDP stack doesn't expect someone to * open the listen file or anything like that. */ if ((r->domain == PF_INET) && (r->stype == SOCK_DGRAM)) { n = snprintf(msg, sizeof(msg), "announce *!%d", ntohs(lip->sin_port)); n = write(cfd, msg, n); if (n < 0) { perror("bind-announce failed"); return -1; } } close(cfd); return 0; }
int __libc_accept4(int fd, __SOCKADDR_ARG addr, socklen_t *alen, int a4_flags) { int nfd, lcfd; socklen_t n; Rock *r, *nr; struct sockaddr_in *ip; char name[Ctlsize]; char file[8 + Ctlsize + 1]; const char *net = 0; char listen[Ctlsize]; int open_flags; r = _sock_findrock(fd, 0); if (r == 0) { errno = ENOTSOCK; return -1; } switch (r->domain) { case PF_INET: switch (r->stype) { case SOCK_DGRAM: net = "udp"; break; case SOCK_STREAM: net = "tcp"; break; } /* at this point, our FD is for the data file. we need to open * the listen file. */ _sock_get_conv_filename(r, "listen", listen); open_flags = O_RDWR; /* This is for the listen - maybe don't block on open */ open_flags |= (r->sopts & SOCK_NONBLOCK ? O_NONBLOCK : 0); /* This is for the ctl we get back - maybe CLOEXEC, based on * what accept4 wants for the child */ open_flags |= (a4_flags & SOCK_CLOEXEC ? O_CLOEXEC : 0); lcfd = open(listen, open_flags); if (lcfd < 0) return -1; /* at this point, we have a new conversation, and lcfd is its * ctl fd. nfd will be the FD for that conv's data file. * sock_data will store our lcfd in the rock and return the data * file fd. * * Note, we pass the listen socket's stype, but not it's sopts. * The sopts (e.g. SOCK_NONBLOCK) apply to the original socket, * not to the new one. Instead, we pass the accept4 flags, * which are the sopts for the new socket. Note that this is * just the sopts. Both the listen socket and the new socket * have the same stype. */ nfd = _sock_data(lcfd, net, r->domain, a4_flags | r->stype, r->protocol, &nr); if (nfd < 0) return -1; /* get remote address */ ip = (struct sockaddr_in *)&nr->raddr; _sock_ingetaddr(nr, ip, &n, "remote"); if (addr.__sockaddr__) { memmove(addr.__sockaddr_in__, ip, sizeof(struct sockaddr_in)); *alen = sizeof(struct sockaddr_in); } return nfd; case PF_UNIX: if (r->other >= 0) { errno = EINVAL; // was EGREG return -1; } for (;;) { /* read path to new connection */ n = read(fd, name, sizeof(name) - 1); if (n < 0) return -1; if (n == 0) continue; name[n] = 0; /* open new connection */ _sock_srvname(file, name); open_flags = O_RDWR; /* This is for the listen - maybe don't block on open */ open_flags |= (r->sopts & SOCK_NONBLOCK ? O_NONBLOCK : 0); /* This is for the ctl we get back - maybe CLOEXEC, * based on what accept4 wants for the child */ open_flags |= (a4_flags & SOCK_CLOEXEC ? O_CLOEXEC : 0); nfd = open(file, open_flags); if (nfd < 0) continue; /* confirm opening on new connection */ if (write(nfd, name, strlen(name)) > 0) break; close(nfd); } nr = _sock_newrock(nfd); if (nr == 0) { close(nfd); return -1; } nr->domain = r->domain; nr->stype = r->stype; nr->sopts = a4_flags; nr->protocol = r->protocol; return nfd; default: errno = EOPNOTSUPP; return -1; } }
int accept(int fd, void *a, int *alen) { int n, nfd, cfd; Rock *r, *nr; struct sockaddr_in *ip; char name[Ctlsize]; char file[8+Ctlsize+1]; char *net; r = _sock_findrock(fd, 0); if(r == 0){ errno = ENOTSOCK; return -1; } switch(r->domain){ case PF_INET: switch(r->stype){ case SOCK_DGRAM: net = "udp"; break; case SOCK_STREAM: net = "tcp"; break; default: net = "gok"; break; } /* get control file name from listener process */ n = read(fd, name, sizeof(name)-1); if(n <= 0){ _syserrno(); return -1; } name[n] = 0; cfd = open(name, O_RDWR); if(cfd < 0){ _syserrno(); return -1; } nfd = _sock_data(cfd, net, r->domain, r->stype, r->protocol, &nr); if(nfd < 0){ _syserrno(); return -1; } if(write(fd, "OK", 2) < 0){ close(nfd); _syserrno(); return -1; } /* get remote address */ ip = (struct sockaddr_in*)&nr->raddr; _sock_ingetaddr(nr, ip, &n, "remote"); if(a){ memmove(a, ip, sizeof(struct sockaddr_in)); *alen = sizeof(struct sockaddr_in); } return nfd; case PF_UNIX: if(r->other >= 0){ errno = EGREG; return -1; } for(;;){ /* read path to new connection */ n = read(fd, name, sizeof(name) - 1); if(n < 0) return -1; if(n == 0) continue; name[n] = 0; /* open new connection */ _sock_srvname(file, name); nfd = open(file, O_RDWR); if(nfd < 0) continue; /* confirm opening on new connection */ if(write(nfd, name, strlen(name)) > 0) break; close(nfd); } nr = _sock_newrock(nfd); if(nr == 0){ close(nfd); return -1; } nr->domain = r->domain; nr->stype = r->stype; nr->protocol = r->protocol; return nfd; default: errno = EOPNOTSUPP; return -1; } }