UNIX Domain sockets The Linux Programming Interface (ch 57) UNIX Network Programming – Vol 1, 3ed (ch 15) Using Sockets in UNIX domain • Unnamed sockets – socketpair( ) – – – – Does not bind to transport layer ports Creates a pair of sockets that are connected Typically used to communicate between related processes Communications similar to pipe • Traditional sockets in UNIX – Binds to transport layer ports – Allows independent processes to communicate – Creates a file type object (socket) • Any process that can access the socket can use it. – Does not use network (IP) layer 2 socketpair( ) • int socketpair (int family, int type, int protocol, int sockfd[2]); – – – – Family must be AF_LOCAL Type may be SOCK_STREAM or SOCK_DGRAM protocol must be 0 On success, the pair of socket descriptors (sockfd) are connected together and available for communications • #include <sys/sockets> • Return zero on success, -1 on fail • In Linux, sockets are full duplex (can both read and write), however, POSIX standard does not require full duplex. 3 sockpair.cpp #define LB_SIZE 128 int main ( ) { time_t now; char child_buf[LB_SIZE], parent_buf[LB_SIZE]; pid_t pid; int sockfd[2], outSize, inSize; bool keepLooping; time (&now); keepLooping = true; cout << "Socket Pair test at " << ctime(&now); socketpair (AF_LOCAL, SOCK_STREAM, 0, sockfd); pid = fork() ; if (pid == 0) { // child process while (keepLooping) { inSize = recv(sockfd[1], child_buf, LB_SIZE, 0); child_buf[inSize] = '\0'; if (strncmp(child_buf, "bye", 3) == 0) keepLooping = false; cout << "Child received: " << child_buf << endl; } cout << "Closing child process" << endl; return 0; } //end of child process section 4 sockpair.cpp else if (pid > 0) { //parent process while (keepLooping) { cout << "Enter text to send to child: " << endl; cin.getline(parent_buf, LB_SIZE); outSize = strlen(parent_buf); if (strncmp(parent_buf, "bye", 3) == 0) keepLooping = false; send (sockfd[0], parent_buf, outSize, 0); } cout << "Closing parent process..." << endl; return 0; } } 5 sockpair example output rcotter@kc-sce-450p2 sockpair]$ ./sockpair Socket Pair test at Wed Oct 12 14:18:28 2011 Enter text to send to child: This is the first message Enter text to send to child: Child received: This is the first message This is the second message Enter text to send to child: Child received: This is the second message bye Closing parent process... Child received: bye Closing child process [rcotter@kc-sce-450p2 sockpair]$ 6 Traditional UNIX Domain Sockets • struct sockaddr_un { sa_family_t sun_family; //AF_LOCAL char sunpath[108]; //NULL terminated path • }; • sunpath length is 108 in Linux, but can be 104, 92, ? in other UNIX based systems. • File (path name) must not exist (be linked) prior to bind( ); 7 UNIX Domain Sockets example 8 Traditional UNIX Domain Sockets Server Socket mytemp.txt Client Socket “unnamed” 9 UNIX Domain socket created by bind 10 unix_udp_echos.cpp #include <iostream>, <fstream>, <sys/socket.h>, <sys/types.h> #include <sys/un.h>, <string.h>, <unistd.h> using namespace std; #define MAXLINE 108 void UDP_echo(int sockfd, sockaddr *pcliaddr, socklen_t clilen); int main(int argc, char *argv[]) { int sockfd; struct sockaddr_un servaddr, cliaddr; char udp_path[MAXLINE]; if (argc != 2) { cout << "Usage: " << argv[0] << " socket_address " << endl; return(1); } if (strlen(argv[1]) < MAXLINE) strcpy(udp_path, argv[1]); else { cout << "Socket Path name too long. Try again." << endl; return(1); } 11 unix_udp_echos.cpp sockfd = socket(AF_LOCAL, SOCK_DGRAM, 0); unlink(udp_path); bzero(&servaddr, sizeof(servaddr)); servaddr.sun_family = AF_LOCAL; strcpy(servaddr.sun_path, udp_path); bind(sockfd, (sockaddr *) &servaddr, sizeof(servaddr)); UDP_echo(sockfd, (sockaddr *) &cliaddr, sizeof(cliaddr)); } 12 unix_udp_echos.cpp void UDP_echo(int sockfd, sockaddr *pcliaddr, socklen_t clilen) { int n; socklen_t len; char mesg[MAXLINE]; for ( ; ; ) { memset(&mesg, 0, MAXLINE); len = clilen; n = recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len); cout << "We just got " << n << " char: " << mesg << endl; sendto(sockfd, mesg, n, 0, pcliaddr, len); } } 13 unix_udp_echo.cpp #include <iostream>, <fstream>, <stdio.h>, <stdlib.h>, <sys/socket.h> #include <sys/types.h>, <sys/un.h>, <string.h>, <unistd.h> using namespace std; #define MAXLINE 128 void UDPecho(int sockfd, const sockaddr *pservaddr, socklen_t servlen); int main(int argc, char *argv[]) { int sockfd; struct sockaddr_un cliaddr, servaddr; char udp_path[MAXLINE]; if (argc != 2) { cout << "Usage: " << argv[0] << " socket_address " << endl; return(1); } if (strlen(argv[1]) < MAXLINE) strcpy(udp_path, argv[1]); else { cout << "Socket Path name too long. Try again." << endl; return(1); } 14 unix_udp_echo.cpp sockfd = socket(AF_LOCAL, SOCK_DGRAM, 0); bzero(&cliaddr, sizeof(cliaddr)); /* bind an address for us */ cliaddr.sun_family = AF_LOCAL; // Bind the client to a local (unique but unnamed) file strcpy(cliaddr.sun_path, tmpnam(NULL)); bind(sockfd, (sockaddr *) &cliaddr, sizeof(cliaddr)); //Identify the server’s address (file) bzero(&servaddr, sizeof(servaddr)); /* fill in server's address */ servaddr.sun_family = AF_LOCAL; strcpy(servaddr.sun_path, udp_path); UDPecho(sockfd, (sockaddr *) &servaddr, sizeof(servaddr)); close(sockfd); exit(0); } 15 unix_udp_echo.cpp void UDPecho(int sockfd, const sockaddr *pservaddr, socklen_t servlen) { int n; char sendline[MAXLINE], recvline[MAXLINE + 1]; while (cin.getline(sendline, MAXLINE) != NULL) { if (strncmp ("_bye", sendline, 4) == 0) break; sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen); n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL); recvline[n] = 0; /* null terminate */ cout << recvline << endl; } cout << "We jumped out of the loop" << endl; } 16 UNIX Domain Sockets example 17 Summary • socketpair( ) – Used to communicate between related processes. – Works like a full-duplex pipe (called a stream pipe) – Does not rely on transport layer functionality • UNIX Domain Sockets – Used to communicate between UNIX / Linux processes that have shared access to a socket file. • Can use file permissions to control access. – Uses transport layer (TCP or UDP), but not network layer (IP) • Removes IP / Ethernet packet size limitations (but still have transport layer limitations). 18