Pass-through file descriptors between processes

Source: Internet
Author: User
Tags sendmsg socket error unix domain socket

The following example shows how to pass file descriptors between processes using UNIX domain sockets reference: 1) UNIX network programming         2)  /HTTP book.51cto.com/art/200912/168560.htm  recently learned to use UNIX domain sockets to pass file descriptors between processes, modelled on reference materials, and wrote a simple program to practice this technique.   Not much to say, specific theoretical knowledge see resources, start my own program introduction (Test on OpenSolaris 2009.06 platform): 1  program role Description: Parent process, The child process and another process write to the file descriptor of the same file.    as follows:   1) parent process specifies the file name to open, open permissions, open mode;   2) fork a child process;   3) The child process calls the EXECL function to execute the program OpenFile: The new program obtains the file descriptor of the specified file, writes "Openfileprog write test" to the specified file, and returns the file descriptor to the parent process;   4) After the parent process receives the file descriptor, write the "Paraent process write PPP";   5) parent process to the file as the server side establishes the domain socket waiting for the client process connection;   6) The client process connects to the parent process;   7) The parent process returns the file descriptor obtained from the child process to the client process;   8) The client process receives the file descriptor and uses it to write in the file "This is the client process CCC ";   where the parent-child process passes the file descriptor through a pair of socket pipes, the parent process and the client process pass the file descriptor through the UNIX domain socket.  2 Specific code Description:   1) First look at the OpenFile program, when the child process by calling Execl execution. The calling method is as follows:  execl ("./openfileprog", "Openfileprog", permit, Mode, ARGSOCKFD, (char *) NULL), where the parameter 1:openfile the program path;     parameter 2:openfile program name;   parameter 3: Permission to open file;   parameter 4: Open file mode;   parameter 5: One of the two socket pipelines established by the parent process;    as OpenFile program, mainly according to the parameters of EXECL, open the specified file, get the file descriptor, write to the file, and then call the FUNC_SEND_FD function through the ARGSOCKFD to pass the obtained file descriptor to the parent process. The program code is as follows:  int main (int argc, char *argv[])/* Openfileprog */
{
int I, FD, ret;
ssize_t size;
size_t Buflen;
Char data[10];
Char buf[] = "Openfileprog write test\n"; /* Content written to the file */
/* EXECL ("./openfileprog", permit, Mode, ARGSOCKFD, (char *) NULL); */
FD =-1;
if (FD = Open ("./file", Atoi (Argv[1]), Atoi (Argv[2]))) < 0)
{
printf ("In Openfileprog, open failed\n");
Exit (-1);
}

size =-1;
Buflen = sizeof (BUF);
if (size = Write (FD, buf, Buflen)) <= 0)
{
printf ("In Openfileprog, write failed\n");
}/* Pass the Set data information to the parent process */
ret = ' a ';
for (i = 0; i < sizeof (data); i++, ret++)
{
Data[i] = ret;
}
Data[sizeof (data)-1] = ' + ';

