/* -*- 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);
}