blob: c872d1641ab2e82f70b78aceee2527bd6541315f [file] [log] [blame]
Brian72c88882007-10-11 18:25:12 -06001/* Copyright (c) 2003 Tungsten Graphics, Inc.
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining
4 * a copy of this software and associated documentation files ("the
5 * Software"), to deal in the Software without restriction, including
6 * without limitation the rights to use, copy, modify, merge, publish,
7 * distribute, sublicense, and/or sell copies of the Software, and to
8 * permit persons to whom the Software is furnished to do so, subject to
9 * the following conditions: The above copyright notice, the Tungsten
10 * Graphics splash screen, and this permission notice shall be included
11 * in all copies or substantial portions of the Software. THE SOFTWARE
12 * IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
15 * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
16 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
17 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
18 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 */
20
21/*
22 * Simple IPC API
23 * Brian Paul
24 */
25
26
27#include <assert.h>
28#include <stdio.h>
29#include <string.h>
Eric Anholtbcb61982008-03-20 17:19:07 -070030#include <sys/types.h>
Brian72c88882007-10-11 18:25:12 -060031#include <netinet/in.h>
32#include <netinet/tcp.h>
33#include <arpa/inet.h>
34#include <netdb.h>
35#include <unistd.h>
Brian72c88882007-10-11 18:25:12 -060036#include <sys/socket.h>
37#include "ipc.h"
38
39#if defined(IRIX) || defined(irix)
40typedef int socklen_t;
41#endif
42
43#define NO_DELAY 1
44
45#define DEFAULT_MASTER_PORT 7011
46
47
48/*
49 * Return my hostname in <nameOut>.
50 * Return 1 for success, 0 for error.
51 */
52int
53MyHostName(char *nameOut, int maxNameLength)
54{
55 int k = gethostname(nameOut, maxNameLength);
56 return k==0;
57}
58
59
60/*
61 * Create a socket attached to a port. Later, we can call AcceptConnection
62 * on the socket returned from this function.
63 * Return the new socket number or -1 if error.
64 */
65int
66CreatePort(int *port)
67{
68 char hostname[1000];
69 struct sockaddr_in servaddr;
70 struct hostent *hp;
71 int so_reuseaddr = 1;
72 int tcp_nodelay = 1;
73 int sock, k;
74
75 /* create socket */
76 sock = socket(AF_INET, SOCK_STREAM, 0);
77 assert(sock > 2);
78
79 /* get my host name */
80 k = gethostname(hostname, 1000);
81 assert(k == 0);
82
83 /* get hostent info */
84 hp = gethostbyname(hostname);
85 assert(hp);
86
87 /* initialize the servaddr struct */
88 memset(&servaddr, 0, sizeof(servaddr) );
89 servaddr.sin_family = AF_INET;
90 servaddr.sin_port = htons((unsigned short) (*port));
91 memcpy((char *) &servaddr.sin_addr, hp->h_addr,
92 sizeof(servaddr.sin_addr));
93
94 /* deallocate when we exit */
95 k = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
96 (char *) &so_reuseaddr, sizeof(so_reuseaddr));
97 assert(k==0);
98
99 /* send packets immediately */
100#if NO_DELAY
101 k = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
102 (char *) &tcp_nodelay, sizeof(tcp_nodelay));
103 assert(k==0);
104#endif
105
106 if (*port == 0)
107 *port = DEFAULT_MASTER_PORT;
108
109 k = 1;
110 while (k && (*port < 65534)) {
111 /* bind our address to the socket */
112 servaddr.sin_port = htons((unsigned short) (*port));
113 k = bind(sock, (struct sockaddr *) &servaddr, sizeof(servaddr));
114 if (k)
115 *port = *port + 1;
116 }
117
118#if 0
119 printf("###### Real Port: %d\n", *port);
120#endif
121
122 /* listen for connections */
123 k = listen(sock, 100);
124 assert(k == 0);
125
126 return sock;
127}
128
129
130/*
131 * Accept a connection on the named socket.
132 * Return a new socket for the new connection, or -1 if error.
133 */
134int
135AcceptConnection(int socket)
136{
137 struct sockaddr addr;
138 socklen_t addrLen;
139 int newSock;
140
141 addrLen = sizeof(addr);
142 newSock = accept(socket, &addr, &addrLen);
143 if (newSock == 1)
144 return -1;
145 else
146 return newSock;
147}
148
149
150/*
151 * Contact the server running on the given host on the named port.
152 * Return socket number or -1 if error.
153 */
154int
155Connect(const char *hostname, int port)
156{
157 struct sockaddr_in servaddr;
158 struct hostent *hp;
159 int sock, k;
160 int tcp_nodelay = 1;
161
162 assert(port);
163
164 sock = socket(AF_INET, SOCK_STREAM, 0);
165 assert(sock >= 0);
166
167 hp = gethostbyname(hostname);
168 assert(hp);
169
170 memset(&servaddr, 0, sizeof(servaddr));
171 servaddr.sin_family = AF_INET;
172 servaddr.sin_port = htons((unsigned short) port);
173 memcpy((char *) &servaddr.sin_addr, hp->h_addr, sizeof(servaddr.sin_addr));
174
175 k = connect(sock, (struct sockaddr *) &servaddr, sizeof(servaddr));
176 if (k != 0) {
177 perror("Connect:");
178 return -1;
179 }
180
181#if NO_DELAY
182 /* send packets immediately */
183 k = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
184 (char *) &tcp_nodelay, sizeof(tcp_nodelay));
185 assert(k==0);
186#endif
187
188 return sock;
189}
190
191
192void
193CloseSocket(int socket)
194{
195 close(socket);
196}
197
198
199int
200SendData(int socket, const void *data, int bytes)
201{
202 int sent = 0;
203 int b;
204
205 while (sent < bytes) {
206 b = write(socket, (char *) data + sent, bytes - sent);
207 if (b <= 0)
208 return -1; /* something broke */
209 sent += b;
210 }
211 return sent;
212}
213
214
215int
216ReceiveData(int socket, void *data, int bytes)
217{
218 int received = 0, b;
219
220 while (received < bytes) {
221 b = read(socket, (char *) data + received, bytes - received);
222 if (b <= 0)
223 return -1;
224 received += b;
225 }
226 return received;
227}
228
229
230int
231SendString(int socket, const char *str)
232{
233 const int len = strlen(str);
234 int sent, b;
235
236 /* first, send a 4-byte length indicator */
237 b = write(socket, &len, sizeof(len));
238 if (b <= 0)
239 return -1;
240
241 sent = SendData(socket, str, len);
242 assert(sent == len);
243 return sent;
244}
245
246
247int
248ReceiveString(int socket, char *str, int maxLen)
249{
250 int len, received, b;
251
252 /* first, read 4 bytes to see how long of string to receive */
253 b = read(socket, &len, sizeof(len));
254 if (b <= 0)
255 return -1;
256
257 assert(len <= maxLen); /* XXX fix someday */
258 assert(len >= 0);
259 received = ReceiveData(socket, str, len);
260 assert(received != -1);
261 assert(received == len);
262 str[len] = 0;
263 return received;
264}