/* Copyright (c) 2003 Tungsten Graphics, Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files ("the * Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: The above copyright notice, the Tungsten * Graphics splash screen, and this permission notice shall be included * in all copies or substantial portions of the Software. THE SOFTWARE * IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * Simple IPC API * Brian Paul */ #include <assert.h> #include <stdio.h> #include <string.h> #include <sys/types.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <arpa/inet.h> #include <netdb.h> #include <unistd.h> #include <sys/socket.h> #include "ipc.h" #if defined(IRIX) || defined(irix) typedef int socklen_t; #endif #define NO_DELAY 1 #define DEFAULT_MASTER_PORT 7011 /* * Return my hostname in <nameOut>. * Return 1 for success, 0 for error. */ int MyHostName(char *nameOut, int maxNameLength) { int k = gethostname(nameOut, maxNameLength); return k==0; } /* * Create a socket attached to a port. Later, we can call AcceptConnection * on the socket returned from this function. * Return the new socket number or -1 if error. */ int CreatePort(int *port) { char hostname[1000]; struct sockaddr_in servaddr; struct hostent *hp; int so_reuseaddr = 1; int tcp_nodelay = 1; int sock, k; /* create socket */ sock = socket(AF_INET, SOCK_STREAM, 0); assert(sock > 2); /* get my host name */ k = gethostname(hostname, 1000); assert(k == 0); /* get hostent info */ hp = gethostbyname(hostname); assert(hp); /* initialize the servaddr struct */ memset(&servaddr, 0, sizeof(servaddr) ); servaddr.sin_family = AF_INET; servaddr.sin_port = htons((unsigned short) (*port)); memcpy((char *) &servaddr.sin_addr, hp->h_addr, sizeof(servaddr.sin_addr)); /* deallocate when we exit */ k = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &so_reuseaddr, sizeof(so_reuseaddr)); assert(k==0); /* send packets immediately */ #if NO_DELAY k = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &tcp_nodelay, sizeof(tcp_nodelay)); assert(k==0); #endif if (*port == 0) *port = DEFAULT_MASTER_PORT; k = 1; while (k && (*port < 65534)) { /* bind our address to the socket */ servaddr.sin_port = htons((unsigned short) (*port)); k = bind(sock, (struct sockaddr *) &servaddr, sizeof(servaddr)); if (k) *port = *port + 1; } #if 0 printf("###### Real Port: %d\n", *port); #endif /* listen for connections */ k = listen(sock, 100); assert(k == 0); return sock; } /* * Accept a connection on the named socket. * Return a new socket for the new connection, or -1 if error. */ int AcceptConnection(int socket) { struct sockaddr addr; socklen_t addrLen; int newSock; addrLen = sizeof(addr); newSock = accept(socket, &addr, &addrLen); if (newSock == 1) return -1; else return newSock; } /* * Contact the server running on the given host on the named port. * Return socket number or -1 if error. */ int Connect(const char *hostname, int port) { struct sockaddr_in servaddr; struct hostent *hp; int sock, k; int tcp_nodelay = 1; assert(port); sock = socket(AF_INET, SOCK_STREAM, 0); assert(sock >= 0); hp = gethostbyname(hostname); assert(hp); memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons((unsigned short) port); memcpy((char *) &servaddr.sin_addr, hp->h_addr, sizeof(servaddr.sin_addr)); k = connect(sock, (struct sockaddr *) &servaddr, sizeof(servaddr)); if (k != 0) { perror("Connect:"); return -1; } #if NO_DELAY /* send packets immediately */ k = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &tcp_nodelay, sizeof(tcp_nodelay)); assert(k==0); #endif return sock; } void CloseSocket(int socket) { close(socket); } int SendData(int socket, const void *data, int bytes) { int sent = 0; int b; while (sent < bytes) { b = write(socket, (char *) data + sent, bytes - sent); if (b <= 0) return -1; /* something broke */ sent += b; } return sent; } int ReceiveData(int socket, void *data, int bytes) { int received = 0, b; while (received < bytes) { b = read(socket, (char *) data + received, bytes - received); if (b <= 0) return -1; received += b; } return received; } int SendString(int socket, const char *str) { const int len = strlen(str); int sent, b; /* first, send a 4-byte length indicator */ b = write(socket, &len, sizeof(len)); if (b <= 0) return -1; sent = SendData(socket, str, len); assert(sent == len); return sent; } int ReceiveString(int socket, char *str, int maxLen) { int len, received, b; /* first, read 4 bytes to see how long of string to receive */ b = read(socket, &len, sizeof(len)); if (b <= 0) return -1; assert(len <= maxLen); /* XXX fix someday */ assert(len >= 0); received = ReceiveData(socket, str, len); assert(received != -1); assert(received == len); str[len] = 0; return received; }