UNIXworkcode

1 /* 2 * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 3 * Version 2, December 2004 4 * 5 * Copyright (C) 2017 Olaf Wintermann <olaf.wintermann@gmail.com> 6 * 7 * Everyone is permitted to copy and distribute verbatim or modified 8 * copies of this license document, and changing it is allowed as long 9 * as the name is changed. 10 * 11 * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 * 14 * 0. You just DO WHAT THE FUCK YOU WANT TO. 15 */ 16 17 #define _POSIX_C_SOURCE 200112L 18 19 #include <stdio.h> 20 #include <stdlib.h> 21 #include <string.h> 22 #include <unistd.h> 23 #include <sys/socket.h> 24 #include <sys/un.h> 25 #include <sys/types.h> 26 #include <sys/wait.h> 27 #include <sys/stat.h> 28 #include <fcntl.h> 29 30 31 /* 32 * sends a buffer and an additional file descriptor to a socket 33 */ 34 ssize_t send_fd(int sock, const char *buf, size_t len, int fd); 35 36 /* 37 * receives a buffer and an additional file descriptor from a socket 38 */ 39 ssize_t recv_fd(int sock, char *buf, size_t len, int *fd); 40 41 void child_process(); 42 43 const char *socket_path = "fd.sock"; 44 45 int main(int argc, char **argv) { 46 // create unix domain socket 47 struct sockaddr_un addr; 48 memset(&addr, 0, sizeof(struct sockaddr_un)); 49 addr.sun_family = AF_UNIX; 50 strcpy(addr.sun_path, socket_path); 51 52 int sock = socket(AF_UNIX, SOCK_STREAM, 0); 53 if(sock == -1) { 54 perror("socket"); 55 return -1; 56 } 57 58 if(bind(sock, (struct sockaddr*)&addr, sizeof(addr))) { 59 perror("bind"); 60 return -1; 61 } 62 63 if(listen(sock, 8) == -1) { 64 perror("listen"); 65 return -1; 66 } 67 68 // create new process 69 pid_t pid = fork(); 70 if(pid == 0) { 71 close(sock); 72 child_process(); 73 return 0; 74 } 75 76 // accept clients 77 int fd = accept(sock, NULL, 0); 78 if(fd == -1) { 79 perror("accept"); 80 return -1; 81 } 82 83 printf("client connected\n"); 84 85 // open test file 86 mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 87 int file = open("testfile", O_WRONLY | O_CREAT, mode); 88 printf("testfile fd = %d\n", file); 89 90 // send fd 91 const char *msg = "Hello World!"; 92 send_fd(fd, msg, strlen(msg), file); 93 94 int status; 95 waitpid(pid, &status, 0); 96 97 // cleanup 98 close(file); 99 close(fd); 100 close(sock); 101 102 if(unlink(socket_path)) { 103 perror("unlink"); 104 } 105 106 return 0; 107 } 108 109 void child_process() { 110 // connect to a unix domain socket 111 struct sockaddr_un addr; 112 memset(&addr, 0, sizeof(addr)); 113 addr.sun_family = AF_UNIX; 114 strcpy(addr.sun_path, socket_path); 115 116 int client = socket(AF_UNIX, SOCK_STREAM, 0); 117 if(client == -1) { 118 perror("client: socket"); 119 return; 120 } 121 122 if(connect(client, (struct sockaddr*)&addr, sizeof(addr))) { 123 perror("client: connect"); 124 return; 125 } 126 127 printf("client connected\n"); 128 129 // receive data and fd 130 char buf[1024]; 131 int fd; 132 ssize_t r = recv_fd(client, buf, 1024, &fd); 133 printf("msg: {%.*s}\n", (int)r, buf); 134 printf("fd: %d\n", fd); 135 136 if(r > 0 && fd != -1) { 137 printf("write msg to fd\n"); 138 write(fd, buf, r); 139 close(fd); 140 } 141 142 close(client); 143 } 144 145 ssize_t send_fd(int sock, const char *buf, size_t len, int fd) { 146 struct msghdr msg; 147 msg.msg_name = NULL; // unused in this case 148 msg.msg_namelen = 0; 149 150 // a message contains an iovec for the normal payload data 151 struct iovec iov[1] ; 152 iov[0].iov_base = (void*)buf; 153 iov[0].iov_len = len; 154 155 msg.msg_iov = iov; 156 msg.msg_iovlen = 1; 157 158 // set ancillary data 159 160 // the ancillary data is a struct cmsghdr followed by additional data 161 // in this case just an int for the file descriptor, but you can send 162 // multiple file descriptors with an array of ints 163 // CMSG_SPACE returns the number of bytes needed for the struct and the 164 // payload data 165 char cmsg_buf[CMSG_SPACE(sizeof(int))]; 166 167 struct cmsghdr *cmsg = (struct cmsghdr*)cmsg_buf; 168 cmsg->cmsg_len = CMSG_LEN(sizeof(int)); 169 cmsg->cmsg_level = SOL_SOCKET; 170 cmsg->cmsg_type = SCM_RIGHTS; // indicates fd payload data 171 172 int *data = (int*)CMSG_DATA(cmsg); 173 *data = fd; 174 175 msg.msg_control = cmsg; 176 msg.msg_controllen = CMSG_LEN(sizeof(int)); 177 178 msg.msg_flags = 0; 179 180 return sendmsg(sock, &msg, 0); 181 } 182 183 ssize_t recv_fd(int sock, char *buf, size_t len, int *fd) { 184 // just fill in the msghdr fields like in the send_fd function 185 struct msghdr msg; 186 msg.msg_name = NULL; 187 msg.msg_namelen = 0; 188 189 struct iovec iov[1]; 190 iov[0].iov_base = buf; 191 iov[0].iov_len = len; 192 193 msg.msg_iov = iov; 194 msg.msg_iovlen = 1; 195 196 char cmsg_buf[CMSG_SPACE(sizeof(int))]; 197 memset(cmsg_buf, 0, CMSG_SPACE(sizeof(int))); 198 199 struct cmsghdr *cmsg = (struct cmsghdr*)cmsg_buf; 200 cmsg->cmsg_len = CMSG_LEN(sizeof(int)); 201 cmsg->cmsg_level = SOL_SOCKET; 202 cmsg->cmsg_type = SCM_RIGHTS; 203 204 msg.msg_control = cmsg; 205 msg.msg_controllen = CMSG_LEN(sizeof(int)); 206 207 msg.msg_flags = 0; 208 209 ssize_t r = recvmsg(sock, &msg, 0); 210 if(r != -1) { 211 // get file descriptor 212 int *data = (int*)CMSG_DATA(cmsg); 213 *fd = *data; 214 } else { 215 *fd = -1; 216 } 217 return r; 218 } 219