diff --git a/drop/pass-socket_client.c b/drop/pass-socket_client.c new file mode 100644 index 0000000..1b96401 --- /dev/null +++ b/drop/pass-socket_client.c @@ -0,0 +1,270 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define USOCK "./.socket" + +#define handle_error(msg) \ + do { log_error (msg); exit(EXIT_FAILURE); } while (0) + +#define handle_err(fun,msg)\ + do { log_error ("%s: file %s line %d %s", fun, __FILE__, __LINE__, msg); } while (0) + +void log_format (const char* tag, const char* message, va_list args) { + time_t now; + + time(&now); + + char * date =ctime(&now); + date[strlen(date) - 1] = '\0'; + printf("%s:%s: ", date, tag); + vprintf(message, args); + + printf("\n"); +} + +void log_error (const char* message, ...) { + va_list args; + va_start(args, message); + + log_format("error", message, args); + + va_end(args); +} + +void log_info (const char* message, ...) { + va_list args; + va_start(args, message); + + log_format("info", message, args); + va_end(args); +} + +void log_debug (const char* message, ...) { + va_list args; + va_start(args, message); + + log_format("debug", message, args); + + va_end(args); +} + +static +int recvsockfd (int socket) // receive fd from socket +{ + struct msghdr msg = {0}; + + /* On Mac OS X, the struct iovec is needed, even if it points to minimal data */ + char m_buffer[1]; + struct iovec io = { .iov_base = m_buffer, .iov_len = sizeof(m_buffer) }; + msg.msg_iov = &io; + msg.msg_iovlen = 1; + + char c_buffer[256]; + msg.msg_control = c_buffer; + msg.msg_controllen = sizeof(c_buffer); + + if (recvmsg(socket, &msg, 0) < 0) + handle_err ("recvsockfd", "Failed to receive message\n"); + + struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); + + printf ("About to extract fd\n"); + int fd; + memmove(&fd, CMSG_DATA(cmsg), sizeof(fd)); + printf ("Extracted fd %d\n", fd); + + return fd; +} + +int usock_connect (int *fd, const char *path) +{ + assert (fd != NULL); + assert (path != NULL); + + if (fd == NULL) { + handle_err ("usock_connect", "fd == NULL"); + return -1; + } + + if (path == NULL) { + handle_err ("usock_connect", "path == NULL"); + return -1; + } + + int sfd; + struct sockaddr_un my_addr; + socklen_t peer_addr_size; + + sfd = socket (AF_UNIX, SOCK_STREAM, 0); + if (sfd == -1) { + handle_err ("usock_connect", "sfd == -1"); + return -1; + } + + // clear structure + memset(&my_addr, 0, sizeof(struct sockaddr_un)); + + my_addr.sun_family = AF_UNIX; + strncpy(my_addr.sun_path, path, strlen (path)); + + peer_addr_size = sizeof(struct sockaddr_un); + if(connect(sfd, (struct sockaddr *) &my_addr, peer_addr_size) == -1) { + handle_err ("usock_connect", "connect == -1"); + perror("connect()"); + exit(errno); + } + + *fd = sfd; + + return 0; +} + +int usock_init (int *fd, const char *path) +{ + assert (fd != NULL); + assert (path != NULL); + + if (fd == NULL) { + handle_err ("usock_init", "fd == NULL"); + return -1; + } + + if (path == NULL) { + handle_err ("usock_init", "path == NULL"); + return -1; + } + + int sfd; + struct sockaddr_un my_addr; + socklen_t peer_addr_size; + + sfd = socket (AF_UNIX, SOCK_STREAM, 0); + if (sfd == -1) { + handle_err ("usock_init", "sfd == -1"); + return -1; + } + + // clear structure + memset(&my_addr, 0, sizeof(struct sockaddr_un)); + + my_addr.sun_family = AF_UNIX; + strncpy(my_addr.sun_path, path, strlen (path)); + + // TODO FIXME + // delete the unix socket if already created + + peer_addr_size = sizeof(struct sockaddr_un); + + if (bind (sfd, (struct sockaddr *) &my_addr, peer_addr_size) == -1) { + handle_err ("usock_init", "bind == -1"); + perror("bind()"); + return -1; + } + + if (listen (sfd, 5) == -1) { + handle_err ("usock_init", "listen == -1"); + perror("listen()"); + return -1; + } + + *fd = sfd; + + return 0; +} + +int usock_accept (int fd, int *pfd) +{ + assert (pfd != NULL); + + if (pfd == NULL) { + handle_err ("usock_accept", "pfd == NULL"); + return -1; + } + + struct sockaddr_un peer_addr; + memset (&peer_addr, 0, sizeof (struct sockaddr_un)); + socklen_t peer_addr_size = 0; + + *pfd = accept (fd, (struct sockaddr *) &peer_addr, &peer_addr_size); + if (*pfd < 0) { + handle_err ("usock_accept", "accept < 0"); + perror("listen()"); + return -1; + } + + return 0; +} + +int usock_close (int fd) +{ + int ret; + ret = close (fd); + if (ret < 0) { + handle_err ("usock_close", "close ret < 0"); + perror ("closing"); + } + return ret; +} + +int usock_remove (const char *path) +{ + return unlink (path); +} + +int main(int argc, char * argv[]) +{ + int tcpsockfd; + int usockfd; + // check the number of args on command line + if(argc != 1) + { + fprintf (stderr, "USAGE: %s\n", argv[0]); + exit(EXIT_FAILURE); + } + + printf("Connection to the unix socket\n"); + + // 1. unix socket connection + int ret = usock_connect (&usockfd, USOCK); + if (ret != 0) { + fprintf (stderr, "error: usock_connect\n"); + exit(EXIT_FAILURE); + } + + printf("Receiving the tcp socket\n"); + + // 2. receive the tcp socket + tcpsockfd = recvsockfd (usockfd); + + printf("Sending 'hello world' to the tcp socket\n"); + + // 3. send a message to check the connection is effective + if (write(tcpsockfd, "hello world\n", strlen("hello world\n")) == -1) { + perror("write"); + close(tcpsockfd); + exit(EXIT_FAILURE); + } + + printf("Disconnection of both sockets\n"); + + // 4. close sockets + close(usockfd); + close(tcpsockfd); + + return EXIT_SUCCESS; +} diff --git a/drop/pass-socket_server.c b/drop/pass-socket_server.c new file mode 100644 index 0000000..fc35280 --- /dev/null +++ b/drop/pass-socket_server.c @@ -0,0 +1,322 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define USOCK "./.socket" + +#define handle_error(msg) \ + do { log_error (msg); exit(EXIT_FAILURE); } while (0) + +#define handle_err(fun,msg)\ + do { log_error ("%s: file %s line %d %s", fun, __FILE__, __LINE__, msg); } while (0) + +void log_format (const char* tag, const char* message, va_list args) { + time_t now; + + time(&now); + + char * date =ctime(&now); + date[strlen(date) - 1] = '\0'; + printf("%s:%s: ", date, tag); + vprintf(message, args); + + printf("\n"); +} + +void log_error (const char* message, ...) { + va_list args; + va_start(args, message); + + log_format("error", message, args); + + va_end(args); +} + +void log_info (const char* message, ...) { + va_list args; + va_start(args, message); + + log_format("info", message, args); + va_end(args); +} + +void log_debug (const char* message, ...) { + va_list args; + va_start(args, message); + + log_format("debug", message, args); + + va_end(args); +} + +int build_socket (char *servername, char * serverport) +{ + int sockfd; + struct sockaddr_in6 server; + socklen_t addrlen; + + // socket factory + if((sockfd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP)) == -1) + { + perror("socket"); + exit(EXIT_FAILURE); + } + + // init remote addr structure and other params + server.sin6_family = AF_INET6; + server.sin6_port = htons(atoi(serverport)); + addrlen = sizeof(struct sockaddr_in6); + + // get addr from command line and convert it + if(inet_pton(AF_INET6, servername, &server.sin6_addr) != 1) + { + perror("inet_pton"); + close(sockfd); + exit(EXIT_FAILURE); + } + + printf("Trying to connect to the remote host\n"); + if(connect(sockfd, (struct sockaddr *) &server, addrlen) == -1) + { + perror("connect"); + exit(EXIT_FAILURE); + } + + return sockfd; +} + +int usock_connect (int *fd, const char *path) +{ + assert (fd != NULL); + assert (path != NULL); + + if (fd == NULL) { + handle_err ("usock_connect", "fd == NULL"); + return -1; + } + + if (path == NULL) { + handle_err ("usock_connect", "path == NULL"); + return -1; + } + + int sfd; + struct sockaddr_un my_addr; + socklen_t peer_addr_size; + + sfd = socket (AF_UNIX, SOCK_STREAM, 0); + if (sfd == -1) { + handle_err ("usock_connect", "sfd == -1"); + return -1; + } + + // clear structure + memset(&my_addr, 0, sizeof(struct sockaddr_un)); + + my_addr.sun_family = AF_UNIX; + strncpy(my_addr.sun_path, path, strlen (path)); + + peer_addr_size = sizeof(struct sockaddr_un); + if(connect(sfd, (struct sockaddr *) &my_addr, peer_addr_size) == -1) { + handle_err ("usock_connect", "connect == -1"); + perror("connect()"); + exit(errno); + } + + *fd = sfd; + + return 0; +} + +int usock_init (int *fd, const char *path) +{ + assert (fd != NULL); + assert (path != NULL); + + if (fd == NULL) { + handle_err ("usock_init", "fd == NULL"); + return -1; + } + + if (path == NULL) { + handle_err ("usock_init", "path == NULL"); + return -1; + } + + int sfd; + struct sockaddr_un my_addr; + socklen_t peer_addr_size; + + sfd = socket (AF_UNIX, SOCK_STREAM, 0); + if (sfd == -1) { + handle_err ("usock_init", "sfd == -1"); + return -1; + } + + // clear structure + memset(&my_addr, 0, sizeof(struct sockaddr_un)); + + my_addr.sun_family = AF_UNIX; + strncpy(my_addr.sun_path, path, strlen (path)); + + // TODO FIXME + // delete the unix socket if already created + + peer_addr_size = sizeof(struct sockaddr_un); + + if (bind (sfd, (struct sockaddr *) &my_addr, peer_addr_size) == -1) { + handle_err ("usock_init", "bind == -1"); + perror("bind()"); + return -1; + } + + if (listen (sfd, 5) == -1) { + handle_err ("usock_init", "listen == -1"); + perror("listen()"); + return -1; + } + + *fd = sfd; + + return 0; +} + +int usock_accept (int fd, int *pfd) +{ + assert (pfd != NULL); + + if (pfd == NULL) { + handle_err ("usock_accept", "pfd == NULL"); + return -1; + } + + struct sockaddr_un peer_addr; + memset (&peer_addr, 0, sizeof (struct sockaddr_un)); + socklen_t peer_addr_size = 0; + + *pfd = accept (fd, (struct sockaddr *) &peer_addr, &peer_addr_size); + if (*pfd < 0) { + handle_err ("usock_accept", "accept < 0"); + perror("listen()"); + return -1; + } + + return 0; +} + +int usock_close (int fd) +{ + int ret; + ret = close (fd); + if (ret < 0) { + handle_err ("usock_close", "close ret < 0"); + perror ("closing"); + } + return ret; +} + +int usock_remove (const char *path) +{ + return unlink (path); +} + +int build_unix_socket (char * path) +{ + int remotefd, localfd; + + usock_init (&localfd, path); + usock_accept (localfd, &remotefd); + + return remotefd; +} + +static +void sendfd (int socket, int fd) // send fd by socket +{ + struct msghdr msg = { 0 }; + char buf[CMSG_SPACE(sizeof(fd))]; + memset(buf, '\0', sizeof(buf)); + + /* On Mac OS X, the struct iovec is needed, even if it points to minimal data */ + struct iovec io = { .iov_base = "", .iov_len = 1 }; + + msg.msg_iov = &io; + msg.msg_iovlen = 1; + msg.msg_control = buf; + msg.msg_controllen = sizeof(buf); + + struct cmsghdr * cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); + + memmove(CMSG_DATA(cmsg), &fd, sizeof(fd)); + + msg.msg_controllen = cmsg->cmsg_len; + + if (sendmsg(socket, &msg, 0) < 0) + handle_err("sendfd", "Failed to send message\n"); +} + +int main(int argc, char * argv[]) +{ + // check the number of args on command line + if(argc != 3) + { + fprintf (stderr, "USAGE: %s @server port_num\n", argv[0]); + exit(EXIT_FAILURE); + } + char *servername = argv[1]; + char *serverport = argv[2]; + + printf("Connection to the tcp socket\n"); + // 1. socket creation (tcp), connection to the server + int sockfd = build_socket (servername, serverport); + + printf("Sending 'coucou' to the tcp socket\n"); + // send a message to check the connection is effective + if (write(sockfd, "coucou\n", strlen("coucou\n")) == -1) { + perror("write"); + close(sockfd); + exit(EXIT_FAILURE); + } + + printf ("Connection to the unix socket\n"); + // 2. socket creation (unix) + int usockfd = build_unix_socket (USOCK); + + printf ("Passing the tcp socket to the unix socket\n"); + // 3. tcp socket passing to the client + sendfd (usockfd, sockfd); + + // send a message to check the connection is (still) effective + if (write(sockfd, "bye\n", strlen("bye\n")) == -1) { + perror("write"); + close(sockfd); + exit(EXIT_FAILURE); + } + + printf("Disconnection\n"); + + // 4. close sockets + close(usockfd); + close(sockfd); + + usock_remove (USOCK); + + return EXIT_SUCCESS; +}