Imported Upstream version 3.2.2
[debian/gnuradio] / usrp2 / host / lib / open_usrp2_socket.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2008 Free Software Foundation, Inc.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22 #include <open_usrp2_socket.h>
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <sys/wait.h>
26 #include <stdio.h>
27 #include <errno.h>
28 #include <string>
29
30 static const char *helper = "usrp2_socket_opener";
31
32 static ssize_t
33 read_fd(int fd, void *ptr, size_t nbytes, int *recvfd)
34 {
35   struct msghdr msg;
36   struct iovec iov[1];
37   ssize_t n;
38
39 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
40   union {
41     struct cmsghdr cm;
42     char     control[CMSG_SPACE(sizeof (int))];
43   } control_un;
44   struct cmsghdr  *cmptr;
45
46   msg.msg_control  = control_un.control;
47   msg.msg_controllen = sizeof(control_un.control);
48 #else
49   int     newfd;
50
51   msg.msg_accrights = (char *) &newfd;
52   msg.msg_accrightslen = sizeof(int);
53 #endif
54
55   msg.msg_name = NULL;
56   msg.msg_namelen = 0;
57
58   iov[0].iov_base = ptr;
59   iov[0].iov_len = nbytes;
60   msg.msg_iov = iov;
61   msg.msg_iovlen = 1;
62
63   if ((n = recvmsg(fd, &msg, 0)) <= 0)
64     return n;
65
66 #ifdef  HAVE_STRUCT_MSGHDR_MSG_CONTROL
67   if ((cmptr = CMSG_FIRSTHDR(&msg)) != NULL
68       && cmptr->cmsg_len == CMSG_LEN(sizeof(int))){
69     if (cmptr->cmsg_level != SOL_SOCKET){
70       fprintf(stderr, "read_fd: control level != SOL_SOCKET\n");
71       return -1;
72     }
73     if (cmptr->cmsg_type != SCM_RIGHTS){
74       fprintf(stderr, "read_fd: control type != SCM_RIGHTS\n");
75       return -1;
76     }
77     *recvfd = *((int *) CMSG_DATA(cmptr));
78   } else
79     *recvfd = -1;           /* descriptor was not passed */
80 #else
81   if (msg.msg_accrightslen == sizeof(int))
82     *recvfd = newfd;
83   else
84     *recvfd = -1;       /* descriptor was not passed */
85 #endif
86
87   return n;
88 }
89
90 int
91 usrp2::open_usrp2_socket()
92 {
93   int     fd = -1, sockfd[2], status;
94   pid_t   childpid;
95   char    c, argsockfd[10];
96
97   if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd) != 0){
98     perror("socketpair");
99     return -1;
100   }
101
102   if ((childpid = fork()) == 0) { /* child process */
103     close(sockfd[0]);
104     snprintf(argsockfd, sizeof(argsockfd), "%d", sockfd[1]);
105     execlp(helper, helper, argsockfd, (char *) NULL);
106     std::string msg("execlp: couldn't exec " + std::string(helper));
107     perror(msg.c_str());
108     close(sockfd[0]);
109     close(sockfd[1]);
110     return -1;
111   }
112
113   /* parent process - wait for the child to terminate */
114   close(sockfd[1]);           /* close the end we don't use */
115
116   waitpid(childpid, &status, 0);
117   if (!WIFEXITED(status)){
118     fprintf(stderr, "child did not terminate\n");
119     return -1;
120   }
121   if ((status = WEXITSTATUS(status)) == 0)
122     read_fd(sockfd[0], &c, 1, &fd);
123   else {
124     errno = status;         /* bogus: set errno value from child's status */
125     fd = -1;
126   }
127
128   close(sockfd[0]);
129   return (fd);
130 }