ret =-1;
if (0 > (ret = FUNC_SEND_FD (Atoi (argv[3]), FD, data, 10))
{
printf ("In Openfileprog, func_send_fd failed\n");
}


Close (FD);

return 0;
The FUNC_SEND_FD function is responsible for getting the file descriptor out: int func_send_fd (int send_sock, int send_fd, void *data, int bytes)
{
struct MSGHDR msghead;
struct Iovec passdata[1];
int ret;
/* Fill msghead structure */
Msghead.msg_accrights = (caddr_t) &send_fd;
Msghead.msg_accrightslen = sizeof (SEND_FD);

Msghead.msg_name = NULL;
Msghead.msg_namelen = 0;
Passdata[0].iov_base = data;
Passdata[0].iov_len = bytes;

Msghead.msg_iov = PassData;
Msghead.msg_iovlen = 1;

/* Send Message */
if (0 > (ret = sendmsg (send_sock, &msghead, 0)))
{
printf ("In Func_send, send_fd are%d, Sendsock is%d, sendmsg Failed,errno is%d\n", Send_fd,send_sock,errno);
return-1;
}

return ret;
Before the two functions above, add the following necessary header files and macros: #include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
#include <unistd.h> #define SLEEPTIME 3
#define Arglen 20 as a C file. 2) then look at the parent process code below is the parent process program: int main (int argc, char *argv)
{
int status,sockfd[2];
Char Permit[arglen];
Char Mode[arglen];
Char Argsockfd[arglen];
int recvfd;
Char data[20];
int bytes;
int ret,i;
ssize_t size;
int Buflen;
pid_t Pid,chldpid;

/* The following lines are the necessary variables for using domain sockets */int fdsock, fdaccept;
struct Sockaddr_un addr_server;
int Len;
const char path[] = "/export/home/temp/test/other_prog/fengxianzhong"; /* The following is what the parent process writes to the file */
Char buf[] = "paraent process write ppp\n"; /* The parent process simultaneously processes the data sent to the client */
Char datasend[] = "Send by myopen\n";


memset (Permit, ' n ', sizeof (permit));
memset (mode, ' n ', sizeof (mode));
memset (ARGSOCKFD, ' n ', sizeof (ARGSOCKFD));
memset (data, ' + ', sizeof (data));

printf ("Now it is the parent Process,now would fork a child process\n");
Sleep (Sleeptime);

/* Set file permissions and open mode */snprintf (permit, sizeof (permit), "%d", permit);
snprintf (mode, sizeof (mode), "%d", mode);
printf ("In Myopen%s,%s\n", permit, mode); /* Set up socket sockets for communication with child processes */
ret = Socketpair (AF_UNIX,SOCK_STREAM,0,SOCKFD);
if (0 > Ret)
{
printf ("Socketpair Failed,errno is%d \ n", errno);
}
/* Fork Child process */
if (0 = = (chldpid = fork))/*/child process */
{
printf ("Now it's child process, Sendsock is%d\n", sockfd[1]);
Close (sockfd[0]);
snprintf (ARGSOCKFD, sizeof (ARGSOCKFD), "%d", sockfd[1]); /* Execute new program in child process OpenFile */
Execl ("./openfileprog", "Openfileprog", permit, Mode, ARGSOCKFD, (char *) NULL);
printf ("Execl failed, Perimit is%s, mode is%s\n", permit, mode);
Exit (-1);
}

/* paraent process start to write the file opened by child process */

printf ("Now it is the parent process\n");
Close (sockfd[1]);
bytes = sizeof (data);
/* Wait for the child process to end */
PID = Wait (&status);
if (status = Wexitstatus (status)) = = 0)/* Child process Terminate */
{
printf ("Child%d process Terminate,now parent would write file ... \ n", PID);
}
/* Get the file descriptor from the child process */
RECVFD =-1;
printf ("Recv sock is%d\n", sockfd[0]);
ret = FUNC_RECV_FD (sockfd[0], &recvfd, data, bytes);
if (Ret < 0)
{
printf ("Paraent recv failed\n");
}
/*
Else
{
printf ("FD%d paraent recv%d bytes data is%s\n", Recvfd,strlen (data), data);
}
*/* Write data to File */
size =-1;
Buflen = sizeof (BUF);

if (size = Write (recvfd, buf, Buflen)) <= 0)
{
printf ("In Openfileprog, write failed\n");
}
/* Parent process establishes a domain socket as server, waiting for client connection */
printf ("Parent Write over! Accept other process ... \ n ");

Fdsock = socket (Af_unix, sock_stream, 0);
if ( -1 = = Fdsock)
{
printf ("Myopen creat socket Error!errno is%d\n", errno);
}

unlink (path);

memset (&addr_server, 0, sizeof (addr_server));
addr_server.sun_family = Af_unix;
strcpy (Addr_server.sun_path, path);
len = sizeof (struct sockaddr_un);

ret = bind (Fdsock, (struct sockaddr*) &addr_server, Len);
if ( -1 = = ret)
{
printf ("In Myopen bind error, Errorno is%d\n", errno);
Close (Fdsock);
unlink (path);
}

RET = Listen (fdsock,1);
if ( -1 = = ret)
{
printf ("In Myopen listen error, Errorno is%d\n", errno);
Close (Fdsock);
unlink (path);
}

Fdaccept = Accept (Fdsock, (struct sockaddr*) &addr_server, &len);
if ( -1 = = ret)
{
printf ("In Myopen accept Error, Errorno is%d\n", errno);
Close (Fdsock);
unlink (path);
}
/* Pass the file descriptor to the already connected client */
ret = FUNC_SEND_FD (fdaccept, recvfd, Datasend, sizeof (datasend));
if (0 > Ret)
{
printf ("In Myopen, func_send_fd failed\n");
}

printf ("Send FD over! would sleep 10s \ n ");

Sleep (10);


Exit (0);

The FUNC_RECV_FD function accepts file descriptors from child processes: int func_recv_fd (int recv_sock, int *recvfd, void *data, int bytes)
{
struct MSGHDR msghead;
struct Iovec passdata[1];
int ret;
int temp;
int NEWFD;

struct CMSGHDR *msgptr1;

struct CMSGHDR *msgptr = NULL;

memset (&msghead, 0, sizeof (msghead));
/* with FUNC_SEND_FD, fill the required structure */msghead.msg_accrights = (caddr_t) &newfd;
Msghead.msg_accrightslen = sizeof (RECVFD);

Msghead.msg_name = NULL;
Msghead.msg_namelen = 0;
Passdata[0].iov_base = data;
Passdata[0].iov_len = bytes;

Msghead.msg_iov = PassData;
Msghead.msg_iovlen = 1;

/* Receive information (file descriptor) */
if (0 > (ret = recvmsg (recv_sock, &msghead, 0)))
{
printf ("In func_recv_fd, Recvmsg failed\n");
return-1;
}


if (Msghead.msg_accrightslen = = sizeof (RECVFD))
{
*recvfd = NEWFD; /* File Descriptor */
}


return ret;
The parent process sends a file descriptor to the client process and also uses the FUNC_SEND_FD function, which is re-written in the C file, but it is not necessary to repeat it. We can use it as a library, but for the moment this is used. The function code reference is written above. In this C file also add the following header file and macro definition: #include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/wait.h> #define SLEEPTIME 3
#define Arglen 20
#define MODE S_IRUSR | S_IWUSR | S_IXUSR | S_irgrp | S_iroth/*-rwxr--r--*/
#define PERMIT O_rdwr | O_append | O_creat/* If the file isn't exit, creat it, data written to it append */3) Last look at the client process code: int Mai N ()
{
int SOCKFD, Recvfd,ret;

struct Sockaddr_un addr_client;
int Length,buflen;
Char data[10];
ssize_t size;
const char path[] = "/export/home/temp/test/other_prog/fengxianzhong";
Char buf[] = "This is client process ccc\n";


SOCKFD = socket (Af_unix, sock_stream, 0);
if ( -1 = = SOCKFD)
{
printf ("Client creat socket Error!errno is%d\n", errno);
}

addr_client.sun_family = Af_unix;
strcpy (Addr_client.sun_path, path);
length = sizeof (addr_client.sun_family) + sizeof (Addr_client.sun_path);
ret = Connect (SOCKFD, (struct sockaddr*) &addr_client, length);
if ( -1 = = ret)
{
printf ("In-Client connect error, Errorno is%d\n", errno);
Close (SOCKFD);
}

ret = FUNC_RECV_FD (SOCKFD, &recvfd, data, sizeof (data));
if ( -1 = = ret)
{
printf ("In client func_recv_fd failed\n");
Close (SOCKFD);
}

size =-1;
Buflen = sizeof (BUF);

if (size = Write (recvfd, buf, Buflen)) <= 0)
{
printf ("In Openfileprog, write failed\n");
}

printf ("Client write over!\n");

Exit (0);
The FUNC_RECV_FD function is also called. Here, we treat it with the same func_send_fd function. Don't forget to add the following header file and macro definition: #include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/wait.h> #define SLEEPTIME 3
#define Arglen 20 or more 3 parts of the code are compiled as 3 C files respectively. Summary: The above functions, such as the FUNC_RECV_FD,FUNC_SEND_FD code, are reused, which makes it redundant. As mentioned above, you can use other methods to avoid this repetition. But I'm here to focus on the delivery of the file descriptor, the rest of it, do not go to investigate more. The following paragraphs in the resources are worth understanding: a process can open a descriptor with any UNIX function that returns a descriptor: for example, open (), pipe (), Mkfifo (), socket (), or accept (). You can pass any type of descriptor between processes.

(3) The sending process establishes a MSGHDR structure that contains the descriptors to be passed. The descriptor is described in POSIX as a secondary data send, but the old implementation uses the Msg_accright member. ( here, on OpenSolaris, I'm using an old member) the Send process calls sendmsg () to emit a socket from the UNIX domain socket that was obtained in the first section. at this point the descriptor is in flight. even after the send process calls sendmsg (), and the descriptor is closed before the accept process calls recvmsg (), it remains open for the receiving process. The transmission of the descriptor causes its access statistics to be added by 1.

(4) The Receive process calls Recvmsg () to receive sockets on UNIX domain sockets. The number of descriptors received by the receiving process is usually different from the number of descriptors in the sending process, but this is fine. Instead of passing the descriptor 's number, the delivery descriptor establishes a new descriptor in the receive process that points to the same entry in the kernel's file table as the sending process.

Pass-through file descriptors between processes

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.