~vcs-imports/qemu/git

« back to all changes in this revision

Viewing changes to qemu-sockets.c

  • Committer: blueswir1
  • Date: 2007-11-25 08:48:16 UTC
  • Revision ID: git-v1:b76482e76560345c00e7d6c89199ced204a926d2
 Fix buffer mux handling for unconnected serial ports


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3737 c046a42c-6fe2-441c-8c8c-71466251a162

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#include <stdio.h>
2
 
#include <stdlib.h>
3
 
#include <string.h>
4
 
#include <ctype.h>
5
 
#include <errno.h>
6
 
#include <unistd.h>
7
 
 
8
 
#include "qemu_socket.h"
9
 
 
10
 
#ifndef AI_ADDRCONFIG
11
 
# define AI_ADDRCONFIG 0
12
 
#endif
13
 
 
14
 
static int sockets_debug = 0;
15
 
static const int on=1, off=0;
16
 
 
17
 
static int inet_getport(struct addrinfo *e)
18
 
{
19
 
    struct sockaddr_in *i4;
20
 
    struct sockaddr_in6 *i6;
21
 
 
22
 
    switch (e->ai_family) {
23
 
    case PF_INET6:
24
 
        i6 = (void*)e->ai_addr;
25
 
        return ntohs(i6->sin6_port);
26
 
    case PF_INET:
27
 
        i4 = (void*)e->ai_addr;
28
 
        return ntohs(i4->sin_port);
29
 
    default:
30
 
        return 0;
31
 
    }
32
 
}
33
 
 
34
 
static void inet_setport(struct addrinfo *e, int port)
35
 
{
36
 
    struct sockaddr_in *i4;
37
 
    struct sockaddr_in6 *i6;
38
 
 
39
 
    switch (e->ai_family) {
40
 
    case PF_INET6:
41
 
        i6 = (void*)e->ai_addr;
42
 
        i6->sin6_port = htons(port);
43
 
        break;
44
 
    case PF_INET:
45
 
        i4 = (void*)e->ai_addr;
46
 
        i4->sin_port = htons(port);
47
 
        break;
48
 
    }
49
 
}
50
 
 
51
 
static const char *inet_strfamily(int family)
52
 
{
53
 
    switch (family) {
54
 
    case PF_INET6: return "ipv6";
55
 
    case PF_INET:  return "ipv4";
56
 
    case PF_UNIX:  return "unix";
57
 
    }
58
 
    return "????";
59
 
}
60
 
 
61
 
static void inet_print_addrinfo(const char *tag, struct addrinfo *res)
62
 
{
63
 
    struct addrinfo *e;
64
 
    char uaddr[INET6_ADDRSTRLEN+1];
65
 
    char uport[33];
66
 
 
67
 
    for (e = res; e != NULL; e = e->ai_next) {
68
 
        getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
69
 
                    uaddr,INET6_ADDRSTRLEN,uport,32,
70
 
                    NI_NUMERICHOST | NI_NUMERICSERV);
71
 
        fprintf(stderr,"%s: getaddrinfo: family %s, host %s, port %s\n",
72
 
                tag, inet_strfamily(e->ai_family), uaddr, uport);
73
 
    }
74
 
}
75
 
 
76
 
int inet_listen(const char *str, char *ostr, int olen,
77
 
                int socktype, int port_offset)
78
 
