debuggers.hg

view tools/vnet/vnetd/connection.c @ 0:7d21f7218375

Exact replica of unstable on 051908 + README-this
author Mukesh Rathor
date Mon May 19 15:34:57 2008 -0700 (2008-05-19)
parents
children
line source
1 /*
2 * Copyright (C) 2003 - 2004 Mike Wray <mike.wray@hp.com>.
3 *
4 * This library is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as
6 * published by the Free Software Foundation; either version 2.1 of the
7 * License, or (at your option) any later version. This library is
8 * distributed in the hope that it will be useful, but WITHOUT ANY
9 * WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE.
11 * See the GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library; if not, write to the Free Software Foundation,
15 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
18 #include <stdlib.h>
19 #include <errno.h>
20 #include <unistd.h>
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <arpa/inet.h>
25 #include "allocate.h"
26 #include "connection.h"
27 #include "file_stream.h"
28 #include "socket_stream.h"
30 #define MODULE_NAME "conn"
31 #define DEBUG 1
32 #undef DEBUG
33 #include "debug.h"
35 /** Initialize a file stream from a file desciptor.
36 *
37 * @param fd file descriptor
38 * @param mode file mode
39 * @param buffered make the stream buffered if 1, unbuffered if 0
40 * @param io return parameter for the stream
41 * @return 0 on success, error code otherwise
42 */
43 int stream_init(int fd, const char *mode, int buffered, IOStream **io){
44 int err = 0;
45 *io = file_stream_fdopen(fd, mode);
46 if(!*io){
47 err = -errno;
48 perror("fdopen");
49 goto exit;
50 }
51 if(!buffered){
52 // Make unbuffered.
53 err = file_stream_setvbuf(*io, NULL, _IONBF, 0);
54 if(err){
55 err = -errno;
56 perror("setvbuf");
57 goto exit;
58 }
59 }
60 exit:
61 if(err && *io){
62 IOStream_close(*io);
63 *io = NULL;
64 }
65 return err;
66 }
68 ConnList * ConnList_add(ConnList *l, Conn *conn){
69 ConnList *v;
70 v = ALLOCATE(ConnList);
71 v->conn = conn;
72 v->next =l;
73 return v;
74 }
76 ConnList * ConnList_del(ConnList *l, Conn *conn){
77 ConnList *prev, *curr, *next;
78 for(prev = NULL, curr = l; curr; prev = curr, curr = next){
79 next = curr->next;
80 if(curr->conn == conn){
81 if(prev){
82 prev->next = curr->next;
83 } else {
84 l = curr->next;
85 }
86 }
87 }
88 return l;
89 }
91 void ConnList_close(ConnList *l){
92 for( ; l; l = l->next){
93 Conn_close(l->conn);
94 }
95 }
97 void ConnList_select(ConnList *l, SelectSet *set){
98 for( ; l; l = l->next){
99 Conn_select(l->conn, set);
100 }
101 }
103 /** Handle connections according to a select set.
104 *
105 * @param set indicates ready connections
106 */
107 ConnList * ConnList_handle(ConnList *l, SelectSet *set){
108 ConnList *prev, *curr, *next;
109 Conn *conn;
110 int err;
112 for(prev = NULL, curr = l; curr; prev = curr, curr = next){
113 next = curr->next;
114 conn = curr->conn;
115 err = Conn_handle(conn, set);
116 if(err){
117 if(prev){
118 prev->next = curr->next;
119 } else {
120 l = curr->next;
121 }
122 }
123 }
124 return l;
125 }
127 Conn *Conn_new(int (*fn)(Conn *conn, int mode), void *data){
128 Conn *conn;
129 conn = ALLOCATE(Conn);
130 conn->fn = fn;
131 conn->data = data;
132 return conn;
133 }
135 int Conn_handler(Conn *conn, int mode){
136 int err = 0;
137 dprintf(">\n");
138 if(conn->fn){
139 err = conn->fn(conn, mode);
140 } else {
141 dprintf("> no handler\n");
142 err = -ENOSYS;
143 }
144 if(err < 0){
145 dprintf("> err=%d, closing %d\n", err, conn->sock);
146 Conn_close(conn);
147 }
148 dprintf("< err=%d\n", err);
149 return err;
150 }
152 int Conn_handle(Conn *conn, SelectSet *set){
153 int err = 0;
154 int mode = SelectSet_in(set, conn->sock);
156 dprintf("> sock=%d mode=%d\n", conn->sock, mode);
157 if(mode){
158 err = Conn_handler(conn, mode);
160 }
161 return err;
162 }
164 void Conn_select(Conn *conn, SelectSet *set){
165 dprintf("> sock=%d\n", conn->sock);
166 SelectSet_add(set, conn->sock, conn->mode);
167 }
169 /** Initialize a connection.
170 *
171 * @param conn connection
172 * @param sock socket
173 * @param ipaddr ip address
174 * @return 0 on success, error code otherwise
175 */
176 int Conn_init(Conn *conn, int sock, int type, int mode, struct sockaddr_in addr){
177 int err = 0;
178 conn->addr = addr;
179 conn->type = type;
180 conn->mode = mode;
181 conn->sock = sock;
182 if(type == SOCK_STREAM){
183 err = stream_init(sock, "r", 0, &conn->in);
184 if(err) goto exit;
185 err = stream_init(sock, "w", 0, &conn->out);
186 if(err) goto exit;
187 } else {
188 conn->in = socket_stream_new(sock);
189 conn->out = socket_stream_new(sock);
190 socket_stream_set_addr(conn->out, &addr);
191 }
192 exit:
193 if(err) eprintf("< err=%d\n", err);
194 return err;
195 }
197 /** Open a connection.
198 *
199 * @param conn connection
200 * @param socktype socket type
201 * @param ipaddr ip address to connect to
202 * @param port port
203 * @return 0 on success, error code otherwise
204 */
205 int Conn_connect(Conn *conn, int socktype, struct in_addr ipaddr, uint16_t port){
206 int err = 0;
207 int sock;
208 struct sockaddr_in addr_in;
209 struct sockaddr *addr = (struct sockaddr *)&addr_in;
210 socklen_t addr_n = sizeof(addr_in);
211 dprintf("> addr=%s:%d\n", inet_ntoa(ipaddr), ntohs(port));
212 sock = socket(AF_INET, socktype, 0);
213 if(sock < 0){
214 err = -errno;
215 goto exit;
216 }
217 addr_in.sin_family = AF_INET;
218 addr_in.sin_addr = ipaddr;
219 addr_in.sin_port = port;
220 err = connect(sock, addr, addr_n);
221 if(err) goto exit;
222 err = Conn_init(conn, sock, socktype, 0, addr_in);
223 exit:
224 if(err){
225 perror("Conn_connect");
226 eprintf("< err=%d\n", err);
227 }
228 return err;
229 }
231 /** Close a connection.
232 *
233 * @param conn connection
234 */
235 void Conn_close(Conn *conn){
236 if(!conn) return;
237 if(conn->in) IOStream_close(conn->in);
238 if(conn->out) IOStream_close(conn->out);
239 shutdown(conn->sock, 2);
240 }
242 /** Set socket option to reuse address.
243 */
244 int setsock_reuse(int sock, int val){
245 int err = 0;
246 err = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
247 if(err < 0){
248 err = -errno;
249 perror("setsockopt SO_REUSEADDR");
250 }
251 return err;
252 }
254 /** Set socket broadcast option.
255 */
256 int setsock_broadcast(int sock, int val){
257 int err = 0;
258 err = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val));
259 if(err < 0){
260 err = -errno;
261 perror("setsockopt SO_BROADCAST");
262 }
263 return err;
264 }
266 /** Join a socket to a multicast group.
267 */
268 int setsock_multicast(int sock, uint32_t iaddr, uint32_t maddr){
269 int err = 0;
270 struct ip_mreqn mreq = {};
271 int mloop = 0;
272 // See 'man 7 ip' for these options.
273 mreq.imr_multiaddr.s_addr = maddr; // IP multicast address.
274 mreq.imr_address.s_addr = iaddr; // Interface IP address.
275 mreq.imr_ifindex = 0; // Interface index (0 means any).
276 err = setsockopt(sock, SOL_IP, IP_MULTICAST_LOOP, &mloop, sizeof(mloop));
277 if(err < 0){
278 err = -errno;
279 perror("setsockopt IP_MULTICAST_LOOP");
280 goto exit;
281 }
282 err = setsockopt(sock, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
283 if(err < 0){
284 err = -errno;
285 perror("setsockopt IP_ADD_MEMBERSHIP");
286 goto exit;
287 }
288 exit:
289 return err;
290 }
292 /** Set a socket's multicast ttl (default is 1).
293 */
294 int setsock_multicast_ttl(int sock, uint8_t ttl){
295 int err = 0;
296 err = setsockopt(sock, SOL_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
297 if(err < 0){
298 err = -errno;
299 perror("setsockopt IP_MULTICAST_TTL");
300 }
301 return err;
302 }
304 int setsock_pktinfo(int sock, int val){
305 int err = 0;
306 err = setsockopt(sock, SOL_IP, IP_PKTINFO, &val, sizeof(val));
307 if(err < 0){
308 err = -errno;
309 perror("setsockopt IP_PKTINFO");
310 }
311 return err;
312 }
314 char * socket_flags(int flags){
315 static char s[6];
316 int i = 0;
317 s[i++] = (flags & VSOCK_CONNECT ? 'c' : '-');
318 s[i++] = (flags & VSOCK_BIND ? 'b' : '-');
319 s[i++] = (flags & VSOCK_REUSE ? 'r' : '-');
320 s[i++] = (flags & VSOCK_BROADCAST ? 'B' : '-');
321 s[i++] = (flags & VSOCK_MULTICAST ? 'M' : '-');
322 s[i++] = '\0';
323 return s;
324 }
326 /** Create a socket.
327 * The flags can include VSOCK_REUSE, VSOCK_BROADCAST, VSOCK_CONNECT.
328 *
329 * @param socktype socket type
330 * @param saddr address
331 * @param port port
332 * @param flags flags
333 * @param val return value for the socket connection
334 * @return 0 on success, error code otherwise
335 */
336 int create_socket(int socktype, uint32_t saddr, uint32_t port, int flags, int *val){
337 int err = 0;
338 int sock = 0;
339 struct sockaddr_in addr_in;
340 struct sockaddr *addr = (struct sockaddr *)&addr_in;
341 socklen_t addr_n = sizeof(addr_in);
342 int reuse, bcast;
344 //dprintf(">\n");
345 reuse = (flags & VSOCK_REUSE);
346 bcast = (flags & VSOCK_BROADCAST);
347 addr_in.sin_family = AF_INET;
348 addr_in.sin_addr.s_addr = saddr;
349 addr_in.sin_port = port;
350 dprintf("> flags=%s addr=%s port=%d\n", socket_flags(flags),
351 inet_ntoa(addr_in.sin_addr), ntohs(addr_in.sin_port));
353 sock = socket(AF_INET, socktype, 0);
354 if(sock < 0){
355 err = -errno;
356 goto exit;
357 }
358 if(reuse){
359 err = setsock_reuse(sock, reuse);
360 if(err < 0) goto exit;
361 }
362 if(bcast){
363 err = setsock_broadcast(sock, bcast);
364 if(err < 0) goto exit;
365 }
366 if(flags & VSOCK_CONNECT){
367 err = connect(sock, addr, addr_n);
368 if(err < 0){
369 err = -errno;
370 perror("connect");
371 goto exit;
372 }
373 }
374 if(flags & VSOCK_BIND){
375 err = bind(sock, addr, addr_n);
376 if(err < 0){
377 err = -errno;
378 perror("bind");
379 goto exit;
380 }
381 }
382 {
383 struct sockaddr_in self = {};
384 socklen_t self_n = sizeof(self);
385 getsockname(sock, (struct sockaddr *)&self, &self_n);
386 dprintf("> sockname sock=%d addr=%s port=%d reuse=%d bcast=%d\n",
387 sock, inet_ntoa(self.sin_addr), ntohs(self.sin_port),
388 reuse, bcast);
389 }
390 exit:
391 *val = (err ? -1 : sock);
392 //dprintf("< err=%d\n", err);
393 return err;
394 }
396 int Conn_socket(int socktype, uint32_t saddr, uint32_t port, int flags, Conn **val){
397 int err;
398 int sock;
399 struct sockaddr_in addr_in;
400 Conn *conn;
402 err = create_socket(socktype, saddr, port, flags, &sock);
403 if(err) goto exit;
404 conn = Conn_new(NULL, NULL);
405 addr_in.sin_family = AF_INET;
406 addr_in.sin_addr.s_addr = saddr;
407 addr_in.sin_port = port;
408 Conn_init(conn, sock, socktype, 0, addr_in);
409 exit:
410 *val = (err ? NULL : conn);
411 return err;
412 }