int dup2(int sockfd1, int sockfd2) #endif { FAR struct socket *psock1; FAR struct socket *psock2; int err; int ret; /* Lock the scheduler throughout the following */ sched_lock(); /* Get the socket structures underly both descriptors */ psock1 = sockfd_socket(sockfd1); psock2 = sockfd_socket(sockfd2); /* Verify that the sockfd1 and sockfd2 both refer to valid socket * descriptors and that sockfd2 corresponds to allocated socket */ if (!psock1 || !psock2 || psock1->s_crefs <= 0) { err = EBADF; goto errout; } /* If sockfd2 also valid, allocated socket, then we will have to * close it! */ if (psock2->s_crefs > 0) { net_close(sockfd2); } /* Duplicate the socket state */ ret = net_clone(psock1, psock2); if (ret < 0) { err = -ret; goto errout; } sched_unlock(); return OK; errout: sched_unlock(); errno = err; return ERROR; }
static inline void sched_dupsockets(FAR _TCB *tcb) { /* The parent task is the one at the head of the ready-to-run list */ FAR _TCB *rtcb = (FAR _TCB*)g_readytorun.head; FAR struct socket *parent; FAR struct socket *child; int i; /* Duplicate the socket descriptors of all sockets opened by the parent * task. */ if (rtcb->sockets) { /* Get pointers to the parent and child task socket lists */ parent = rtcb->sockets->sl_sockets; child = tcb->sockets->sl_sockets; /* Check each socket in the parent socket list */ for (i = 0; i < CONFIG_NSOCKET_DESCRIPTORS; i++) { /* Check if this parent socket is allocated. We can tell if the * socket is allocated because it will have a positive, non-zero * reference count. */ if (parent[i].s_crefs > 0) { /* Yes... duplicate it for the child */ (void)net_clone(&parent[i], &child[i]); } } } }
FAR char *telnetd_driver(int sd, FAR struct telnetd_s *daemon) { FAR struct telnetd_dev_s *priv; FAR struct socket *psock; FAR char *devpath = NULL; int ret; /* Allocate instance data for this driver */ priv = (FAR struct telnetd_dev_s*)malloc(sizeof(struct telnetd_dev_s)); if (!priv) { nlldbg("Failed to allocate the driver data structure\n"); return NULL; } /* Initialize the allocated driver instance */ sem_init(&priv->td_exclsem, 0, 1); priv->td_state = STATE_NORMAL; priv->td_crefs = 0; priv->td_pending = 0; priv->td_offset = 0; /* Clone the internal socket structure. We do this so that it will be * independent of threads and of socket descriptors (the original socket * instance resided in the daemon's socket array). */ psock = sockfd_socket(sd); if (!psock) { nlldbg("Failed to convert sd=%d to a socket structure\n", sd); goto errout_with_dev; } ret = net_clone(psock, &priv->td_psock); if (ret < 0) { nlldbg("net_clone failed: %d\n", ret); goto errout_with_dev; } /* And close the original */ psock_close(psock); /* Allocation a unique minor device number of the telnet drvier */ do { ret = sem_wait(&g_telnetdcommon.exclsem); if (ret < 0 && errno != -EINTR) { goto errout_with_dev; } } while (ret < 0); priv->td_minor = g_telnetdcommon.minor; g_telnetdcommon.minor++; sem_post(&g_telnetdcommon.exclsem); /* Create a path and name for the driver. */ ret = asprintf(&devpath, TELNETD_DEVFMT, priv->td_minor); if (ret < 0) { nlldbg("Failed to allocate the driver path\n"); goto errout_with_dev; } /* Register the driver */ ret = register_driver(devpath, &g_telnetdfops, 0666, priv); if (ret < 0) { nlldbg("Failed to register the driver %s: %d\n", devpath, ret); goto errout_with_devpath; } /* Return the path to the new telnet driver */ return devpath; errout_with_devpath: free(devpath); errout_with_dev: free(priv); return NULL; }