2016年10月12日水曜日

fdを他のプロセスに引き継ぐ。

cc -o send send.c fdtrans.c
cc -o recv recv.c fdtrans.c

別ウインドウで次の順番で起動し、recv画面にキー入力。
① send起動
② recv起動

【fdtrans.c】
#include <stdio.h>
#include <errno.h>

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <fcntl.h>
#include <string.h>
//#include "vncgw.h"
//#include "../android/jni/vncserver.h"

//extern web_gate_settings_t settings;

#define UNIX_DOMAIN_PATH_NAME_REQ "/var/local/netreg/request"
#define UNIX_DOMAIN_PATH_NAME_RES "/var/local/netreg/response"

int listen_un(const char* id )
{
char path[48];
int soc,c_soc;
struct sockaddr_un u_addr;

if( (soc = socket(PF_UNIX, SOCK_SEQPACKET, 0)) < 0 ) {
printf( "ERROR Socket in listen_un %s\n", strerror(errno));
return -1;
}

strcpy(  path, UNIX_DOMAIN_PATH_NAME_REQ );
strncat( path, id, 16 );

memset(&u_addr, 0, sizeof(u_addr));
u_addr.sun_family = AF_UNIX;

        u_addr.sun_path[0] = '\0';  /* abstract namespace */
strncpy(u_addr.sun_path + 1, path, sizeof(u_addr.sun_path));

// handler_msg( "unix domain path (ACCEPT)= %s\n", u_addr.sun_path + 1 );

if( bind(soc, (struct sockaddr*)&u_addr, sizeof(u_addr)) < 0 ) {
printf( "ERROR Bind 1 in listen_un() %s\n", strerror(errno));
c_soc = connect_un( id );

/* // add by takahab 20180724
struct timeval timeout;
fd_set rfds;
char buf[2048];

timeout.tv_sec  = 1;
timeout.tv_usec = 0;

FD_ZERO( &rfds );
FD_SET( c_soc, &rfds );

select(c_soc+1, &rfds, NULL, NULL, &timeout);

if (FD_ISSET(c_soc, &rfds)) {
errno = 0;
recv(c_soc, buf, sizeof(buf), 0);
printf( "Done Dummy reading Beause UNIX DOMAIN SOCKET broken  %s\n", strerror(errno));
}
// add by takahab 20180724 */

close( c_soc );
sleep(1);
errno = 0;
if( bind(soc, (struct sockaddr*)&u_addr, sizeof(u_addr)) < 0 ) {

printf( "ERROR Bind 2 in listen_un() %s\n", strerror(errno));
close( soc );
return -1;
}
}

if( listen( soc, 1 ) < 0 ) {
printf( "ERROR listen in listen_un() %s\n", strerror(errno));
close( soc );
return -1;
}

struct sockaddr_un c_addr;
        socklen_t c_len = sizeof(c_addr);

// handler_msg("Accept in Linsten_un() soc=%d\n", soc);
 
if ( (c_soc = accept(soc, (struct sockaddr*)&c_addr, &c_len)) < 0 ) {
printf( "ERROR Accept in listen_un() %s\n", strerror(errno));
close( soc );
return -1;
}
// handler_msg( "accept form   %s     len:%d    c_soc:%d\n", c_addr.sun_path + 1, c_len, c_soc );
close( soc );

return c_soc;
}

int connect_un(const char* id )
{
char path[48];
int soc;
struct sockaddr_un u_addr;

if( (soc = socket(PF_UNIX, SOCK_SEQPACKET, 0)) < 0 ) {
printf( "ERROR Socket in connect_un() %s\n", strerror(errno));
return -1;
}


strcpy(  path, UNIX_DOMAIN_PATH_NAME_RES );
strncat( path, id, 16 );

memset(&u_addr, 0, sizeof(u_addr));
u_addr.sun_family = AF_UNIX;

        u_addr.sun_path[0] = '\0';  /* abstract namespace */
strncpy(u_addr.sun_path + 1, path, sizeof(u_addr.sun_path));

// handler_msg( "unix domain path (CONNECT)= %s\n", u_addr.sun_path + 1);

if( bind(soc, (struct sockaddr*)&u_addr, sizeof(u_addr)) < 0 ) {
printf( "ERROR Bind in connect_un() %s\n", strerror(errno));
close( soc );
return -1;
}

strcpy(  path, UNIX_DOMAIN_PATH_NAME_REQ );
strncat( path, id, 16 );

memset(&u_addr, 0, sizeof(u_addr));
u_addr.sun_family = AF_UNIX;

        u_addr.sun_path[0] = '\0';  /* abstract namespace */
strncpy(u_addr.sun_path + 1, path, sizeof(u_addr.sun_path));

if ( connect(soc, (struct sockaddr*)&u_addr, sizeof(u_addr)) < 0 ) {
printf( "ERROR connect in connect_un() %s\n", strerror(errno));
close( soc );
return -1;
}

return soc;
}