{
79
 
    struct addrinfo ai,*res,*e;
80
 
    char addr[64];
81
 
    char port[33];
82
 
    char uaddr[INET6_ADDRSTRLEN+1];
83
 
    char uport[33];
84
 
    const char *opts, *h;
85
 
    int slisten,rc,pos,to,try_next;
86
 
 
87
 
    memset(&ai,0, sizeof(ai));
88
 
    ai.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
89
 
    ai.ai_family = PF_UNSPEC;
90
 
    ai.ai_socktype = socktype;
91
 
 
92
 
    /* parse address */
93
 
    if (str[0] == ':') {
94
 
        /* no host given */
95
 
        strcpy(addr,"");
96
 
        if (1 != sscanf(str,":%32[^,]%n",port,&pos)) {
97
 
            fprintf(stderr, "%s: portonly parse error (%s)\n",
98
 
                    __FUNCTION__, str);
99
 
            return -1;
100
 
        }
101
 
    } else if (str[0] == '[') {
102
 
        /* IPv6 addr */
103
 
        if (2 != sscanf(str,"[%64[^]]]:%32[^,]%n",addr,port,&pos)) {
104
 
            fprintf(stderr, "%s: ipv6 parse error (%s)\n",
105
 
                    __FUNCTION__, str);
106
 
            return -1;
107
 
        }
108
 
        ai.ai_family = PF_INET6;
109
 
    } else if (isdigit(str[0])) {
110
 
        /* IPv4 addr */
111
 
        if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) {
112
 
            fprintf(stderr, "%s: ipv4 parse error (%s)\n",
113
 
                    __FUNCTION__, str);
114
 
            return -1;
115
 
        }
116
 
        ai.ai_family = PF_INET;
117
 
    } else {
118
 
        /* hostname */
119
 
        if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) {
120
 
            fprintf(stderr, "%s: hostname parse error (%s)\n",
121
 
                    __FUNCTION__, str);
122
 
            return -1;
123
 
        }
124
 
    }
125
 
 
126
 
    /* parse options */
127
 
    opts = str + pos;
128
 
    h = strstr(opts, ",to=");
129
 
    to = h ? atoi(h+4) : 0;
130
 
    if (strstr(opts, ",ipv4"))
131
 
        ai.ai_family = PF_INET;
132
 
    if (strstr(opts, ",ipv6"))
133
 
        ai.ai_family = PF_INET6;
134
 
 
135
 
    /* lookup */
136
 
    if (port_offset)
137
 
        snprintf(port, sizeof(port), "%d", atoi(port) + port_offset);
138
 
    rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res);
139
 
    if (rc != 0) {
140
 
        fprintf(stderr,"%s: getaddrinfo(%s,%s): %s\n", __FUNCTION__,
141
 
                addr, port, gai_strerror(rc));
142
 
        return -1;
143
 
    }
144
 
    if (sockets_debug)
145
 
        inet_print_addrinfo(__FUNCTION__, res);
146
 
 
147
 
    /* create socket + bind */
148
 
    for (e = res; e != NULL; e = e->ai_next) {
149
 
        getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
150
 
                    uaddr,INET6_ADDRSTRLEN,uport,32,
151
 
                    NI_NUMERICHOST | NI_NUMERICSERV);
152
 
        slisten = socket(e->ai_family, e->ai_socktype, e->ai_protocol);
153
 
        if (slisten < 0) {
154
 
            fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
155
 
                    inet_strfamily(e->ai_family), strerror(errno));
156
 
            continue;
157
 
        }
158
 
 
159
 
        setsockopt(slisten,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on));
160
 
#ifdef IPV6_V6ONLY
161
 
        if (e->ai_family == PF_INET6) {
162
 
            /* listen on both ipv4 and ipv6 */
163
 
            setsockopt(slisten,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&off,sizeof(off));
164
 
        }
165
 
#endif
166
 
 
167
 
        for (;;) {
168
 
            if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) {
169
 
                if (sockets_debug)
170
 
                    fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__,
171
 
                            inet_strfamily(e->ai_family), uaddr, inet_getport(e));
172
 
                goto listen;
173
 
            }
174
 
            try_next = to && (inet_getport(e) <= to + port_offset);
175
 
            if (!try_next || sockets_debug)
176
 
                fprintf(stderr,"%s: bind(%s,%s,%d): %s\n", __FUNCTION__,
177
 
                        inet_strfamily(e->ai_family), uaddr, inet_getport(e),
178
 
                        strerror(errno));
179
 
            if (try_next) {
180
 
                inet_setport(e, inet_getport(e) + 1);
181
 
                continue;
182
 
            }
183
 
            break;
184
 
        }
185
 
        closesocket(slisten);
186
 
    }
187
 
    fprintf(stderr, "%s: FAILED\n", __FUNCTION__);
188
 
    freeaddrinfo(res);
189
 
    return -1;
190
 
 
191
 
listen:
192
 
    if (listen(slisten,1) != 0) {
193
 
        perror("listen");
194
 
        closesocket(slisten);
195
 
        return -1;
196
 
    }
