/**************************************************************************** * apps/netutils/usrsock_rpmsg/usrsock_rpmsg_server.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include "usrsock_rpmsg.h" struct usrsock_rpmsg_s { struct file *eventfp; pthread_mutex_t mutex; pthread_cond_t cond; struct iovec iov[CONFIG_NETUTILS_USRSOCK_NIOVEC]; struct socket socks[CONFIG_NETUTILS_USRSOCK_NSOCK_DESCRIPTORS]; struct rpmsg_endpoint *epts[CONFIG_NETUTILS_USRSOCK_NSOCK_DESCRIPTORS]; struct pollfd pfds[CONFIG_NETUTILS_USRSOCK_NSOCK_DESCRIPTORS + 1]; }; /**************************************************************************** * Private Function Prototypes ****************************************************************************/ static int usrsock_rpmsg_send_ack(struct rpmsg_endpoint *ept, uint8_t xid, int32_t result); static int usrsock_rpmsg_send_data_ack(struct rpmsg_endpoint *ept, struct usrsock_message_datareq_ack_s *ack, uint8_t xid, int32_t result, uint16_t valuelen, uint16_t valuelen_nontrunc); static int usrsock_rpmsg_send_event(struct rpmsg_endpoint *ept, int16_t usockid, uint16_t events); static int usrsock_rpmsg_socket_handler(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv_); static int usrsock_rpmsg_close_handler(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv_); static int usrsock_rpmsg_connect_handler(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv_); static int usrsock_rpmsg_sendto_handler(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv_); static int usrsock_rpmsg_recvfrom_handler(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv_); static int usrsock_rpmsg_setsockopt_handler(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv_); static int usrsock_rpmsg_getsockopt_handler(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv_); static int usrsock_rpmsg_getsockname_handler(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv_); static int usrsock_rpmsg_getpeername_handler(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv_); static int usrsock_rpmsg_bind_handler(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv_); static int usrsock_rpmsg_listen_handler(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv_); static int usrsock_rpmsg_accept_handler(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv_); static int usrsock_rpmsg_ioctl_handler(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv_); static void usrsock_rpmsg_ns_bind(struct rpmsg_device *rdev, void *priv_, const char *name, uint32_t dest); static void usrsock_rpmsg_ns_unbind(struct rpmsg_endpoint *ept); static int usrsock_rpmsg_ept_cb(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv); static int usrsock_rpmsg_notify_poll(struct usrsock_rpmsg_s *priv); static int usrsock_rpmsg_prepare_poll(struct usrsock_rpmsg_s *priv, struct pollfd *pfds); static bool usrsock_rpmsg_process_poll(struct usrsock_rpmsg_s *priv, struct pollfd *pfds, int count); /**************************************************************************** * Private Data ****************************************************************************/ static const rpmsg_ept_cb g_usrsock_rpmsg_handler[] = { [USRSOCK_REQUEST_SOCKET] = usrsock_rpmsg_socket_handler, [USRSOCK_REQUEST_CLOSE] = usrsock_rpmsg_close_handler, [USRSOCK_REQUEST_CONNECT] = usrsock_rpmsg_connect_handler, [USRSOCK_REQUEST_SENDTO] = usrsock_rpmsg_sendto_handler, [USRSOCK_REQUEST_RECVFROM] = usrsock_rpmsg_recvfrom_handler, [USRSOCK_REQUEST_SETSOCKOPT] = usrsock_rpmsg_setsockopt_handler, [USRSOCK_REQUEST_GETSOCKOPT] = usrsock_rpmsg_getsockopt_handler, [USRSOCK_REQUEST_GETSOCKNAME] = usrsock_rpmsg_getsockname_handler, [USRSOCK_REQUEST_GETPEERNAME] = usrsock_rpmsg_getpeername_handler, [USRSOCK_REQUEST_BIND] = usrsock_rpmsg_bind_handler, [USRSOCK_REQUEST_LISTEN] = usrsock_rpmsg_listen_handler, [USRSOCK_REQUEST_ACCEPT] = usrsock_rpmsg_accept_handler, [USRSOCK_REQUEST_IOCTL] = usrsock_rpmsg_ioctl_handler, }; /**************************************************************************** * Private Functions ****************************************************************************/ static int usrsock_rpmsg_send_ack(struct rpmsg_endpoint *ept, uint8_t xid, int32_t result) { struct usrsock_message_req_ack_s ack; ack.head.msgid = USRSOCK_MESSAGE_RESPONSE_ACK; ack.head.flags = (result == -EINPROGRESS); ack.xid = xid; ack.result = result; return rpmsg_send(ept, &ack, sizeof(ack)); } static int usrsock_rpmsg_send_data_ack(struct rpmsg_endpoint *ept, struct usrsock_message_datareq_ack_s *ack, uint8_t xid, int32_t result, uint16_t valuelen, uint16_t valuelen_nontrunc) { ack->reqack.head.msgid = USRSOCK_MESSAGE_RESPONSE_DATA_ACK; ack->reqack.head.flags = 0; ack->reqack.xid = xid; ack->reqack.result = result; if (result < 0) { result = 0; valuelen = 0; valuelen_nontrunc = 0; } else if (valuelen > valuelen_nontrunc) { valuelen = valuelen_nontrunc; } ack->valuelen = valuelen; ack->valuelen_nontrunc = valuelen_nontrunc; return rpmsg_send_nocopy(ept, ack, sizeof(*ack) + valuelen + result); } static int usrsock_rpmsg_send_event(struct rpmsg_endpoint *ept, int16_t usockid, uint16_t events) { struct usrsock_message_socket_event_s event; event.head.msgid = USRSOCK_MESSAGE_SOCKET_EVENT; event.head.flags = USRSOCK_MESSAGE_FLAG_EVENT; event.usockid = usockid; event.events = events; return rpmsg_send(ept, &event, sizeof(event)); } static int usrsock_rpmsg_socket_handler(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv_) { struct usrsock_request_socket_s *req = data; struct usrsock_rpmsg_s *priv = priv_; int i; int retr; int ret = -ENFILE; for (i = 0; i < CONFIG_NETUTILS_USRSOCK_NSOCK_DESCRIPTORS; i++) { pthread_mutex_lock(&priv->mutex); if (priv->socks[i].s_conn == NULL) { ret = psock_socket(req->domain, req->type, req->protocol, &priv->socks[i]); pthread_mutex_unlock(&priv->mutex); if (ret >= 0) { psock_fcntl(&priv->socks[i], F_SETFL, psock_fcntl(&priv->socks[i], F_GETFL) | O_NONBLOCK); priv->epts[i] = ept; ret = i; /* Return index as the usockid */ } break; } pthread_mutex_unlock(&priv->mutex); } retr = usrsock_rpmsg_send_ack(ept, req->head.xid, ret); if (retr >= 0 && ret >= 0 && req->type != SOCK_STREAM && req->type != SOCK_SEQPACKET) { pthread_mutex_lock(&priv->mutex); priv->pfds[ret].ptr = &priv->socks[ret]; priv->pfds[ret].events = POLLIN; usrsock_rpmsg_notify_poll(priv); pthread_mutex_unlock(&priv->mutex); retr = usrsock_rpmsg_send_event(ept, ret, USRSOCK_EVENT_SENDTO_READY); } return retr; } static int usrsock_rpmsg_close_handler(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv_) { struct usrsock_request_close_s *req = data; struct usrsock_rpmsg_s *priv = priv_; int ret = -EBADF; if (req->usockid >= 0 && req->usockid < CONFIG_NETUTILS_USRSOCK_NSOCK_DESCRIPTORS) { priv->pfds[req->usockid].ptr = NULL; priv->epts[req->usockid] = NULL; /* Signal and wait the poll thread to wakeup */ pthread_mutex_lock(&priv->mutex); usrsock_rpmsg_notify_poll(priv); pthread_cond_wait(&priv->cond, &priv->mutex); pthread_mutex_unlock(&priv->mutex); /* It's safe to close sock here */ ret = psock_close(&priv->socks[req->usockid]); } return usrsock_rpmsg_send_ack(ept, req->head.xid, ret); } static int usrsock_rpmsg_connect_handler(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv_) { struct usrsock_request_connect_s *req = data; struct usrsock_rpmsg_s *priv = priv_; bool inprogress = false; int retr; int ret = -EBADF; if (req->usockid >= 0 && req->usockid < CONFIG_NETUTILS_USRSOCK_NSOCK_DESCRIPTORS) { ret = psock_connect(&priv->socks[req->usockid], (const struct sockaddr *)(req + 1), req->addrlen); if (ret == -EINPROGRESS) { inprogress = true; ret = 0; } } retr = usrsock_rpmsg_send_ack(ept, req->head.xid, ret); if (retr >= 0 && ret >= 0 && priv->pfds[req->usockid].ptr == NULL) { pthread_mutex_lock(&priv->mutex); priv->pfds[req->usockid].ptr = &priv->socks[req->usockid]; priv->pfds[req->usockid].events = POLLIN; if (inprogress) { priv->pfds[req->usockid].events |= POLLOUT; } usrsock_rpmsg_notify_poll(priv); pthread_mutex_unlock(&priv->mutex); if (!inprogress) { retr = usrsock_rpmsg_send_event(ept, req->usockid, USRSOCK_EVENT_SENDTO_READY); } } return retr; } static int usrsock_rpmsg_sendto_handler(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv_) { struct usrsock_request_sendto_s *req; struct usrsock_rpmsg_s *priv = priv_; ssize_t ret = -EBADF; size_t total; int retr; int i; if (priv->iov[0].iov_base) { size_t hlen; struct msghdr msg = { }; req = priv->iov[0].iov_base; hlen = sizeof(*req) + req->addrlen; total = len; for (i = 0; i < CONFIG_NETUTILS_USRSOCK_NIOVEC; i++) { if (!priv->iov[i].iov_base) { priv->iov[i].iov_base = data; priv->iov[i].iov_len = len; rpmsg_hold_rx_buffer(ept, data); break; } total += priv->iov[i].iov_len; } if (i == CONFIG_NETUTILS_USRSOCK_NIOVEC) { ret = -ENOMEM; goto out; } /* Partial packet ? continue to fetch */ if (req->buflen > total - hlen) { return 0; } else if (req->buflen < total - hlen) { ret = -EINVAL; goto out; } /* Skip the sendto header from I/O vector */ priv->iov[0].iov_base = (char *)priv->iov[0].iov_base + hlen; priv->iov[0].iov_len -= hlen; msg.msg_name = req->addrlen ? (void *)(req + 1) : NULL; msg.msg_namelen = req->addrlen; msg.msg_iov = priv->iov; msg.msg_iovlen = i + 1; ret = psock_sendmsg(&priv->socks[req->usockid], &msg, req->flags); /* Recover the I/O vector */ priv->iov[0].iov_base = (char *)priv->iov[0].iov_base - hlen; priv->iov[0].iov_len += hlen; } else { req = data; if (req->usockid >= 0 && req->usockid < CONFIG_NETUTILS_USRSOCK_NSOCK_DESCRIPTORS) { total = sizeof(*req) + req->addrlen + req->buflen; if (total > len) { priv->iov[0].iov_base = data; priv->iov[0].iov_len = len; rpmsg_hold_rx_buffer(ept, data); return 0; } else { ret = psock_sendto(&priv->socks[req->usockid], (const void *)(req + 1) + req->addrlen, req->buflen, req->flags, req->addrlen ? (const struct sockaddr *)(req + 1) : NULL, req->addrlen); } } } out: retr = usrsock_rpmsg_send_ack(ept, req->head.xid, ret); if (retr >= 0 && ret >= 0) { /* Assume the new buffer can be accepted until return -EAGAIN */ retr = usrsock_rpmsg_send_event(ept, req->usockid, USRSOCK_EVENT_SENDTO_READY); } else if (ret == -EAGAIN) { pthread_mutex_lock(&priv->mutex); priv->pfds[req->usockid].events |= POLLOUT; usrsock_rpmsg_notify_poll(priv); pthread_mutex_unlock(&priv->mutex); } if (priv->iov[0].iov_base) { for (i = 0; i < CONFIG_NETUTILS_USRSOCK_NIOVEC; i++) { if (priv->iov[i].iov_base == NULL) { break; } rpmsg_release_rx_buffer(ept, priv->iov[i].iov_base); priv->iov[i].iov_base = NULL; priv->iov[i].iov_len = 0; } } return retr; } static int usrsock_rpmsg_recvfrom_handler(struct rpmsg_endpoint *ept, void *data, size_t len_, uint32_t src, void *priv_) { struct usrsock_request_recvfrom_s *req = data; struct usrsock_message_datareq_ack_s *ack; struct usrsock_rpmsg_s *priv = priv_; socklen_t outaddrlen = req->max_addrlen; socklen_t inaddrlen = req->max_addrlen; size_t buflen = req->max_buflen; ssize_t ret = -EBADF; uint32_t len; int retr; ack = rpmsg_get_tx_payload_buffer(ept, &len, true); if (sizeof(*ack) + inaddrlen + buflen > len) { buflen = len - sizeof(*ack) - inaddrlen; } if (req->usockid >= 0 && req->usockid < CONFIG_NETUTILS_USRSOCK_NSOCK_DESCRIPTORS) { ret = psock_recvfrom(&priv->socks[req->usockid], (void *)(ack + 1) + inaddrlen, buflen, req->flags, outaddrlen ? (struct sockaddr *)(ack + 1) : NULL, outaddrlen ? &outaddrlen : NULL); if (ret > 0 && outaddrlen < inaddrlen) { memcpy((void *)(ack + 1) + outaddrlen, (void *)(ack + 1) + inaddrlen, ret); } } retr = usrsock_rpmsg_send_data_ack(ept, ack, req->head.xid, ret, inaddrlen, outaddrlen); if (retr >= 0 && (ret >= 0 || ret == -EAGAIN)) { pthread_mutex_lock(&priv->mutex); priv->pfds[req->usockid].events |= POLLIN; usrsock_rpmsg_notify_poll(priv); pthread_mutex_unlock(&priv->mutex); } return retr; } static int usrsock_rpmsg_setsockopt_handler(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv_) { struct usrsock_request_setsockopt_s *req = data; struct usrsock_rpmsg_s *priv = priv_; int ret = -EBADF; if (req->usockid >= 0 && req->usockid < CONFIG_NETUTILS_USRSOCK_NSOCK_DESCRIPTORS) { ret = psock_setsockopt(&priv->socks[req->usockid], req->level, req->option, req + 1, req->valuelen); } return usrsock_rpmsg_send_ack(ept, req->head.xid, ret); } static int usrsock_rpmsg_getsockopt_handler(struct rpmsg_endpoint *ept, void *data, size_t len_, uint32_t src, void *priv_) { struct usrsock_request_getsockopt_s *req = data; struct usrsock_message_datareq_ack_s *ack; struct usrsock_rpmsg_s *priv = priv_; socklen_t optlen = req->max_valuelen; int ret = -EBADF; uint32_t len; ack = rpmsg_get_tx_payload_buffer(ept, &len, true); if (req->usockid >= 0 && req->usockid < CONFIG_NETUTILS_USRSOCK_NSOCK_DESCRIPTORS) { ret = psock_getsockopt(&priv->socks[req->usockid], req->level, req->option, ack + 1, &optlen); } return usrsock_rpmsg_send_data_ack(ept, ack, req->head.xid, ret, optlen, optlen); } static int usrsock_rpmsg_getsockname_handler(struct rpmsg_endpoint *ept, void *data, size_t len_, uint32_t src, void *priv_) { struct usrsock_request_getsockname_s *req = data; struct usrsock_message_datareq_ack_s *ack; struct usrsock_rpmsg_s *priv = priv_; socklen_t outaddrlen = req->max_addrlen; socklen_t inaddrlen = req->max_addrlen; int ret = -EBADF; uint32_t len; ack = rpmsg_get_tx_payload_buffer(ept, &len, true); if (req->usockid >= 0 && req->usockid < CONFIG_NETUTILS_USRSOCK_NSOCK_DESCRIPTORS) { ret = psock_getsockname(&priv->socks[req->usockid], (struct sockaddr *)(ack + 1), &outaddrlen); } return usrsock_rpmsg_send_data_ack(ept, ack, req->head.xid, ret, inaddrlen, outaddrlen); } static int usrsock_rpmsg_getpeername_handler(struct rpmsg_endpoint *ept, void *data, size_t len_, uint32_t src, void *priv_) { struct usrsock_request_getpeername_s *req = data; struct usrsock_message_datareq_ack_s *ack; struct usrsock_rpmsg_s *priv = priv_; socklen_t outaddrlen = req->max_addrlen; socklen_t inaddrlen = req->max_addrlen; int ret = -EBADF; uint32_t len; ack = rpmsg_get_tx_payload_buffer(ept, &len, true); if (req->usockid >= 0 && req->usockid < CONFIG_NETUTILS_USRSOCK_NSOCK_DESCRIPTORS) { ret = psock_getpeername(&priv->socks[req->usockid], (struct sockaddr *)(ack + 1), &outaddrlen); } return usrsock_rpmsg_send_data_ack(ept, ack, req->head.xid, ret, inaddrlen, outaddrlen); } static int usrsock_rpmsg_bind_handler(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv_) { struct usrsock_request_bind_s *req = data; struct usrsock_rpmsg_s *priv = priv_; int ret = -EBADF; if (req->usockid >= 0 && req->usockid < CONFIG_NETUTILS_USRSOCK_NSOCK_DESCRIPTORS) { ret = psock_bind(&priv->socks[req->usockid], (const struct sockaddr *)(req + 1), req->addrlen); } return usrsock_rpmsg_send_ack(ept, req->head.xid, ret); } static int usrsock_rpmsg_listen_handler(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv_) { struct usrsock_request_listen_s *req = data; struct usrsock_rpmsg_s *priv = priv_; int retr; int ret = -EBADF; if (req->usockid >= 0 && req->usockid < CONFIG_NETUTILS_USRSOCK_NSOCK_DESCRIPTORS) { ret = psock_listen(&priv->socks[req->usockid], req->backlog); } retr = usrsock_rpmsg_send_ack(ept, req->head.xid, ret); if (retr >= 0 && ret >= 0) { pthread_mutex_lock(&priv->mutex); priv->pfds[req->usockid].ptr = &priv->socks[req->usockid]; priv->pfds[req->usockid].events = POLLIN; usrsock_rpmsg_notify_poll(priv); pthread_mutex_unlock(&priv->mutex); } return retr; } static int usrsock_rpmsg_accept_handler(struct rpmsg_endpoint *ept, void *data, size_t len_, uint32_t src, void *priv_) { struct usrsock_request_accept_s *req = data; struct usrsock_message_datareq_ack_s *ack; struct usrsock_rpmsg_s *priv = priv_; socklen_t outaddrlen = req->max_addrlen; socklen_t inaddrlen = req->max_addrlen; int ret = -EBADF; uint32_t len; int i = 0; int retr; ack = rpmsg_get_tx_payload_buffer(ept, &len, true); if (req->usockid >= 0 && req->usockid < CONFIG_NETUTILS_USRSOCK_NSOCK_DESCRIPTORS) { ret = -ENFILE; /* Assume no free socket handler */ for (i = 0; i < CONFIG_NETUTILS_USRSOCK_NSOCK_DESCRIPTORS; i++) { pthread_mutex_lock(&priv->mutex); if (priv->socks[i].s_conn == NULL) { ret = psock_accept(&priv->socks[req->usockid], outaddrlen ? (struct sockaddr *)(ack + 1) : NULL, outaddrlen ? &outaddrlen : NULL, &priv->socks[i]); pthread_mutex_unlock(&priv->mutex); if (ret >= 0) { psock_fcntl(&priv->socks[i], F_SETFL, psock_fcntl(&priv->socks[i], F_GETFL) | O_NONBLOCK); priv->epts[i] = ept; /* Append index as usockid to the payload */ if (outaddrlen <= inaddrlen) { *(int16_t *)((void *)(ack + 1) + outaddrlen) = i; } else { *(int16_t *)((void *)(ack + 1) + inaddrlen) = i; } ret = sizeof(int16_t); /* Return usockid size */ } break; } pthread_mutex_unlock(&priv->mutex); } } retr = usrsock_rpmsg_send_data_ack(ept, ack, req->head.xid, ret, inaddrlen, outaddrlen); if (retr >= 0 && ret >= 0) { pthread_mutex_lock(&priv->mutex); priv->pfds[i].ptr = &priv->socks[i]; priv->pfds[i].events = POLLIN; usrsock_rpmsg_notify_poll(priv); pthread_mutex_unlock(&priv->mutex); usrsock_rpmsg_send_event(ept, i, USRSOCK_EVENT_SENDTO_READY); } return retr; } static int usrsock_rpmsg_ioctl_handler(struct rpmsg_endpoint *ept, void *data, size_t len_, uint32_t src, void *priv_) { struct usrsock_request_ioctl_s *req = data; struct usrsock_message_datareq_ack_s *ack; struct usrsock_rpmsg_s *priv = priv_; int ret = -EBADF; uint32_t len; ack = rpmsg_get_tx_payload_buffer(ept, &len, true); if (req->usockid >= 0 && req->usockid < CONFIG_NETUTILS_USRSOCK_NSOCK_DESCRIPTORS) { memcpy(ack + 1, req + 1, req->arglen); ret = psock_ioctl(&priv->socks[req->usockid], req->cmd, (unsigned long)(ack + 1)); } return usrsock_rpmsg_send_data_ack(ept, ack, req->head.xid, ret, req->arglen, req->arglen); } #ifdef CONFIG_NETDB_DNSCLIENT static int usrsock_rpmsg_send_dns_event(void *arg, struct sockaddr *addr, socklen_t addrlen) { struct rpmsg_endpoint *ept = arg; struct usrsock_rpmsg_dns_event_s *dns; uint32_t len; dns = rpmsg_get_tx_payload_buffer(ept, &len, true); dns->head.msgid = USRSOCK_RPMSG_DNS_EVENT; dns->head.flags = USRSOCK_MESSAGE_FLAG_EVENT; dns->addrlen = addrlen; memcpy(dns + 1, addr, addrlen); return rpmsg_send_nocopy(ept, dns, sizeof(*dns) + addrlen); } #endif static void usrsock_rpmsg_ns_bind(struct rpmsg_device *rdev, void *priv_, const char *name, uint32_t dest) { struct usrsock_rpmsg_s *priv = priv_; struct rpmsg_endpoint *ept; int ret; if (strcmp(name, USRSOCK_RPMSG_EPT_NAME)) { return; } ept = zalloc(sizeof(struct rpmsg_endpoint)); if (!ept) { return; } ept->priv = priv; ret = rpmsg_create_ept(ept, rdev, USRSOCK_RPMSG_EPT_NAME, RPMSG_ADDR_ANY, dest, usrsock_rpmsg_ept_cb, usrsock_rpmsg_ns_unbind); if (ret) { free(ept); return; } #ifdef CONFIG_NETDB_DNSCLIENT dns_register_notify(usrsock_rpmsg_send_dns_event, ept); #endif } static void usrsock_rpmsg_ns_unbind(struct rpmsg_endpoint *ept) { struct usrsock_rpmsg_s *priv = ept->priv; struct socket *socks[CONFIG_NETUTILS_USRSOCK_NSOCK_DESCRIPTORS]; int count = 0; int i; #ifdef CONFIG_NETDB_DNSCLIENT dns_unregister_notify(usrsock_rpmsg_send_dns_event, ept); #endif /* Collect all socks belong to the dead client */ for (i = 0; i < CONFIG_NETUTILS_USRSOCK_NSOCK_DESCRIPTORS; i++) { if (priv->epts[i] == ept) { socks[count++] = &priv->socks[i]; priv->pfds[i].ptr = NULL; priv->epts[i] = NULL; } } /* Signal and wait the poll thread to wakeup */ pthread_mutex_lock(&priv->mutex); usrsock_rpmsg_notify_poll(priv); pthread_cond_wait(&priv->cond, &priv->mutex); pthread_mutex_unlock(&priv->mutex); /* It's safe to close all socks here */ for (i = 0; i < count; i++) { psock_close(socks[i]); } rpmsg_destroy_ept(ept); } static int usrsock_rpmsg_ept_cb(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv_) { struct usrsock_request_common_s *common = data; struct usrsock_rpmsg_s *priv = priv_; if (priv->iov[0].iov_base) { return usrsock_rpmsg_sendto_handler(ept, data, len, src, priv); } else if (common->reqid >= 0 && common->reqid < USRSOCK_REQUEST__MAX) { return g_usrsock_rpmsg_handler[common->reqid](ept, data, len, src, priv); } return -EINVAL; } static int usrsock_rpmsg_notify_poll(struct usrsock_rpmsg_s *priv) { eventfd_t value = 1ULL; return file_write(priv->eventfp, &value, sizeof(value)); } static int usrsock_rpmsg_prepare_poll(struct usrsock_rpmsg_s *priv, struct pollfd *pfds) { int count = 0; int i; pthread_mutex_lock(&priv->mutex); /* Signal the worker it's safe to close sock */ pthread_cond_signal(&priv->cond); for (i = 0; i < CONFIG_NETUTILS_USRSOCK_NSOCK_DESCRIPTORS; i++) { if (priv->pfds[i].ptr) { pfds[count] = priv->pfds[i]; pfds[count++].events |= POLLERR | POLLHUP | POLLSOCK; } } pfds[count].ptr = priv->eventfp; pfds[count++].events = POLLIN | POLLFILE; pthread_mutex_unlock(&priv->mutex); return count; } static bool usrsock_rpmsg_process_poll(struct usrsock_rpmsg_s *priv, struct pollfd *pfds, int count) { bool prepare = false; int i; for (i = 0; i < count; i++) { pthread_mutex_lock(&priv->mutex); if (pfds[i].ptr == priv->eventfp) { if (pfds[i].revents & POLLIN) { eventfd_t value; file_read(priv->eventfp, &value, sizeof(value)); } prepare = true; } else { int j; j = (struct socket *)pfds[i].ptr - priv->socks; if (priv->epts[j] != NULL) { int events = 0; if (pfds[i].revents & POLLIN) { events |= USRSOCK_EVENT_RECVFROM_AVAIL; /* Stop poll in until recv get called */ pfds[i].events &= ~POLLIN; priv->pfds[j].events &= ~POLLIN; } if (pfds[i].revents & POLLOUT) { events |= USRSOCK_EVENT_SENDTO_READY; /* Stop poll out until send get called */ pfds[i].events &= ~POLLOUT; priv->pfds[j].events &= ~POLLOUT; } if (pfds[i].revents & (POLLHUP | POLLERR)) { events |= USRSOCK_EVENT_REMOTE_CLOSED; /* Stop poll at all */ pfds[i].ptr = NULL; priv->pfds[j].ptr = NULL; } if (events != 0) { usrsock_rpmsg_send_event(priv->epts[j], j, events); } } } pthread_mutex_unlock(&priv->mutex); } return prepare; } /**************************************************************************** * Public Functions ****************************************************************************/ int main(int argc, char *argv[]) { struct pollfd pfds[CONFIG_NETUTILS_USRSOCK_NSOCK_DESCRIPTORS + 1]; struct usrsock_rpmsg_s *priv; bool prepare = true; int ret; int fd; priv = calloc(1, sizeof(*priv)); if (priv == NULL) { return -ENOMEM; } pthread_mutex_init(&priv->mutex, NULL); pthread_cond_init(&priv->cond, NULL); fd = eventfd(0, 0); if (fd < 0) { ret = -errno; goto free_priv; } ret = fs_getfilep(fd, &priv->eventfp); if (ret < 0) { goto free_fd; } ret = rpmsg_register_callback(priv, NULL, NULL, usrsock_rpmsg_ns_bind); if (ret < 0) { goto free_fd; } while (1) { /* Collect all socks which need monitor */ if (prepare) { ret = usrsock_rpmsg_prepare_poll(priv, pfds); } /* Monitor the state change from them */ if (poll(pfds, ret, -1) > 0) { /* Process all changed socks */ prepare = usrsock_rpmsg_process_poll(priv, pfds, ret); } } rpmsg_unregister_callback(priv, NULL, NULL, usrsock_rpmsg_ns_bind); free_fd: close(fd); free_priv: pthread_cond_destroy(&priv->cond); pthread_mutex_destroy(&priv->mutex); free(priv); return ret; }