int recv_un(int soc, void* pid, size_t pid_len)
{
struct msghdr msg;
struct iovec  iov;
char cmsgbuf[CMSG_SPACE(sizeof(int))];

iov.iov_base = pid;
iov.iov_len = pid_len;

msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = cmsgbuf;
msg.msg_controllen = sizeof(cmsgbuf);
msg.msg_flags = MSG_WAITALL;

if ( recvmsg(soc, &msg, 0) < 0 ) {
printf( "ERROR Recvmsg in recv_un() %s\n", strerror(errno));
return -1;
}

struct cmsghdr *cmsg = (struct cmsghdr*)cmsgbuf;
return *((int *)CMSG_DATA(cmsg));
}

int send_un(int soc, int fd, void* pid, int pid_len)
{
struct iovec iov;
char buf[CMSG_SPACE(sizeof(int))];

iov.iov_base = pid;
iov.iov_len = pid_len;

struct cmsghdr *cmsg = (struct cmsghdr*)buf;
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
*((int *)CMSG_DATA(cmsg)) = fd;

struct msghdr msg;
memset(&msg, 0, sizeof(msg));
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = buf;
msg.msg_controllen = sizeof(buf);
msg.msg_flags = 0;

if (sendmsg(soc, &msg, 0) < 0) {
printf( "ERROR Sendmsg when sending fd in send_un() %s soc=%d\n", strerror(errno),soc);
return -1;
}
return 0;
}


int send_fdesc(int fd, const char* id )
{
int soc, ret;
        pid_t pid; 
// handshake_headers_t headers;

        soc = listen_un( id );

        pid     = getpid(); 

if( soc >= 0 ) {

// memset( &headers, 0 , sizeof( headers ));
// strcpy( headers.version, PROXY_HANDSHAKE_VERSION );
// headers.cmd = PROXY_HANDSHAKE_CMD;
// strcpy(headers.protocols, PROXY_HANDSHAKE_PROTOCOL );
//
// headers.type = PROXY_HANDSHAKE_TYPE_REQ;
// handshakeToTarget( fd, &headers);


ret    = send_un(soc, fd, &pid, sizeof(pid)); 
if( ret != -1 ) {
printf( "Send to  fd:%d from pid:%d\n", fd, pid );
}

}


close (soc);
perror( "close(soc) in send_fdesc()");

// handler_msg( "Go to  close:%d\n", soc );

return ret;
}

int recv_fdesc( const char* id )
{
int soc, ret, fd;
        int pid = 0; 

        soc       = connect_un( id );

if( soc >= 0 ) {
fd  = recv_un(soc, &pid, sizeof(pid));
// handler_msg( "Answer from pid %d( fd:%d)\n", pid, fd );
}

close( soc );
// handler_msg( "Go to  close:%d\n", soc );


        return fd;
}


テストプログラム
【送り手 send.c】
#include <stdio.h>
int main(void)
{
send_fdesc( 1, "/7716618000486" );
   perror("end");
   return 0;
}

【受け手 recv.c 】
int main(void)
{
      int fd = recv_fdesc( "/7716618000486" );
      printf("Recieve file descriptor %d\n", fd);
      char buf[1024];
      ssize_t len; 
      while( (len = read(0, buf, sizeof(buf))) > 0 ) {
          write(fd, buf, len);
      }
}





シャットダウン時の後処理 (shutdown)

# vi /etc/systemd/system/drop.service [Unit] Description= stop httpgwd DefaultDependencies=no Before=shutdown.target RefuseManualStart=true ...