/* -*- c++ -*- */ /* * Copyright 2008 Free Software Foundation, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include static const char *helper = "usrp2_socket_opener"; static ssize_t read_fd(int fd, void *ptr, size_t nbytes, int *recvfd) { struct msghdr msg; struct iovec iov[1]; ssize_t n; #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL union { struct cmsghdr cm; char control[CMSG_SPACE(sizeof (int))]; } control_un; struct cmsghdr *cmptr; msg.msg_control = control_un.control; msg.msg_controllen = sizeof(control_un.control); #else int newfd; msg.msg_accrights = (char *) &newfd; msg.msg_accrightslen = sizeof(int); #endif msg.msg_name = NULL; msg.msg_namelen = 0; iov[0].iov_base = ptr; iov[0].iov_len = nbytes; msg.msg_iov = iov; msg.msg_iovlen = 1; if ((n = recvmsg(fd, &msg, 0)) <= 0) return n; #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL if ((cmptr = CMSG_FIRSTHDR(&msg)) != NULL && cmptr->cmsg_len == CMSG_LEN(sizeof(int))){ if (cmptr->cmsg_level != SOL_SOCKET){ fprintf(stderr, "read_fd: control level != SOL_SOCKET\n"); return -1; } if (cmptr->cmsg_type != SCM_RIGHTS){ fprintf(stderr, "read_fd: control type != SCM_RIGHTS\n"); return -1; } *recvfd = *((int *) CMSG_DATA(cmptr)); } else *recvfd = -1; /* descriptor was not passed */ #else if (msg.msg_accrightslen == sizeof(int)) *recvfd = newfd; else *recvfd = -1; /* descriptor was not passed */ #endif return n; } int usrp2::open_usrp2_socket() { int fd = -1, sockfd[2], status; pid_t childpid; char c, argsockfd[10]; if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd) != 0){ perror("socketpair"); return -1; } if ((childpid = fork()) == 0) { /* child process */ close(sockfd[0]); snprintf(argsockfd, sizeof(argsockfd), "%d", sockfd[1]); execlp(helper, helper, argsockfd, (char *) NULL); std::string msg("execlp: couldn't exec " + std::string(helper)); perror(msg.c_str()); close(sockfd[0]); close(sockfd[1]); return -1; } /* parent process - wait for the child to terminate */ close(sockfd[1]); /* close the end we don't use */ waitpid(childpid, &status, 0); if (!WIFEXITED(status)){ fprintf(stderr, "child did not terminate\n"); return -1; } if ((status = WEXITSTATUS(status)) == 0) read_fd(sockfd[0], &c, 1, &fd); else { errno = status; /* bogus: set errno value from child's status */ fd = -1; } close(sockfd[0]); return (fd); }