197
 
    if (ostr) {
198
 
        if (e->ai_family == PF_INET6) {
199
 
            snprintf(ostr, olen, "[%s]:%d%s", uaddr,
200
 
                     inet_getport(e) - port_offset, opts);
201
 
        } else {
202
 
            snprintf(ostr, olen, "%s:%d%s", uaddr,
203
 
                     inet_getport(e) - port_offset, opts);
204
 
        }
205
 
    }
206
 
    freeaddrinfo(res);
207
 
    return slisten;
208
 
}
209
 
 
210
 
int inet_connect(const char *str, int socktype)
211
 
{
212
 
    struct addrinfo ai,*res,*e;
213
 
    char addr[64];
214
 
    char port[33];
215
 
    char uaddr[INET6_ADDRSTRLEN+1];
216
 
    char uport[33];
217
 
    int sock,rc;
218
 
 
219
 
    memset(&ai,0, sizeof(ai));
220
 
    ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
221
 
    ai.ai_family = PF_UNSPEC;
222
 
    ai.ai_socktype = socktype;
223
 
 
224
 
    /* parse address */
225
 
    if (str[0] == '[') {
226
 
        /* IPv6 addr */
227
 
        if (2 != sscanf(str,"[%64[^]]]:%32[^,]",addr,port)) {
228
 
            fprintf(stderr, "%s: ipv6 parse error (%s)\n",
229
 
                    __FUNCTION__, str);
230
 
            return -1;
231
 
        }
232
 
        ai.ai_family = PF_INET6;
233
 
    } else if (isdigit(str[0])) {
234
 
        /* IPv4 addr */
235
 
        if (2 != sscanf(str,"%64[0-9.]:%32[^,]",addr,port)) {
236
 
            fprintf(stderr, "%s: ipv4 parse error (%s)\n",
237
 
                    __FUNCTION__, str);
238
 
            return -1;
239
 
        }
240
 
        ai.ai_family = PF_INET;
241
 
    } else {
242
 
        /* hostname */
243
 
        if (2 != sscanf(str,"%64[^:]:%32[^,]",addr,port)) {
244
 
            fprintf(stderr, "%s: hostname parse error (%s)\n",
245
 
                    __FUNCTION__, str);
246
 
            return -1;
247
 
        }
248
 
    }
249
 
 
250
 
    /* parse options */
251
 
    if (strstr(str, ",ipv4"))
252
 
        ai.ai_family = PF_INET;
253
 
    if (strstr(str, ",ipv6"))
254
 
        ai.ai_family = PF_INET6;
255
 
 
256
 
    /* lookup */
257
 
    if (0 != (rc = getaddrinfo(addr, port, &ai, &res))) {
258
 
        fprintf(stderr,"getaddrinfo(%s,%s): %s\n", gai_strerror(rc),
259
 
                addr, port);
260
 
        return -1;
261
 
    }
262
 
    if (sockets_debug)
263
 
        inet_print_addrinfo(__FUNCTION__, res);
264
 
 
265
 
    for (e = res; e != NULL; e = e->ai_next) {
266
 
        if (getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
267
 
                        uaddr,INET6_ADDRSTRLEN,uport,32,
268
 
                        NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
269
 
            fprintf(stderr,"%s: getnameinfo: oops\n", __FUNCTION__);
270
 
            continue;
271
 
        }
272
 
        sock = socket(e->ai_family, e->ai_socktype, e->ai_protocol);
273
 
        if (sock < 0) {
274
 
            fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
275
 
                    inet_strfamily(e->ai_family), strerror(errno));
276
 
            continue;
277
 
        }
278
 
        setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on));
279
 
 
280
 
        /* connect to peer */
281
 
        if (connect(sock,e->ai_addr,e->ai_addrlen) < 0) {
282
 
            if (sockets_debug || NULL == e->ai_next)
283
 
                fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__,
284
 
                        inet_strfamily(e->ai_family),
285
 
                        e->ai_canonname, uaddr, uport, strerror(errno));
286
 
            closesocket(sock);
287
 
            continue;
288
 
        }
289
 
        if (sockets_debug)
