int bluetooth_input(FAR struct radio_driver_s *radio, FAR struct iob_s *framelist, FAR struct bluetooth_frame_meta_s *meta) { FAR struct bluetooth_conn_s *conn; FAR struct iob_s *frame; FAR struct iob_s *next; int ret = OK; /* Check if there is a connection that will accept this packet */ conn = bluetooth_conn_active(meta); if (conn != NULL) { /* Setup for the application callback (NOTE: These should not be * used by PF_BLUETOOTH sockets). */ radio->r_dev.d_appdata = radio->r_dev.d_buf; radio->r_dev.d_len = 0; radio->r_dev.d_sndlen = 0; /* The framelist probably contains only a single frame, but we will * process it as a list of frames. */ for (frame = framelist; frame != NULL; frame = next) { /* Remove the frame from the list */ next = frame->io_flink; frame->io_flink = NULL; /* Add the frame to the RX queue */ ret = bluetooth_queue_frame(conn, frame, meta); if (ret < 0) { nerr("ERROR: Failed to queue frame: %d\n", ret); iob_free(frame); } } /* Perform the application callback. The frame may be processed now * if there is a user wait for an incoming frame. Or it may pend in * the RX queue until some user process reads the frame. NOTE: The * return value from bluetooth_callback would distinguish these * cases: BLUETOOTH_NEWDATA will still be processed if the frame * was not consumed. */ (void)bluetooth_callback(radio, conn, BLUETOOTH_NEWDATA); } else { nwarn("WARNING: No listener\n"); } return ret; }
int ftpc_chmod(SESSION handle, FAR const char *path, FAR const char *mode) { FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; /* Does the server support the size CHMOD command? */ if (FTPC_HAS_CHMOD(session)) { (void)ftpc_cmd(session, "SITE CHMOD %s %s", path, mode); /* Check for "502 Command not implemented" */ if (session->code == 502) { /* No.. the server does not support the SITE CHMOD command */ FTPC_CLR_CHMOD(session); } return OK; } else { nwarn("WARNING: Server does not support SITE CHMOD\n"); } return ERROR; }
static int netdev_pktradio_ioctl(FAR struct socket *psock, int cmd, unsigned long arg) { FAR struct net_driver_s *dev; FAR char *ifname; int ret = -ENOTTY; if (arg != 0ul) { if (WL_ISPKTRADIOCMD(cmd)) { /* Get the packet radio device to receive the radio IOCTL * command */ FAR struct pktradio_ifreq_s *cmddata = (FAR struct pktradio_ifreq_s *)((uintptr_t)arg); ifname = cmddata->pifr_name; } else { /* Not a packet radio IOCTL command */ nwarn("WARNING: Not a packet radio IOCTL command: %d\n", cmd); return -ENOTTY; } /* Find the device with this name */ dev = netdev_findbyname(ifname); if (dev != NULL && dev->d_lltype == NET_LL_PKTRADIO) { /* Perform the device IOCTL */ ret = dev->d_ioctl(dev, cmd, arg); } } return ret; }
static int tcpecho_server(void) { int i, maxi, listenfd, connfd, sockfd; int nready; int ret; ssize_t n; char buf[TCPECHO_MAXLINE]; socklen_t clilen; bool stop = false; struct pollfd client[CONFIG_EXAMPLES_TCPECHO_NCONN]; struct sockaddr_in cliaddr, servaddr; listenfd = socket(AF_INET, SOCK_STREAM, 0); if (listenfd < 0) { perror("ERROR: failed to create socket.\n"); return ERROR; } bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(CONFIG_EXAMPLES_TCPECHO_PORT); ret = bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)); if (ret < 0) { perror("ERROR: failed to bind socket.\n"); return ERROR; } ninfo("start listening on port: %d\n", CONFIG_EXAMPLES_TCPECHO_PORT); ret = listen(listenfd, CONFIG_EXAMPLES_TCPECHO_BACKLOG); if (ret < 0) { perror("ERROR: failed to start listening\n"); return ERROR; } client[0].fd = listenfd; client[0].events = POLLRDNORM; for (i = 1; i < CONFIG_EXAMPLES_TCPECHO_NCONN; i++) { client[i].fd = -1; /* -1 indicates available entry */ } maxi = 0; /* max index into client[] array */ while (!stop) { nready = poll(client, maxi+1, TCPECHO_POLLTIMEOUT); if (client[0].revents & POLLRDNORM) { /* new client connection */ clilen = sizeof(cliaddr); connfd = accept(listenfd, (struct sockaddr*)&cliaddr, &clilen); ninfo("new client: %s\n", inet_ntoa(cliaddr.sin_addr)); for (i = 1; i < CONFIG_EXAMPLES_TCPECHO_NCONN; i++) { if (client[i].fd < 0) { client[i].fd = connfd; /* save descriptor */ break; } } if (i == CONFIG_EXAMPLES_TCPECHO_NCONN) { perror("ERROR: too many clients"); return ERROR; } client[i].events = POLLRDNORM; if (i > maxi) { maxi = i; /* max index in client[] array */ } if (--nready <= 0) { continue; /* no more readable descriptors */ } } for (i = 1; i <= maxi; i++) { /* check all clients for data */ if ((sockfd = client[i].fd) < 0) { continue; } if (client[i].revents & (POLLRDNORM | POLLERR)) { if ( (n = read(sockfd, buf, TCPECHO_MAXLINE)) < 0) { if (errno == ECONNRESET) { /* connection reset by client */ nwarn("WARNING: client[%d] aborted connection\n", i); close(sockfd); client[i].fd = -1; } else { perror("ERROR: readline error\n"); close(sockfd); client[i].fd = -1; } } else if (n == 0) { /* connection closed by client */ nwarn("WARNING: client[%d] closed connection\n", i); close(sockfd); client[i].fd = -1; } else { if (strcmp(buf, "exit\r\n") == 0) { nwarn("WARNING: client[%d] closed connection\n", i); close(sockfd); client[i].fd = -1; } else { write(sockfd, buf, n); } } if (--nready <= 0) { break; /* no more readable descriptors */ } } } } for (i = 0; i <= maxi; i++) { if (client[i].fd < 0) { continue; } close(client[i].fd); } return ret; }
void netdriver_loop(void) { FAR struct eth_hdr_s *eth; /* Check for new frames. If so, then poll the network for new XMIT data */ net_lock(); (void)devif_poll(&g_sim_dev, sim_txpoll); net_unlock(); /* netdev_read will return 0 on a timeout event and >0 on a data received event */ g_sim_dev.d_len = netdev_read((FAR unsigned char *)g_sim_dev.d_buf, CONFIG_NET_ETH_MTU); /* Disable preemption through to the following so that it behaves a little more * like an interrupt (otherwise, the following logic gets pre-empted an behaves * oddly. */ sched_lock(); if (g_sim_dev.d_len > 0) { /* Data received event. Check for valid Ethernet header with destination == our * MAC address */ eth = BUF; if (g_sim_dev.d_len > ETH_HDRLEN) { int is_ours; /* Figure out if this ethernet frame is addressed to us. This affects * what we're willing to receive. Note that in promiscuous mode, the * up_comparemac will always return 0. */ is_ours = (up_comparemac(eth->dest, &g_sim_dev.d_mac.ether) == 0); #ifdef CONFIG_NET_PKT /* When packet sockets are enabled, feed the frame into the packet * tap. */ if (is_ours) { pkt_input(&g_sim_dev); } #endif /* CONFIG_NET_PKT */ /* We only accept IP packets of the configured type and ARP packets */ #ifdef CONFIG_NET_IPv4 if (eth->type == HTONS(ETHTYPE_IP) && is_ours) { ninfo("IPv4 frame\n"); /* Handle ARP on input then give the IPv4 packet to the network * layer */ arp_ipin(&g_sim_dev); ipv4_input(&g_sim_dev); /* If the above function invocation resulted in data that * should be sent out on the network, the global variable * d_len is set to a value > 0. */ if (g_sim_dev.d_len > 0) { /* Update the Ethernet header with the correct MAC address */ #ifdef CONFIG_NET_IPv6 if (IFF_IS_IPv4(g_sim_dev.d_flags)) #endif { arp_out(&g_sim_dev); } #ifdef CONFIG_NET_IPv6 else { neighbor_out(&g_sim_dev); } #endif /* And send the packet */ netdev_send(g_sim_dev.d_buf, g_sim_dev.d_len); } } else #endif /* CONFIG_NET_IPv4 */ #ifdef CONFIG_NET_IPv6 if (eth->type == HTONS(ETHTYPE_IP6) && is_ours) { ninfo("Iv6 frame\n"); /* Give the IPv6 packet to the network layer */ ipv6_input(&g_sim_dev); /* If the above function invocation resulted in data that * should be sent out on the network, the global variable * d_len is set to a value > 0. */ if (g_sim_dev.d_len > 0) { /* Update the Ethernet header with the correct MAC address */ #ifdef CONFIG_NET_IPv4 if (IFF_IS_IPv4(g_sim_dev.d_flags)) { arp_out(&g_sim_dev); } else #endif #ifdef CONFIG_NET_IPv6 { neighbor_out(&g_sim_dev); } #endif /* CONFIG_NET_IPv6 */ /* And send the packet */ netdev_send(g_sim_dev.d_buf, g_sim_dev.d_len); } } else #endif/* CONFIG_NET_IPv6 */ #ifdef CONFIG_NET_ARP if (eth->type == htons(ETHTYPE_ARP)) { arp_arpin(&g_sim_dev); /* If the above function invocation resulted in data that * should be sent out on the network, the global variable * d_len is set to a value > 0. */ if (g_sim_dev.d_len > 0) { netdev_send(g_sim_dev.d_buf, g_sim_dev.d_len); } } else #endif { nwarn("WARNING: Unsupported Ethernet type %u\n", eth->type); } } } /* Otherwise, it must be a timeout event */ else if (timer_expired(&g_periodic_timer)) { timer_reset(&g_periodic_timer); devif_timer(&g_sim_dev, sim_txpoll); } sched_unlock(); }
static uint16_t psock_send_interrupt(FAR struct net_driver_s *dev, FAR void *pvconn, FAR void *pvpriv, uint16_t flags) { FAR struct tcp_conn_s *conn = (FAR struct tcp_conn_s *)pvconn; FAR struct socket *psock = (FAR struct socket *)pvpriv; #ifdef CONFIG_NETDEV_MULTINIC /* The TCP socket is connected and, hence, should be bound to a device. * Make sure that the polling device is the one that we are bound to. */ DEBUGASSERT(conn->dev != NULL); if (dev != conn->dev) { return flags; } #endif ninfo("flags: %04x\n", flags); /* If this packet contains an acknowledgement, then update the count of * acknowledged bytes. */ if ((flags & TCP_ACKDATA) != 0) { FAR struct tcp_wrbuffer_s *wrb; FAR struct tcp_hdr_s *tcp; FAR sq_entry_t *entry; FAR sq_entry_t *next; uint32_t ackno; /* Get the offset address of the TCP header */ #ifdef CONFIG_NET_IPv4 #ifdef CONFIG_NET_IPv6 if (conn->domain == PF_INET) #endif { DEBUGASSERT(IFF_IS_IPv4(dev->d_flags)); tcp = TCPIPv4BUF; } #endif /* CONFIG_NET_IPv4 */ #ifdef CONFIG_NET_IPv6 #ifdef CONFIG_NET_IPv4 else #endif { DEBUGASSERT(IFF_IS_IPv6(dev->d_flags)); tcp = TCPIPv6BUF; } #endif /* CONFIG_NET_IPv6 */ /* Get the ACK number from the TCP header */ ackno = tcp_getsequence(tcp->ackno); ninfo("ACK: ackno=%u flags=%04x\n", ackno, flags); /* Look at every write buffer in the unacked_q. The unacked_q * holds write buffers that have been entirely sent, but which * have not yet been ACKed. */ for (entry = sq_peek(&conn->unacked_q); entry; entry = next) { uint32_t lastseq; /* Check of some or all of this write buffer has been ACKed. */ next = sq_next(entry); wrb = (FAR struct tcp_wrbuffer_s *)entry; /* If the ACKed sequence number is greater than the start * sequence number of the write buffer, then some or all of * the write buffer has been ACKed. */ if (ackno > WRB_SEQNO(wrb)) { /* Get the sequence number at the end of the data */ lastseq = WRB_SEQNO(wrb) + WRB_PKTLEN(wrb); ninfo("ACK: wrb=%p seqno=%u lastseq=%u pktlen=%u ackno=%u\n", wrb, WRB_SEQNO(wrb), lastseq, WRB_PKTLEN(wrb), ackno); /* Has the entire buffer been ACKed? */ if (ackno >= lastseq) { ninfo("ACK: wrb=%p Freeing write buffer\n", wrb); /* Yes... Remove the write buffer from ACK waiting queue */ sq_rem(entry, &conn->unacked_q); /* And return the write buffer to the pool of free buffers */ tcp_wrbuffer_release(wrb); } else { unsigned int trimlen; /* No, then just trim the ACKed bytes from the beginning * of the write buffer. This will free up some I/O buffers * that can be reused while are still sending the last * buffers in the chain. */ trimlen = ackno - WRB_SEQNO(wrb); if (trimlen > WRB_SENT(wrb)) { /* More data has been ACKed then we have sent? */ trimlen = WRB_SENT(wrb); } ninfo("ACK: wrb=%p trim %u bytes\n", wrb, trimlen); WRB_TRIM(wrb, trimlen); WRB_SEQNO(wrb) = ackno; WRB_SENT(wrb) -= trimlen; /* Set the new sequence number for what remains */ ninfo("ACK: wrb=%p seqno=%u pktlen=%u\n", wrb, WRB_SEQNO(wrb), WRB_PKTLEN(wrb)); } } } /* A special case is the head of the write_q which may be partially * sent and so can still have un-ACKed bytes that could get ACKed * before the entire write buffer has even been sent. */ wrb = (FAR struct tcp_wrbuffer_s *)sq_peek(&conn->write_q); if (wrb && WRB_SENT(wrb) > 0 && ackno > WRB_SEQNO(wrb)) { uint32_t nacked; /* Number of bytes that were ACKed */ nacked = ackno - WRB_SEQNO(wrb); if (nacked > WRB_SENT(wrb)) { /* More data has been ACKed then we have sent? ASSERT? */ nacked = WRB_SENT(wrb); } ninfo("ACK: wrb=%p seqno=%u nacked=%u sent=%u ackno=%u\n", wrb, WRB_SEQNO(wrb), nacked, WRB_SENT(wrb), ackno); /* Trim the ACKed bytes from the beginning of the write buffer. */ WRB_TRIM(wrb, nacked); WRB_SEQNO(wrb) = ackno; WRB_SENT(wrb) -= nacked; ninfo("ACK: wrb=%p seqno=%u pktlen=%u sent=%u\n", wrb, WRB_SEQNO(wrb), WRB_PKTLEN(wrb), WRB_SENT(wrb)); } } /* Check for a loss of connection */ else if ((flags & TCP_DISCONN_EVENTS) != 0) { ninfo("Lost connection: %04x\n", flags); if (psock->s_conn != NULL) { /* Report not connected */ net_lostconnection(psock, flags); } /* Free write buffers and terminate polling */ psock_lost_connection(psock, conn); return flags; } /* Check if we are being asked to retransmit data */ else if ((flags & TCP_REXMIT) != 0) { FAR struct tcp_wrbuffer_s *wrb; FAR sq_entry_t *entry; ninfo("REXMIT: %04x\n", flags); /* If there is a partially sent write buffer at the head of the * write_q? Has anything been sent from that write buffer? */ wrb = (FAR struct tcp_wrbuffer_s *)sq_peek(&conn->write_q); ninfo("REXMIT: wrb=%p sent=%u\n", wrb, wrb ? WRB_SENT(wrb) : 0); if (wrb != NULL && WRB_SENT(wrb) > 0) { FAR struct tcp_wrbuffer_s *tmp; uint16_t sent; /* Yes.. Reset the number of bytes sent sent from the write buffer */ sent = WRB_SENT(wrb); if (conn->unacked > sent) { conn->unacked -= sent; } else { conn->unacked = 0; } if (conn->sent > sent) { conn->sent -= sent; } else { conn->sent = 0; } WRB_SENT(wrb) = 0; ninfo("REXMIT: wrb=%p sent=%u, conn unacked=%d sent=%d\n", wrb, WRB_SENT(wrb), conn->unacked, conn->sent); /* Increment the retransmit count on this write buffer. */ if (++WRB_NRTX(wrb) >= TCP_MAXRTX) { nwarn("WARNING: Expiring wrb=%p nrtx=%u\n", wrb, WRB_NRTX(wrb)); /* The maximum retry count as been exhausted. Remove the write * buffer at the head of the queue. */ tmp = (FAR struct tcp_wrbuffer_s *)sq_remfirst(&conn->write_q); DEBUGASSERT(tmp == wrb); UNUSED(tmp); /* And return the write buffer to the free list */ tcp_wrbuffer_release(wrb); /* NOTE expired is different from un-ACKed, it is designed to * represent the number of segments that have been sent, * retransmitted, and un-ACKed, if expired is not zero, the * connection will be closed. * * field expired can only be updated at TCP_ESTABLISHED state */ conn->expired++; } } /* Move all segments that have been sent but not ACKed to the write * queue again note, the un-ACKed segments are put at the head of the * write_q so they can be resent as soon as possible. */ while ((entry = sq_remlast(&conn->unacked_q)) != NULL) { wrb = (FAR struct tcp_wrbuffer_s *)entry; uint16_t sent; /* Reset the number of bytes sent sent from the write buffer */ sent = WRB_SENT(wrb); if (conn->unacked > sent) { conn->unacked -= sent; } else { conn->unacked = 0; } if (conn->sent > sent) { conn->sent -= sent; } else { conn->sent = 0; } WRB_SENT(wrb) = 0; ninfo("REXMIT: wrb=%p sent=%u, conn unacked=%d sent=%d\n", wrb, WRB_SENT(wrb), conn->unacked, conn->sent); /* Free any write buffers that have exceed the retry count */ if (++WRB_NRTX(wrb) >= TCP_MAXRTX) { nwarn("WARNING: Expiring wrb=%p nrtx=%u\n", wrb, WRB_NRTX(wrb)); /* Return the write buffer to the free list */ tcp_wrbuffer_release(wrb); /* NOTE expired is different from un-ACKed, it is designed to * represent the number of segments that have been sent, * retransmitted, and un-ACKed, if expired is not zero, the * connection will be closed. * * field expired can only be updated at TCP_ESTABLISHED state */ conn->expired++; continue; } else { /* Insert the write buffer into the write_q (in sequence * number order). The retransmission will occur below * when the write buffer with the lowest sequence number * is pulled from the write_q again. */ ninfo("REXMIT: Moving wrb=%p nrtx=%u\n", wrb, WRB_NRTX(wrb)); psock_insert_segment(wrb, &conn->write_q); } } } /* Check if the outgoing packet is available (it may have been claimed * by a sendto interrupt serving a different thread). */ if (dev->d_sndlen > 0) { /* Another thread has beat us sending data, wait for the next poll */ return flags; } /* We get here if (1) not all of the data has been ACKed, (2) we have been * asked to retransmit data, (3) the connection is still healthy, and (4) * the outgoing packet is available for our use. In this case, we are * now free to send more data to receiver -- UNLESS the buffer contains * unprocessed incoming data. In that event, we will have to wait for the * next polling cycle. */ if ((conn->tcpstateflags & TCP_ESTABLISHED) && (flags & (TCP_POLL | TCP_REXMIT)) && !(sq_empty(&conn->write_q))) { /* Check if the destination IP address is in the ARP or Neighbor * table. If not, then the send won't actually make it out... it * will be replaced with an ARP request or Neighbor Solicitation. */ if (psock_send_addrchck(conn)) { FAR struct tcp_wrbuffer_s *wrb; uint32_t predicted_seqno; size_t sndlen; /* Peek at the head of the write queue (but don't remove anything * from the write queue yet). We know from the above test that * the write_q is not empty. */ wrb = (FAR struct tcp_wrbuffer_s *)sq_peek(&conn->write_q); DEBUGASSERT(wrb); /* Get the amount of data that we can send in the next packet. * We will send either the remaining data in the buffer I/O * buffer chain, or as much as will fit given the MSS and current * window size. */ sndlen = WRB_PKTLEN(wrb) - WRB_SENT(wrb); if (sndlen > conn->mss) { sndlen = conn->mss; } if (sndlen > conn->winsize) { sndlen = conn->winsize; } ninfo("SEND: wrb=%p pktlen=%u sent=%u sndlen=%u\n", wrb, WRB_PKTLEN(wrb), WRB_SENT(wrb), sndlen); /* Set the sequence number for this segment. If we are * retransmitting, then the sequence number will already * be set for this write buffer. */ if (WRB_SEQNO(wrb) == (unsigned)-1) { WRB_SEQNO(wrb) = conn->isn + conn->sent; } /* The TCP stack updates sndseq on receipt of ACK *before* * this function is called. In that case sndseq will point * to the next unacknowledged byte (which might have already * been sent). We will overwrite the value of sndseq here * before the packet is sent. */ tcp_setsequence(conn->sndseq, WRB_SEQNO(wrb) + WRB_SENT(wrb)); #ifdef NEED_IPDOMAIN_SUPPORT /* If both IPv4 and IPv6 support are enabled, then we will need to * select which one to use when generating the outgoing packet. * If only one domain is selected, then the setup is already in * place and we need do nothing. */ send_ipselect(dev, psock); #endif /* Then set-up to send that amount of data with the offset * corresponding to the amount of data already sent. (this * won't actually happen until the polling cycle completes). */ devif_iob_send(dev, WRB_IOB(wrb), sndlen, WRB_SENT(wrb)); /* Remember how much data we send out now so that we know * when everything has been acknowledged. Just increment * the amount of data sent. This will be needed in sequence * number calculations. */ conn->unacked += sndlen; conn->sent += sndlen; /* Below prediction will become true, unless retransmission occurrence */ predicted_seqno = tcp_getsequence(conn->sndseq) + sndlen; if ((predicted_seqno > conn->sndseq_max) || (tcp_getsequence(conn->sndseq) > predicted_seqno)) /* overflow */ { conn->sndseq_max = predicted_seqno; } ninfo("SEND: wrb=%p nrtx=%u unacked=%u sent=%u\n", wrb, WRB_NRTX(wrb), conn->unacked, conn->sent); /* Increment the count of bytes sent from this write buffer */ WRB_SENT(wrb) += sndlen; ninfo("SEND: wrb=%p sent=%u pktlen=%u\n", wrb, WRB_SENT(wrb), WRB_PKTLEN(wrb)); /* Remove the write buffer from the write queue if the * last of the data has been sent from the buffer. */ DEBUGASSERT(WRB_SENT(wrb) <= WRB_PKTLEN(wrb)); if (WRB_SENT(wrb) >= WRB_PKTLEN(wrb)) { FAR struct tcp_wrbuffer_s *tmp; ninfo("SEND: wrb=%p Move to unacked_q\n", wrb); tmp = (FAR struct tcp_wrbuffer_s *)sq_remfirst(&conn->write_q); DEBUGASSERT(tmp == wrb); UNUSED(tmp); /* Put the I/O buffer chain in the un-acked queue; the * segment is waiting for ACK again */ psock_insert_segment(wrb, &conn->unacked_q); } /* Only one data can be sent by low level driver at once, * tell the caller stop polling the other connection. */ flags &= ~TCP_POLL; } } /* Continue waiting */ return flags; }
int main(int argc, char *argv[]) { int ret; const char *cid; char cmd[CMD_SIZE]; GError *err = NULL; _cleanup_free_ char *contents; int cpid = -1; int status; pid_t pid; _cleanup_close_ int mfd = -1; _cleanup_close_ int epfd = -1; char slname[BUF_SIZE]; char buf[BUF_SIZE]; int num_read; struct termios t; struct epoll_event ev; struct epoll_event evlist[MAX_EVENTS]; if (argc < 2) { nexit("Run as: conmon <id>"); } /* Get the container id */ cid = argv[1]; /* * Set self as subreaper so we can wait for container process * and return its exit code. */ ret = prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0); if (ret != 0) { pexit("Failed to set as subreaper"); } /* Open the master pty */ mfd = open("/dev/ptmx", O_RDWR | O_NOCTTY); if (mfd < 0) pexit("Failed to open console master pty"); /* Grant access to the slave pty */ if (grantpt(mfd) == -1) pexit("Failed to grant access to slave pty"); /* Unlock the slave pty */ if (unlockpt(mfd) == -1) { /* Unlock slave pty */ pexit("Failed to unlock the slave pty"); } /* Get the slave pty name */ ret = ptsname_r(mfd, slname, BUF_SIZE); if (ret != 0) { pexit("Failed to get the slave pty name"); } /* Create the container */ snprintf(cmd, CMD_SIZE, "runc create %s --pid-file pidfile --console %s", cid, slname); ret = system(cmd); if (ret != 0) { nexit("Failed to create container"); } /* Read the pid so we can wait for the process to exit */ g_file_get_contents("pidfile", &contents, NULL, &err); if (err) { fprintf(stderr, "Failed to read pidfile: %s\n", err->message); g_error_free(err); exit(1); } cpid = atoi(contents); printf("container PID: %d\n", cpid); /* Save exiting termios settings */ if (tcgetattr(STDIN_FILENO, &tty_orig) == -1) pexit("tcegetattr"); /* Settings for raw mode */ t.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL | IEXTEN); t.c_iflag &= ~(BRKINT | ICRNL | IGNBRK | IGNCR | INLCR | INPCK | ISTRIP | IXON | IXOFF | IGNPAR | PARMRK); t.c_oflag &= ~OPOST; t.c_cc[VMIN] = 1; t.c_cc[VTIME] = 0; /* Set terminal to raw mode */ if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t) == -1) pexit("tcsetattr"); /* Setup terminal restore on exit */ if (atexit(tty_restore) != 0) pexit("atexit"); epfd = epoll_create(5); if (epfd < 0) pexit("epoll_create"); ev.events = EPOLLIN; ev.data.fd = STDIN_FILENO; if (epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev) < 0) { pexit("Failed to add stdin to epoll"); } ev.data.fd = mfd; if (epoll_ctl(epfd, EPOLL_CTL_ADD, mfd, &ev) < 0) { pexit("Failed to add console master fd to epoll"); } /* Copy data back and forth between STDIN and master fd */ while (true) { int ready = epoll_wait(epfd, evlist, MAX_EVENTS, -1); for (int i = 0; i < ready; i++) { if (evlist[i].events & EPOLLIN) { if (evlist[i].data.fd == STDIN_FILENO) { num_read = read(STDIN_FILENO, buf, BUF_SIZE); if (num_read <= 0) goto out; if (write(mfd, buf, num_read) != num_read) { nwarn("partial/failed write (masterFd)"); goto out; } } else if (evlist[i].data.fd == mfd) { num_read = read(mfd, buf, BUF_SIZE); if (num_read <= 0) goto out; if (write(STDOUT_FILENO, buf, num_read) != num_read) { nwarn("partial/failed write (STDOUT_FILENO)"); goto out; } } } else if (evlist[i].events & (EPOLLHUP | EPOLLERR)) { printf("closing fd %d\n", evlist[i].data.fd); if (close(evlist[i].data.fd) < 0) pexit("close"); goto out; } } } out: tty_restore(); /* Wait for the container process and record its exit code */ while ((pid = waitpid(-1, &status, 0)) > 0) { printf("PID %d exited\n", pid); if (pid == cpid) { _cleanup_free_ char *status_str = NULL; ret = asprintf(&status_str, "%d", status); if (ret < 0) { pexit("Failed to allocate memory for status"); } g_file_set_contents("exit", status_str, strlen(status_str), &err); if (err) { fprintf(stderr, "Failed to write %s to exit file: %s\n", status_str, err->message); g_error_free(err); exit(1); } break; } } return EXIT_SUCCESS; }
static uint16_t sendto_interrupt(FAR struct net_driver_s *dev, FAR void *conn, FAR void *pvpriv, uint16_t flags) { FAR struct sendto_s *pstate = (FAR struct sendto_s *)pvpriv; ninfo("flags: %04x\n", flags); if (pstate) { /* If the network device has gone down, then we will have terminate * the wait now with an error. */ if ((flags & NETDEV_DOWN) != 0) { /* Terminate the transfer with an error. */ nwarn("WARNING: Network is down\n"); pstate->st_sndlen = -ENETUNREACH; } /* Check if the outgoing packet is available. It may have been claimed * by a sendto interrupt serving a different thread -OR- if the output * buffer currently contains unprocessed incoming data. In these cases * we will just have to wait for the next polling cycle. */ else if (dev->d_sndlen > 0 || (flags & UDP_NEWDATA) != 0) { /* Another thread has beat us sending data or the buffer is busy, * Check for a timeout. If not timed out, wait for the next * polling cycle and check again. */ #ifdef CONFIG_NET_SENDTO_TIMEOUT if (send_timeout(pstate)) { /* Yes.. report the timeout */ nwarn("WARNING: SEND timeout\n"); pstate->st_sndlen = -ETIMEDOUT; } else #endif /* CONFIG_NET_SENDTO_TIMEOUT */ { /* No timeout. Just wait for the next polling cycle */ return flags; } } /* It looks like we are good to send the data */ else { #ifdef NEED_IPDOMAIN_SUPPORT /* If both IPv4 and IPv6 support are enabled, then we will need to * select which one to use when generating the outgoing packet. * If only one domain is selected, then the setup is already in * place and we need do nothing. */ sendto_ipselect(dev, pstate); #endif /* Copy the user data into d_appdata and send it */ devif_send(dev, pstate->st_buffer, pstate->st_buflen); pstate->st_sndlen = pstate->st_buflen; } /* Don't allow any further call backs. */ pstate->st_cb->flags = 0; pstate->st_cb->priv = NULL; pstate->st_cb->event = NULL; /* Wake up the waiting thread */ sem_post(&pstate->st_sem); } return flags; }
FAR struct tcp_conn_s *tcp_alloc(uint8_t domain) { FAR struct tcp_conn_s *conn; /* Because this routine is called from both interrupt level and * and from user level, we have not option but to disable interrupts * while accessing g_free_tcp_connections[]; */ net_lock(); /* Return the entry from the head of the free list */ conn = (FAR struct tcp_conn_s *)dq_remfirst(&g_free_tcp_connections); #ifndef CONFIG_NET_SOLINGER /* Is the free list empty? */ if (!conn) { /* As a fall-back, check for connection structures which can be stalled. * * Search the active connection list for the oldest connection * that is about to be closed anyway. */ FAR struct tcp_conn_s *tmp = (FAR struct tcp_conn_s *)g_active_tcp_connections.head; while (tmp) { ninfo("conn: %p state: %02x\n", tmp, tmp->tcpstateflags); /* Is this connection in a state we can sacrifice. */ /* REVISIT: maybe we could check for SO_LINGER but it's buried * in the socket layer. */ if (tmp->tcpstateflags == TCP_CLOSING || tmp->tcpstateflags == TCP_FIN_WAIT_1 || tmp->tcpstateflags == TCP_FIN_WAIT_2 || tmp->tcpstateflags == TCP_TIME_WAIT || tmp->tcpstateflags == TCP_LAST_ACK) { /* Yes.. Is it the oldest one we have seen so far? */ if (!conn || tmp->timer > conn->timer) { /* Yes.. remember it */ conn = tmp; } } /* Look at the next active connection */ tmp = (FAR struct tcp_conn_s *)tmp->node.flink; } /* Did we find a connection that we can re-use? */ if (conn != NULL) { nwarn("WARNING: Closing unestablished connection: %p\n", conn); /* Yes... free it. This will remove the connection from the list * of active connections and release all resources held by the * connection. * * REVISIT: Could there be any higher level, socket interface * that needs to be informed that we did this to them? * * Actually yes. When CONFIG_NET_SOLINGER is enabled there is a * pending callback in netclose_disconnect waiting for getting * woken up. Otherwise there's the callback too, but no one is * waiting for it. */ tcp_free(conn); /* Now there is guaranteed to be one free connection. Get it! */ conn = (FAR struct tcp_conn_s *)dq_remfirst(&g_free_tcp_connections); } } #endif net_unlock(); /* Mark the connection allocated */ if (conn) { memset(conn, 0, sizeof(struct tcp_conn_s)); conn->tcpstateflags = TCP_ALLOCATED; #if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6) conn->domain = domain; #endif } return conn; }