source: trunk/packages/xen-3.1/xen-3.1/tools/vnet/vnetd/connection.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 10.6 KB
Line 
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 */
17
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>
24
25#include "allocate.h"
26#include "connection.h"
27#include "file_stream.h"
28#include "socket_stream.h"
29
30#define MODULE_NAME "conn"
31#define DEBUG 1
32#undef DEBUG
33#include "debug.h"
34
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 */
43int 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}
67
68ConnList * 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}
75
76ConnList * 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}
90
91void ConnList_close(ConnList *l){
92    for( ; l; l = l->next){
93        Conn_close(l->conn);
94    }
95}
96   
97void ConnList_select(ConnList *l, SelectSet *set){
98    for( ; l; l = l->next){
99        Conn_select(l->conn, set);
100    }
101}
102
103/** Handle connections according to a select set.
104 *
105 * @param set indicates ready connections
106 */
107ConnList * ConnList_handle(ConnList *l, SelectSet *set){
108    ConnList *prev, *curr, *next;
109    Conn *conn;
110    int err;
111
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}
126
127Conn *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}
134
135int 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}
151
152int Conn_handle(Conn *conn, SelectSet *set){
153    int err = 0;
154    int mode = SelectSet_in(set, conn->sock);
155
156    dprintf("> sock=%d mode=%d\n", conn->sock, mode);
157    if(mode){
158        err = Conn_handler(conn, mode);
159
160    }
161    return err;
162}
163
164void Conn_select(Conn *conn, SelectSet *set){
165    dprintf("> sock=%d\n", conn->sock);
166    SelectSet_add(set, conn->sock, conn->mode);
167}
168
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 */
176int 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}
196
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 */
205int 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}
230
231/** Close a connection.
232 *
233 * @param conn connection
234 */
235void 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}
241
242/** Set socket option to reuse address.
243 */
244int 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}
253
254/** Set socket broadcast option.
255 */
256int 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}
265
266/** Join a socket to a multicast group.
267 */
268int 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}
291
292/** Set a socket's multicast ttl (default is 1).
293 */
294int 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}
303
304int 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}
313
314char * 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}
325
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 */
336int 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;
343
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));
352
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}
395
396int 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;
401
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}
Note: See TracBrowser for help on using the repository browser.