290
 
            fprintf(stderr, "%s: connect(%s,%s,%s,%s): OK\n", __FUNCTION__,
291
 
                    inet_strfamily(e->ai_family),
292
 
                    e->ai_canonname, uaddr, uport);
293
 
        freeaddrinfo(res);
294
 
        return sock;
295
 
    }
296
 
    freeaddrinfo(res);
297
 
    return -1;
298
 
}
299
 
 
300
 
#ifndef _WIN32
301
 
 
302
 
int unix_listen(const char *str, char *ostr, int olen)
303
 
{
304
 
    struct sockaddr_un un;
305
 
    char *path, *opts;
306
 
    int sock, fd, len;
307
 
 
308
 
    sock = socket(PF_UNIX, SOCK_STREAM, 0);
309
 
    if (sock < 0) {
310
 
        perror("socket(unix)");
311
 
        return -1;
312
 
    }
313
 
 
314
 
    opts = strchr(str, ',');
315
 
    if (opts) {
316
 
        len = opts - str;
317
 
        path = malloc(len+1);
318
 
        snprintf(path, len+1, "%.*s", len, str);
319
 
    } else
320
 
        path = strdup(str);
321
 
 
322
 
    memset(&un, 0, sizeof(un));
323
 
    un.sun_family = AF_UNIX;
324
 
    if (path && strlen(path)) {
325
 
        snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
326
 
    } else {
327
 
        char *tmpdir = getenv("TMPDIR");
328
 
        snprintf(un.sun_path, sizeof(un.sun_path), "%s/qemu-socket-XXXXXX",
329
 
                 tmpdir ? tmpdir : "/tmp");
330
 
        /*
331
 
         * This dummy fd usage silences the mktemp() unsecure warning.
332
 
         * Using mkstemp() doesn't make things more secure here
333
 
         * though.  bind() complains about existing files, so we have
334
 
         * to unlink first and thus re-open the race window.  The
335
 
         * worst case possible is bind() failing, i.e. a DoS attack.
336
 
         */
337
 
        fd = mkstemp(un.sun_path); close(fd);
338
 
    }
339
 
    snprintf(ostr, olen, "%s%s", un.sun_path, opts ? opts : "");
340
 
 
341
 
    unlink(un.sun_path);
342
 
    if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
343
 
        fprintf(stderr, "bind(unix:%s): %s\n", un.sun_path, strerror(errno));
344
 
        goto err;
345
 
    }
346
 
    if (listen(sock, 1) < 0) {
347
 
        fprintf(stderr, "listen(unix:%s): %s\n", un.sun_path, strerror(errno));
348
 
        goto err;
349
 
    }
350
 
 
351
 
    if (sockets_debug)
352
 
        fprintf(stderr, "bind(unix:%s): OK\n", un.sun_path);
353
 
    free(path);
354
 
    return sock;
355
 
 
356
 
err:
357
 
    free(path);
358
 
    closesocket(sock);
359
 
    return -1;
360
 
}
361
 
 
362
 
int unix_connect(const char *path)
363
 
{
364
 
    struct sockaddr_un un;
365
 
    int sock;
366
 
 
367
 
    sock = socket(PF_UNIX, SOCK_STREAM, 0);
368
 
    if (sock < 0) {
369
 
        perror("socket(unix)");
370
 
        return -1;
371
 
    }
372
 
 
373
 
    memset(&un, 0, sizeof(un));
374
 
    un.sun_family = AF_UNIX;
375
 
    snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
376
 
    if (connect(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
377
 
        fprintf(stderr, "connect(unix:%s): %s\n", path, strerror(errno));
378
 
        return -1;
379
 
    }
380
 
 
381
 
    if (sockets_debug)
382
 
        fprintf(stderr, "connect(unix:%s): OK\n", path);
383
 
    return sock;
384
 
}
385
 
 
386
 
#else
387
 
 
388
 
int unix_listen(const char *path, char *ostr, int olen)
389
 
{
390
 
    fprintf(stderr, "unix sockets are not available on windows\n");
391
 
    return -1;
392
 
}
393
 
 
394
 
int unix_connect(const char *path)
395
 
{
396
 
    fprintf(stderr, "unix sockets are not available on windows\n");
397
 
    return -1;
398
 
}
399
 
 
400
 
#endif