int close(int socket) { struct fd_info *fdi; int ret; init_preload(); fdi = idm_lookup(&idm, socket); if (!fdi) return real.close(socket); if (fdi->dupfd != -1) { ret = close(fdi->dupfd); if (ret) return ret; } if (atomic_dec(&fdi->refcnt)) return 0; idm_clear(&idm, socket); real.close(socket); ret = (fdi->type == fd_rsocket) ? rclose(fdi->fd) : real.close(fdi->fd); free(fdi); return ret; }
ssize_t writev(int socket, const struct iovec *iov, int iovcnt) { int fd; init_preload(); return (fd_fork_get(socket, &fd) == fd_rsocket) ? rwritev(fd, iov, iovcnt) : real.writev(fd, iov, iovcnt); }
int poll(struct pollfd *fds, nfds_t nfds, int timeout) { struct pollfd *rfds; int i, ret; init_preload(); for (i = 0; i < nfds; i++) { if (fd_gett(fds[i].fd) == fd_rsocket) goto use_rpoll; } return real.poll(fds, nfds, timeout); use_rpoll: rfds = fds_alloc(nfds); if (!rfds) return ERR(ENOMEM); for (i = 0; i < nfds; i++) { rfds[i].fd = fd_getd(fds[i].fd); rfds[i].events = fds[i].events; rfds[i].revents = 0; } ret = rpoll(rfds, nfds, timeout); for (i = 0; i < nfds; i++) fds[i].revents = rfds[i].revents; return ret; }
ssize_t write(int socket, const void *buf, size_t count) { int fd; init_preload(); return (fd_fork_get(socket, &fd) == fd_rsocket) ? rwrite(fd, buf, count) : real.write(fd, buf, count); }
ssize_t read(int socket, void *buf, size_t count) { int fd; init_preload(); return (fd_fork_get(socket, &fd) == fd_rsocket) ? rread(fd, buf, count) : real.read(fd, buf, count); }
int socket(int domain, int type, int protocol) { static __thread int recursive; int index, ret; if (recursive) goto real; init_preload(); index = fd_open(); if (index < 0) return index; if (fork_support && (domain == PF_INET || domain == PF_INET6) && (type == SOCK_STREAM) && (!protocol || protocol == IPPROTO_TCP)) { ret = real.socket(domain, type, protocol); if (ret < 0) return ret; fd_store(index, ret, fd_normal, fd_fork); return index; } recursive = 1; ret = rsocket(domain, type, protocol); recursive = 0; if (ret >= 0) { fd_store(index, ret, fd_rsocket, fd_ready); set_rsocket_options(ret); return index; } fd_close(index, &ret); real: return real.socket(domain, type, protocol); }
int getsockname(int socket, struct sockaddr *addr, socklen_t *addrlen) { int fd; init_preload(); return (fd_get(socket, &fd) == fd_rsocket) ? rgetsockname(fd, addr, addrlen) : real.getsockname(fd, addr, addrlen); }
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) { int r; init_preload(); lock_release(&__get_lock(rwlock)->dep_map, 0, (unsigned long)_RET_IP_); r = ll_pthread_rwlock_unlock(rwlock); if (r) lock_acquire(&__get_lock(rwlock)->dep_map, 0, 0, 0, 2, NULL, (unsigned long)_RET_IP_); return r; }
int __fxstat(int ver, int socket, struct stat *buf) { int fd, ret; init_preload(); if (fd_get(socket, &fd) == fd_rsocket) { ret = real.fxstat(ver, socket, buf); if (!ret) buf->st_mode = (buf->st_mode & ~S_IFMT) | __S_IFSOCK; } else { ret = real.fxstat(ver, fd, buf); } return ret; }
/* * dup2 is not thread safe */ int dup2(int oldfd, int newfd) { struct fd_info *oldfdi, *newfdi; int ret; init_preload(); oldfdi = idm_lookup(&idm, oldfd); if (oldfdi) { if (oldfdi->state == fd_fork_passive) fork_passive(oldfd); else if (oldfdi->state == fd_fork_active) fork_active(oldfd); } newfdi = idm_lookup(&idm, newfd); if (newfdi) { /* newfd cannot have been dup'ed directly */ if (atomic_get(&newfdi->refcnt) > 1) return ERR(EBUSY); close(newfd); } ret = real.dup2(oldfd, newfd); if (!oldfdi || ret != newfd) return ret; newfdi = calloc(1, sizeof *newfdi); if (!newfdi) { close(newfd); return ERR(ENOMEM); } pthread_mutex_lock(&mut); idm_set(&idm, newfd, newfdi); pthread_mutex_unlock(&mut); newfdi->fd = oldfdi->fd; newfdi->type = oldfdi->type; if (oldfdi->dupfd != -1) { newfdi->dupfd = oldfdi->dupfd; oldfdi = idm_lookup(&idm, oldfdi->dupfd); } else { newfdi->dupfd = oldfd; } atomic_init(&newfdi->refcnt); atomic_set(&newfdi->refcnt, 1); atomic_inc(&oldfdi->refcnt); return newfd; }
int fcntl(int socket, int cmd, ... /* arg */) { va_list args; long lparam; void *pparam; int fd, ret; init_preload(); va_start(args, cmd); switch (cmd) { case F_GETFD: case F_GETFL: case F_GETOWN: case F_GETSIG: case F_GETLEASE: ret = (fd_get(socket, &fd) == fd_rsocket) ? rfcntl(fd, cmd) : real.fcntl(fd, cmd); break; case F_DUPFD: /*case F_DUPFD_CLOEXEC:*/ case F_SETFD: case F_SETFL: case F_SETOWN: case F_SETSIG: case F_SETLEASE: case F_NOTIFY: lparam = va_arg(args, long); ret = (fd_get(socket, &fd) == fd_rsocket) ? rfcntl(fd, cmd, lparam) : real.fcntl(fd, cmd, lparam); break; default: pparam = va_arg(args, void *); ret = (fd_get(socket, &fd) == fd_rsocket) ? rfcntl(fd, cmd, pparam) : real.fcntl(fd, cmd, pparam); break; } va_end(args); return ret; }
static void try_init_preload(void) { if (!__init_state != done) init_preload(); }