/* * Copyright 2009-2010, Axel Dörfler, axeld@pinc-software.de. * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAX_SOCKET_ADDRESS_LENGTH (sizeof(sockaddr_storage)) #define MAX_SOCKET_OPTION_LENGTH 128 #define MAX_ANCILLARY_DATA_LENGTH 1024 #define GET_SOCKET_FD_OR_RETURN(fd, kernel, descriptor) \ do { \ status_t getError = get_socket_descriptor(fd, kernel, descriptor); \ if (getError != B_OK) \ return getError; \ } while (false) static net_stack_interface_module_info* sStackInterface = NULL; static vint32 sStackInterfaceInitialized = 0; static mutex sLock = MUTEX_INITIALIZER("stack interface"); static net_stack_interface_module_info* get_stack_interface_module() { MutexLocker _(sLock); if (sStackInterfaceInitialized++ == 0) { // load module net_stack_interface_module_info* module; // TODO: Add driver settings option to load the userland net stack. status_t error = get_module(NET_STACK_INTERFACE_MODULE_NAME, (module_info**)&module); if (error == B_OK) sStackInterface = module; else sStackInterface = NULL; } return sStackInterface; } static void put_stack_interface_module() { MutexLocker _(sLock); if (sStackInterfaceInitialized-- == 1) put_module(NET_STACK_INTERFACE_MODULE_NAME); } static status_t prepare_userland_address_result(struct sockaddr* userAddress, socklen_t* _addressLength, socklen_t& addressLength, bool addressRequired) { // check parameters if (_addressLength == NULL) return B_BAD_VALUE; if (userAddress == NULL) { if (addressRequired) return B_BAD_VALUE; } else if (!IS_USER_ADDRESS(userAddress) || !IS_USER_ADDRESS(_addressLength)) { return B_BAD_ADDRESS; } // copy the buffer size from userland addressLength = 0; if (userAddress != NULL && user_memcpy(&addressLength, _addressLength, sizeof(socklen_t)) != B_OK) { return B_BAD_ADDRESS; } if (addressLength > MAX_SOCKET_ADDRESS_LENGTH) addressLength = MAX_SOCKET_ADDRESS_LENGTH; return B_OK; } static status_t copy_address_to_userland(const void* address, socklen_t addressLength, sockaddr* userAddress, socklen_t userAddressBufferSize, socklen_t* userAddressLength) { // copy address size and address back to userland if (user_memcpy(userAddressLength, &addressLength, sizeof(socklen_t)) != B_OK || (userAddress != NULL && user_memcpy(userAddress, address, min_c(addressLength, userAddressBufferSize)) != B_OK)) { return B_BAD_ADDRESS; } return B_OK; } static status_t prepare_userland_msghdr(const msghdr* userMessage, msghdr& message, iovec*& userVecs, MemoryDeleter& vecsDeleter, void*& userAddress, char* address) { if (userMessage == NULL) return B_BAD_VALUE; // copy message from userland if (!IS_USER_ADDRESS(userMessage) || user_memcpy(&message, userMessage, sizeof(msghdr)) != B_OK) { return B_BAD_ADDRESS; } userVecs = message.msg_iov; userAddress = message.msg_name; // copy iovecs from userland if (message.msg_iovlen < 0 || message.msg_iovlen > IOV_MAX) return EMSGSIZE; if (userVecs != NULL && message.msg_iovlen > 0) { iovec* vecs; status_t error = get_iovecs_from_user(message.msg_iov, message.msg_iovlen, vecs); if (error != B_OK) return error; vecsDeleter.SetTo(vecs); message.msg_iov = vecs; } else { message.msg_iov = NULL; message.msg_iovlen = 0; } // prepare the address field userAddress = message.msg_name; if (userAddress != NULL) { if (!IS_USER_ADDRESS(message.msg_name)) return B_BAD_ADDRESS; if (message.msg_namelen > MAX_SOCKET_ADDRESS_LENGTH) message.msg_namelen = MAX_SOCKET_ADDRESS_LENGTH; message.msg_name = address; } return B_OK; } static status_t get_socket_descriptor(int fd, bool kernel, file_descriptor*& descriptor) { if (fd < 0) return EBADF; descriptor = get_fd(get_current_io_context(kernel), fd); if (descriptor == NULL) return EBADF; if (descriptor->type != FDTYPE_SOCKET) { put_fd(descriptor); return ENOTSOCK; } return B_OK; } // #pragma mark - socket file descriptor static status_t socket_read(struct file_descriptor *descriptor, off_t pos, void *buffer, size_t *_length) { ssize_t bytesRead = sStackInterface->recv(descriptor->u.socket, buffer, *_length, 0); *_length = bytesRead >= 0 ? bytesRead : 0; return bytesRead >= 0 ? B_OK : bytesRead; } static status_t socket_write(struct file_descriptor *descriptor, off_t pos, const void *buffer, size_t *_length) { ssize_t bytesWritten = sStackInterface->send(descriptor->u.socket, buffer, *_length, 0); *_length = bytesWritten >= 0 ? bytesWritten : 0; return bytesWritten >= 0 ? B_OK : bytesWritten; } static status_t socket_ioctl(struct file_descriptor *descriptor, ulong op, void *buffer, size_t length) { return sStackInterface->ioctl(descriptor->u.socket, op, buffer, length); } static status_t socket_set_flags(struct file_descriptor *descriptor, int flags) { // we ignore O_APPEND, but O_NONBLOCK we need to translate uint32 op = (flags & O_NONBLOCK) != 0 ? B_SET_NONBLOCKING_IO : B_SET_BLOCKING_IO; return sStackInterface->ioctl(descriptor->u.socket, op, NULL, 0); } static status_t socket_select(struct file_descriptor *descriptor, uint8 event, struct selectsync *sync) { return sStackInterface->select(descriptor->u.socket, event, sync); } static status_t socket_deselect(struct file_descriptor *descriptor, uint8 event, struct selectsync *sync) { return sStackInterface->deselect(descriptor->u.socket, event, sync); } static status_t socket_read_stat(struct file_descriptor *descriptor, struct stat *st) { st->st_dev = 0; st->st_ino = (addr_t)descriptor->u.socket; st->st_mode = S_IFSOCK | 0666; st->st_nlink = 1; st->st_uid = 0; st->st_gid = 0; st->st_size = 0; st->st_rdev = 0; st->st_blksize = 1024; // use MTU for datagram sockets? st->st_type = 0; timespec now; now.tv_sec = time(NULL); now.tv_nsec = 0; st->st_atim = now; st->st_mtim = now; st->st_ctim = now; st->st_crtim = now; return B_OK; } static status_t socket_close(struct file_descriptor *descriptor) { return sStackInterface->close(descriptor->u.socket); } static void socket_free(struct file_descriptor *descriptor) { sStackInterface->free(descriptor->u.socket); put_stack_interface_module(); } static struct fd_ops sSocketFDOps = { &socket_read, &socket_write, NULL, // fd_seek &socket_ioctl, &socket_set_flags, &socket_select, &socket_deselect, NULL, // fd_read_dir NULL, // fd_rewind_dir &socket_read_stat, NULL, // fd_write_stat &socket_close, &socket_free }; static int create_socket_fd(net_socket* socket, bool kernel) { // Get the socket's non-blocking flag, so we can set the respective // open mode flag. int32 nonBlock; socklen_t nonBlockLen = sizeof(int32); status_t error = sStackInterface->getsockopt(socket, SOL_SOCKET, SO_NONBLOCK, &nonBlock, &nonBlockLen); if (error != B_OK) return error; // allocate a file descriptor file_descriptor* descriptor = alloc_fd(); if (descriptor == NULL) return B_NO_MEMORY; // init it descriptor->type = FDTYPE_SOCKET; descriptor->ops = &sSocketFDOps; descriptor->u.socket = socket; descriptor->open_mode = O_RDWR | (nonBlock ? O_NONBLOCK : 0); // publish it int fd = new_fd(get_current_io_context(kernel), descriptor); if (fd < 0) { descriptor->ops = NULL; put_fd(descriptor); } return fd; } // #pragma mark - common sockets API implementation static int common_socket(int family, int type, int protocol, bool kernel) { if (!get_stack_interface_module()) return B_UNSUPPORTED; // create the socket net_socket* socket; status_t error = sStackInterface->open(family, type, protocol, &socket); if (error != B_OK) { put_stack_interface_module(); return error; } // allocate the FD int fd = create_socket_fd(socket, kernel); if (fd < 0) { sStackInterface->close(socket); sStackInterface->free(socket); put_stack_interface_module(); } return fd; } static status_t common_bind(int fd, const struct sockaddr *address, socklen_t addressLength, bool kernel) { file_descriptor* descriptor; GET_SOCKET_FD_OR_RETURN(fd, kernel, descriptor); FileDescriptorPutter _(descriptor); return sStackInterface->bind(descriptor->u.socket, address, addressLength); } static status_t common_shutdown(int fd, int how, bool kernel) { file_descriptor* descriptor; GET_SOCKET_FD_OR_RETURN(fd, kernel, descriptor); FileDescriptorPutter _(descriptor); return sStackInterface->shutdown(descriptor->u.socket, how); } static status_t common_connect(int fd, const struct sockaddr *address, socklen_t addressLength, bool kernel) { file_descriptor* descriptor; GET_SOCKET_FD_OR_RETURN(fd, kernel, descriptor); FileDescriptorPutter _(descriptor); return sStackInterface->connect(descriptor->u.socket, address, addressLength); } static status_t common_listen(int fd, int backlog, bool kernel) { file_descriptor* descriptor; GET_SOCKET_FD_OR_RETURN(fd, kernel, descriptor); FileDescriptorPutter _(descriptor); return sStackInterface->listen(descriptor->u.socket, backlog); } static int common_accept(int fd, struct sockaddr *address, socklen_t *_addressLength, bool kernel) { file_descriptor* descriptor; GET_SOCKET_FD_OR_RETURN(fd, kernel, descriptor); FileDescriptorPutter _(descriptor); net_socket* acceptedSocket; status_t error = sStackInterface->accept(descriptor->u.socket, address, _addressLength, &acceptedSocket); if (error != B_OK) return error; // allocate the FD int acceptedFD = create_socket_fd(acceptedSocket, kernel); if (acceptedFD < 0) { sStackInterface->close(acceptedSocket); sStackInterface->free(acceptedSocket); } else { // we need a reference for the new FD get_stack_interface_module(); } return acceptedFD; } static ssize_t common_recv(int fd, void *data, size_t length, int flags, bool kernel) { file_descriptor* descriptor; GET_SOCKET_FD_OR_RETURN(fd, kernel, descriptor); FileDescriptorPutter _(descriptor); return sStackInterface->recv(descriptor->u.socket, data, length, flags); } static ssize_t common_recvfrom(int fd, void *data, size_t length, int flags, struct sockaddr *address, socklen_t *_addressLength, bool kernel) { file_descriptor* descriptor; GET_SOCKET_FD_OR_RETURN(fd, kernel, descriptor); FileDescriptorPutter _(descriptor); return sStackInterface->recvfrom(descriptor->u.socket, data, length, flags, address, _addressLength); } static ssize_t common_recvmsg(int fd, struct msghdr *message, int flags, bool kernel) { file_descriptor* descriptor; GET_SOCKET_FD_OR_RETURN(fd, kernel, descriptor); FileDescriptorPutter _(descriptor); return sStackInterface->recvmsg(descriptor->u.socket, message, flags); } static ssize_t common_send(int fd, const void *data, size_t length, int flags, bool kernel) { file_descriptor* descriptor; GET_SOCKET_FD_OR_RETURN(fd, kernel, descriptor); FileDescriptorPutter _(descriptor); return sStackInterface->send(descriptor->u.socket, data, length, flags); } static ssize_t common_sendto(int fd, const void *data, size_t length, int flags, const struct sockaddr *address, socklen_t addressLength, bool kernel) { file_descriptor* descriptor; GET_SOCKET_FD_OR_RETURN(fd, kernel, descriptor); FileDescriptorPutter _(descriptor); return sStackInterface->sendto(descriptor->u.socket, data, length, flags, address, addressLength); } static ssize_t common_sendmsg(int fd, const struct msghdr *message, int flags, bool kernel) { file_descriptor* descriptor; GET_SOCKET_FD_OR_RETURN(fd, kernel, descriptor); FileDescriptorPutter _(descriptor); return sStackInterface->sendmsg(descriptor->u.socket, message, flags); } static status_t common_getsockopt(int fd, int level, int option, void *value, socklen_t *_length, bool kernel) { file_descriptor* descriptor; GET_SOCKET_FD_OR_RETURN(fd, kernel, descriptor); FileDescriptorPutter _(descriptor); return sStackInterface->getsockopt(descriptor->u.socket, level, option, value, _length); } static status_t common_setsockopt(int fd, int level, int option, const void *value, socklen_t length, bool kernel) { file_descriptor* descriptor; GET_SOCKET_FD_OR_RETURN(fd, kernel, descriptor); FileDescriptorPutter _(descriptor); return sStackInterface->setsockopt(descriptor->u.socket, level, option, value, length); } static status_t common_getpeername(int fd, struct sockaddr *address, socklen_t *_addressLength, bool kernel) { file_descriptor* descriptor; GET_SOCKET_FD_OR_RETURN(fd, kernel, descriptor); FileDescriptorPutter _(descriptor); return sStackInterface->getpeername(descriptor->u.socket, address, _addressLength); } static status_t common_getsockname(int fd, struct sockaddr *address, socklen_t *_addressLength, bool kernel) { file_descriptor* descriptor; GET_SOCKET_FD_OR_RETURN(fd, kernel, descriptor); FileDescriptorPutter _(descriptor); return sStackInterface->getsockname(descriptor->u.socket, address, _addressLength); } static int common_sockatmark(int fd, bool kernel) { file_descriptor* descriptor; GET_SOCKET_FD_OR_RETURN(fd, kernel, descriptor); FileDescriptorPutter _(descriptor); return sStackInterface->sockatmark(descriptor->u.socket); } static status_t common_socketpair(int family, int type, int protocol, int fds[2], bool kernel) { if (!get_stack_interface_module()) return B_UNSUPPORTED; net_socket* sockets[2]; status_t error = sStackInterface->socketpair(family, type, protocol, sockets); if (error != B_OK) { put_stack_interface_module(); return error; } // allocate the FDs for (int i = 0; i < 2; i++) { fds[i] = create_socket_fd(sockets[i], kernel); if (fds[i] < 0) { sStackInterface->close(sockets[i]); sStackInterface->free(sockets[i]); put_stack_interface_module(); return fds[i]; } } // We need another reference for the second socket get_stack_interface_module(); return B_OK; } static status_t common_get_next_socket_stat(int family, uint32 *cookie, struct net_stat *stat) { if (!get_stack_interface_module()) return B_UNSUPPORTED; status_t status = sStackInterface->get_next_socket_stat(family, cookie, stat); put_stack_interface_module(); return status; } // #pragma mark - kernel sockets API int socket(int family, int type, int protocol) { SyscallFlagUnsetter _; RETURN_AND_SET_ERRNO(common_socket(family, type, protocol, true)); } int bind(int socket, const struct sockaddr *address, socklen_t addressLength) { SyscallFlagUnsetter _; RETURN_AND_SET_ERRNO(common_bind(socket, address, addressLength, true)); } int shutdown(int socket, int how) { SyscallFlagUnsetter _; RETURN_AND_SET_ERRNO(common_shutdown(socket, how, true)); } int connect(int socket, const struct sockaddr *address, socklen_t addressLength) { SyscallFlagUnsetter _; RETURN_AND_SET_ERRNO(common_connect(socket, address, addressLength, true)); } int listen(int socket, int backlog) { SyscallFlagUnsetter _; RETURN_AND_SET_ERRNO(common_listen(socket, backlog, true)); } int accept(int socket, struct sockaddr *address, socklen_t *_addressLength) { SyscallFlagUnsetter _; RETURN_AND_SET_ERRNO(common_accept(socket, address, _addressLength, true)); } ssize_t recv(int socket, void *data, size_t length, int flags) { SyscallFlagUnsetter _; RETURN_AND_SET_ERRNO(common_recv(socket, data, length, flags, true)); } ssize_t recvfrom(int socket, void *data, size_t length, int flags, struct sockaddr *address, socklen_t *_addressLength) { SyscallFlagUnsetter _; RETURN_AND_SET_ERRNO(common_recvfrom(socket, data, length, flags, address, _addressLength, true)); } ssize_t recvmsg(int socket, struct msghdr *message, int flags) { SyscallFlagUnsetter _; RETURN_AND_SET_ERRNO(common_recvmsg(socket, message, flags, true)); } ssize_t send(int socket, const void *data, size_t length, int flags) { SyscallFlagUnsetter _; RETURN_AND_SET_ERRNO(common_send(socket, data, length, flags, true)); } ssize_t sendto(int socket, const void *data, size_t length, int flags, const struct sockaddr *address, socklen_t addressLength) { SyscallFlagUnsetter _; RETURN_AND_SET_ERRNO(common_sendto(socket, data, length, flags, address, addressLength, true)); } ssize_t sendmsg(int socket, const struct msghdr *message, int flags) { SyscallFlagUnsetter _; RETURN_AND_SET_ERRNO(common_sendmsg(socket, message, flags, true)); } int getsockopt(int socket, int level, int option, void *value, socklen_t *_length) { SyscallFlagUnsetter _; RETURN_AND_SET_ERRNO(common_getsockopt(socket, level, option, value, _length, true)); } int setsockopt(int socket, int level, int option, const void *value, socklen_t length) { SyscallFlagUnsetter _; RETURN_AND_SET_ERRNO(common_setsockopt(socket, level, option, value, length, true)); } int getpeername(int socket, struct sockaddr *address, socklen_t *_addressLength) { SyscallFlagUnsetter _; RETURN_AND_SET_ERRNO(common_getpeername(socket, address, _addressLength, true)); } int getsockname(int socket, struct sockaddr *address, socklen_t *_addressLength) { SyscallFlagUnsetter _; RETURN_AND_SET_ERRNO(common_getsockname(socket, address, _addressLength, true)); } int sockatmark(int socket) { SyscallFlagUnsetter _; RETURN_AND_SET_ERRNO(common_sockatmark(socket, true)); } int socketpair(int family, int type, int protocol, int socketVector[2]) { SyscallFlagUnsetter _; RETURN_AND_SET_ERRNO(common_socketpair(family, type, protocol, socketVector, true)); } // #pragma mark - syscalls int _user_socket(int family, int type, int protocol) { SyscallRestartWrapper result; return result = common_socket(family, type, protocol, false); } status_t _user_bind(int socket, const struct sockaddr *userAddress, socklen_t addressLength) { // check parameters and copy address from userland if (userAddress == NULL || addressLength > MAX_SOCKET_ADDRESS_LENGTH) return B_BAD_VALUE; sockaddr_storage address; memset(&address, 0, sizeof(address)); if (!IS_USER_ADDRESS(userAddress) || user_memcpy(&address, userAddress, addressLength) != B_OK) { return B_BAD_ADDRESS; } address.ss_len = addressLength; // make sure the sa_len field is set correctly SyscallRestartWrapper error; return error = common_bind(socket, (sockaddr*)&address, addressLength, false); } status_t _user_shutdown_socket(int socket, int how) { SyscallRestartWrapper error; return error = common_shutdown(socket, how, false); } status_t _user_connect(int socket, const struct sockaddr *userAddress, socklen_t addressLength) { // check parameters and copy address from userland if (userAddress == NULL || addressLength > MAX_SOCKET_ADDRESS_LENGTH) return B_BAD_VALUE; sockaddr_storage address; memset(&address, 0, sizeof(address)); if (!IS_USER_ADDRESS(userAddress) || user_memcpy(&address, userAddress, addressLength) != B_OK) { return B_BAD_ADDRESS; } address.ss_len = addressLength; // make sure the sa_len field is set correctly SyscallRestartWrapper error; return error = common_connect(socket, (sockaddr*)&address, addressLength, false); } status_t _user_listen(int socket, int backlog) { SyscallRestartWrapper error; return error = common_listen(socket, backlog, false); } int _user_accept(int socket, struct sockaddr *userAddress, socklen_t *_addressLength) { // check parameters socklen_t addressLength = 0; status_t error = prepare_userland_address_result(userAddress, _addressLength, addressLength, false); if (error != B_OK) return error; // accept() SyscallRestartWrapper result; char address[MAX_SOCKET_ADDRESS_LENGTH]; socklen_t userAddressBufferSize = addressLength; result = common_accept(socket, userAddress != NULL ? (sockaddr*)address : NULL, &addressLength, false); // copy address size and address back to userland if (copy_address_to_userland(address, addressLength, userAddress, userAddressBufferSize, _addressLength) != B_OK) { _user_close(result); return B_BAD_ADDRESS; } return result; } ssize_t _user_recv(int socket, void *data, size_t length, int flags) { if (data == NULL || !is_user_address_range(data, length)) return B_BAD_ADDRESS; SyscallRestartWrapper result; return result = common_recv(socket, data, length, flags, false); } ssize_t _user_recvfrom(int socket, void *data, size_t length, int flags, struct sockaddr *userAddress, socklen_t *_addressLength) { if (data == NULL || !is_user_address_range(data, length)) return B_BAD_ADDRESS; // check parameters socklen_t addressLength = 0; status_t error = prepare_userland_address_result(userAddress, _addressLength, addressLength, false); if (error != B_OK) return error; // recvfrom() SyscallRestartWrapper result; char address[MAX_SOCKET_ADDRESS_LENGTH]; socklen_t userAddressBufferSize = addressLength; result = common_recvfrom(socket, data, length, flags, userAddress != NULL ? (sockaddr*)address : NULL, &addressLength, false); if (result < 0) return result; // copy address size and address back to userland if (copy_address_to_userland(address, addressLength, userAddress, userAddressBufferSize, _addressLength) != B_OK) { return B_BAD_ADDRESS; } return result; } ssize_t _user_recvmsg(int socket, struct msghdr *userMessage, int flags) { // copy message from userland msghdr message; iovec* userVecs; MemoryDeleter vecsDeleter; void* userAddress; char address[MAX_SOCKET_ADDRESS_LENGTH]; status_t error = prepare_userland_msghdr(userMessage, message, userVecs, vecsDeleter, userAddress, address); if (error != B_OK) return error; // prepare a buffer for ancillary data MemoryDeleter ancillaryDeleter; void* ancillary = NULL; void* userAncillary = message.msg_control; if (userAncillary != NULL) { if (!IS_USER_ADDRESS(userAncillary)) return B_BAD_ADDRESS; if (message.msg_controllen < 0) return B_BAD_VALUE; if (message.msg_controllen > MAX_ANCILLARY_DATA_LENGTH) message.msg_controllen = MAX_ANCILLARY_DATA_LENGTH; message.msg_control = ancillary = malloc(message.msg_controllen); if (message.msg_control == NULL) return B_NO_MEMORY; ancillaryDeleter.SetTo(ancillary); } // recvmsg() SyscallRestartWrapper result; result = common_recvmsg(socket, &message, flags, false); if (result < 0) return result; // copy the address, the ancillary data, and the message header back to // userland message.msg_name = userAddress; message.msg_iov = userVecs; message.msg_control = userAncillary; if ((userAddress != NULL && user_memcpy(userAddress, address, message.msg_namelen) != B_OK) || (userAncillary != NULL && user_memcpy(userAncillary, ancillary, message.msg_controllen) != B_OK) || user_memcpy(userMessage, &message, sizeof(msghdr)) != B_OK) { return B_BAD_ADDRESS; } return result; } ssize_t _user_send(int socket, const void *data, size_t length, int flags) { if (data == NULL || !is_user_address_range(data, length)) return B_BAD_ADDRESS; SyscallRestartWrapper result; return result = common_send(socket, data, length, flags, false); } ssize_t _user_sendto(int socket, const void *data, size_t length, int flags, const struct sockaddr *userAddress, socklen_t addressLength) { if (data == NULL || !is_user_address_range(data, length)) return B_BAD_ADDRESS; if (addressLength <= 0 || addressLength > MAX_SOCKET_ADDRESS_LENGTH) { return B_BAD_VALUE; } // copy address from userland char address[MAX_SOCKET_ADDRESS_LENGTH]; if (userAddress != NULL) { if (!IS_USER_ADDRESS(userAddress) || user_memcpy(address, userAddress, addressLength) != B_OK) { return B_BAD_ADDRESS; } } else { addressLength = 0; } // sendto() SyscallRestartWrapper result; return result = common_sendto(socket, data, length, flags, userAddress != NULL ? (sockaddr*)address : NULL, addressLength, false); } ssize_t _user_sendmsg(int socket, const struct msghdr *userMessage, int flags) { // copy message from userland msghdr message; iovec* userVecs; MemoryDeleter vecsDeleter; void* userAddress; char address[MAX_SOCKET_ADDRESS_LENGTH]; status_t error = prepare_userland_msghdr(userMessage, message, userVecs, vecsDeleter, userAddress, address); if (error != B_OK) return error; // copy the address from userland if (userAddress != NULL && user_memcpy(address, userAddress, message.msg_namelen) != B_OK) { return B_BAD_ADDRESS; } // copy ancillary data from userland MemoryDeleter ancillaryDeleter; void* userAncillary = message.msg_control; if (userAncillary != NULL) { if (!IS_USER_ADDRESS(userAncillary)) return B_BAD_ADDRESS; if (message.msg_controllen < 0 || message.msg_controllen > MAX_ANCILLARY_DATA_LENGTH) { return B_BAD_VALUE; } message.msg_control = malloc(message.msg_controllen); if (message.msg_control == NULL) return B_NO_MEMORY; ancillaryDeleter.SetTo(message.msg_control); if (user_memcpy(message.msg_control, userAncillary, message.msg_controllen) != B_OK) { return B_BAD_ADDRESS; } } // sendmsg() SyscallRestartWrapper result; return result = common_sendmsg(socket, &message, flags, false); } status_t _user_getsockopt(int socket, int level, int option, void *userValue, socklen_t *_length) { // check params if (userValue == NULL || _length == NULL) return B_BAD_VALUE; if (!IS_USER_ADDRESS(userValue) || !IS_USER_ADDRESS(_length)) return B_BAD_ADDRESS; // copy length from userland socklen_t length; if (user_memcpy(&length, _length, sizeof(socklen_t)) != B_OK) return B_BAD_ADDRESS; if (length > MAX_SOCKET_OPTION_LENGTH) return B_BAD_VALUE; // getsockopt() char value[MAX_SOCKET_OPTION_LENGTH]; SyscallRestartWrapper error; error = common_getsockopt(socket, level, option, value, &length, false); if (error != B_OK) return error; // copy value back to userland if (user_memcpy(userValue, value, length) != B_OK) return B_BAD_ADDRESS; return B_OK; } status_t _user_setsockopt(int socket, int level, int option, const void *userValue, socklen_t length) { // check params if (userValue == NULL || length > MAX_SOCKET_OPTION_LENGTH) return B_BAD_VALUE; // copy value from userland char value[MAX_SOCKET_OPTION_LENGTH]; if (!IS_USER_ADDRESS(userValue) || user_memcpy(value, userValue, length) != B_OK) { return B_BAD_ADDRESS; } // setsockopt(); SyscallRestartWrapper error; return error = common_setsockopt(socket, level, option, value, length, false); } status_t _user_getpeername(int socket, struct sockaddr *userAddress, socklen_t *_addressLength) { // check parameters socklen_t addressLength = 0; SyscallRestartWrapper error; error = prepare_userland_address_result(userAddress, _addressLength, addressLength, true); if (error != B_OK) return error; // getpeername() char address[MAX_SOCKET_ADDRESS_LENGTH]; socklen_t userAddressBufferSize = addressLength; error = common_getpeername(socket, (sockaddr*)address, &addressLength, false); if (error != B_OK) return error; // copy address size and address back to userland if (copy_address_to_userland(address, addressLength, userAddress, userAddressBufferSize, _addressLength) != B_OK) { return B_BAD_ADDRESS; } return B_OK; } status_t _user_getsockname(int socket, struct sockaddr *userAddress, socklen_t *_addressLength) { // check parameters socklen_t addressLength = 0; SyscallRestartWrapper error; error = prepare_userland_address_result(userAddress, _addressLength, addressLength, true); if (error != B_OK) return error; // getsockname() char address[MAX_SOCKET_ADDRESS_LENGTH]; socklen_t userAddressBufferSize = addressLength; error = common_getsockname(socket, (sockaddr*)address, &addressLength, false); if (error != B_OK) return error; // copy address size and address back to userland if (copy_address_to_userland(address, addressLength, userAddress, userAddressBufferSize, _addressLength) != B_OK) { return B_BAD_ADDRESS; } return B_OK; } int _user_sockatmark(int socket) { SyscallRestartWrapper error; return error = common_sockatmark(socket, false); } status_t _user_socketpair(int family, int type, int protocol, int *userSocketVector) { // check parameters if (userSocketVector == NULL) return B_BAD_VALUE; if (!IS_USER_ADDRESS(userSocketVector)) return B_BAD_ADDRESS; // socketpair() int socketVector[2]; SyscallRestartWrapper error; error = common_socketpair(family, type, protocol, socketVector, false); if (error != B_OK) return error; // copy FDs back to userland if (user_memcpy(userSocketVector, socketVector, sizeof(socketVector)) != B_OK) { _user_close(socketVector[0]); _user_close(socketVector[1]); return B_BAD_ADDRESS; } return B_OK; } status_t _user_get_next_socket_stat(int family, uint32 *_cookie, struct net_stat *_stat) { // check parameters and copy cookie from userland if (_cookie == NULL || _stat == NULL) return B_BAD_VALUE; uint32 cookie; if (!IS_USER_ADDRESS(_stat) || !IS_USER_ADDRESS(_cookie) || user_memcpy(&cookie, _cookie, sizeof(cookie)) != B_OK) { return B_BAD_ADDRESS; } net_stat stat; SyscallRestartWrapper error; error = common_get_next_socket_stat(family, &cookie, &stat); if (error != B_OK) return error; // copy cookie and data back to userland if (user_memcpy(_cookie, &cookie, sizeof(cookie)) != B_OK || user_memcpy(_stat, &stat, sizeof(net_stat)) != B_OK) { return B_BAD_ADDRESS; } return B_OK; }