]> Git Repo - qemu.git/blob - net/socket.c
Fix regression in option parsing
[qemu.git] / net / socket.c
1 /*
2  * QEMU System Emulator
3  *
4  * Copyright (c) 2003-2008 Fabrice Bellard
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 #include "net/socket.h"
25
26 #include "config-host.h"
27
28 #include "net.h"
29 #include "qemu-char.h"
30 #include "qemu-common.h"
31 #include "qemu-option.h"
32 #include "qemu_socket.h"
33 #include "sysemu.h"
34
35 typedef struct NetSocketState {
36     VLANClientState nc;
37     int fd;
38     int state; /* 0 = getting length, 1 = getting data */
39     unsigned int index;
40     unsigned int packet_len;
41     uint8_t buf[4096];
42     struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */
43 } NetSocketState;
44
45 typedef struct NetSocketListenState {
46     VLANState *vlan;
47     char *model;
48     char *name;
49     int fd;
50 } NetSocketListenState;
51
52 /* XXX: we consider we can send the whole packet without blocking */
53 static ssize_t net_socket_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
54 {
55     NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
56     uint32_t len;
57     len = htonl(size);
58
59     send_all(s->fd, (const uint8_t *)&len, sizeof(len));
60     return send_all(s->fd, buf, size);
61 }
62
63 static ssize_t net_socket_receive_dgram(VLANClientState *nc, const uint8_t *buf, size_t size)
64 {
65     NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
66
67     return sendto(s->fd, (const void *)buf, size, 0,
68                   (struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst));
69 }
70
71 static void net_socket_send(void *opaque)
72 {
73     NetSocketState *s = opaque;
74     int size, err;
75     unsigned l;
76     uint8_t buf1[4096];
77     const uint8_t *buf;
78
79     size = recv(s->fd, (void *)buf1, sizeof(buf1), 0);
80     if (size < 0) {
81         err = socket_error();
82         if (err != EWOULDBLOCK)
83             goto eoc;
84     } else if (size == 0) {
85         /* end of connection */
86     eoc:
87         qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
88         closesocket(s->fd);
89         return;
90     }
91     buf = buf1;
92     while (size > 0) {
93         /* reassemble a packet from the network */
94         switch(s->state) {
95         case 0:
96             l = 4 - s->index;
97             if (l > size)
98                 l = size;
99             memcpy(s->buf + s->index, buf, l);
100             buf += l;
101             size -= l;
102             s->index += l;
103             if (s->index == 4) {
104                 /* got length */
105                 s->packet_len = ntohl(*(uint32_t *)s->buf);
106                 s->index = 0;
107                 s->state = 1;
108             }
109             break;
110         case 1:
111             l = s->packet_len - s->index;
112             if (l > size)
113                 l = size;
114             if (s->index + l <= sizeof(s->buf)) {
115                 memcpy(s->buf + s->index, buf, l);
116             } else {
117                 fprintf(stderr, "serious error: oversized packet received,"
118                     "connection terminated.\n");
119                 s->state = 0;
120                 goto eoc;
121             }
122
123             s->index += l;
124             buf += l;
125             size -= l;
126             if (s->index >= s->packet_len) {
127                 qemu_send_packet(&s->nc, s->buf, s->packet_len);
128                 s->index = 0;
129                 s->state = 0;
130             }
131             break;
132         }
133     }
134 }
135
136 static void net_socket_send_dgram(void *opaque)
137 {
138     NetSocketState *s = opaque;
139     int size;
140
141     size = recv(s->fd, (void *)s->buf, sizeof(s->buf), 0);
142     if (size < 0)
143         return;
144     if (size == 0) {
145         /* end of connection */
146         qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
147         return;
148     }
149     qemu_send_packet(&s->nc, s->buf, size);
150 }
151
152 static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
153 {
154     struct ip_mreq imr;
155     int fd;
156     int val, ret;
157     if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) {
158         fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) does not contain a multicast address\n",
159                 inet_ntoa(mcastaddr->sin_addr),
160                 (int)ntohl(mcastaddr->sin_addr.s_addr));
161         return -1;
162
163     }
164     fd = qemu_socket(PF_INET, SOCK_DGRAM, 0);
165     if (fd < 0) {
166         perror("socket(PF_INET, SOCK_DGRAM)");
167         return -1;
168     }
169
170     val = 1;
171     ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
172                    (const char *)&val, sizeof(val));
173     if (ret < 0) {
174         perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
175         goto fail;
176     }
177
178     ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr));
179     if (ret < 0) {
180         perror("bind");
181         goto fail;
182     }
183
184     /* Add host to multicast group */
185     imr.imr_multiaddr = mcastaddr->sin_addr;
186     imr.imr_interface.s_addr = htonl(INADDR_ANY);
187
188     ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
189                      (const char *)&imr, sizeof(struct ip_mreq));
190     if (ret < 0) {
191         perror("setsockopt(IP_ADD_MEMBERSHIP)");
192         goto fail;
193     }
194
195     /* Force mcast msgs to loopback (eg. several QEMUs in same host */
196     val = 1;
197     ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
198                    (const char *)&val, sizeof(val));
199     if (ret < 0) {
200         perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)");
201         goto fail;
202     }
203
204     socket_set_nonblock(fd);
205     return fd;
206 fail:
207     if (fd >= 0)
208         closesocket(fd);
209     return -1;
210 }
211
212 static void net_socket_cleanup(VLANClientState *nc)
213 {
214     NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
215     qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
216     close(s->fd);
217 }
218
219 static NetClientInfo net_dgram_socket_info = {
220     .type = NET_CLIENT_TYPE_SOCKET,
221     .size = sizeof(NetSocketState),
222     .receive = net_socket_receive_dgram,
223     .cleanup = net_socket_cleanup,
224 };
225
226 static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan,
227                                                 const char *model,
228                                                 const char *name,
229                                                 int fd, int is_connected)
230 {
231     struct sockaddr_in saddr;
232     int newfd;
233     socklen_t saddr_len;
234     VLANClientState *nc;
235     NetSocketState *s;
236
237     /* fd passed: multicast: "learn" dgram_dst address from bound address and save it
238      * Because this may be "shared" socket from a "master" process, datagrams would be recv()
239      * by ONLY ONE process: we must "clone" this dgram socket --jjo
240      */
241
242     if (is_connected) {
243         if (getsockname(fd, (struct sockaddr *) &saddr, &saddr_len) == 0) {
244             /* must be bound */
245             if (saddr.sin_addr.s_addr==0) {
246                 fprintf(stderr, "qemu: error: init_dgram: fd=%d unbound, cannot setup multicast dst addr\n",
247                         fd);
248                 return NULL;
249             }
250             /* clone dgram socket */
251             newfd = net_socket_mcast_create(&saddr);
252             if (newfd < 0) {
253                 /* error already reported by net_socket_mcast_create() */
254                 close(fd);
255                 return NULL;
256             }
257             /* clone newfd to fd, close newfd */
258             dup2(newfd, fd);
259             close(newfd);
260
261         } else {
262             fprintf(stderr, "qemu: error: init_dgram: fd=%d failed getsockname(): %s\n",
263                     fd, strerror(errno));
264             return NULL;
265         }
266     }
267
268     nc = qemu_new_net_client(&net_dgram_socket_info, vlan, NULL, model, name);
269
270     snprintf(nc->info_str, sizeof(nc->info_str),
271             "socket: fd=%d (%s mcast=%s:%d)",
272             fd, is_connected ? "cloned" : "",
273             inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
274
275     s = DO_UPCAST(NetSocketState, nc, nc);
276
277     s->fd = fd;
278
279     qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s);
280
281     /* mcast: save bound address as dst */
282     if (is_connected) s->dgram_dst=saddr;
283
284     return s;
285 }
286
287 static void net_socket_connect(void *opaque)
288 {
289     NetSocketState *s = opaque;
290     qemu_set_fd_handler(s->fd, net_socket_send, NULL, s);
291 }
292
293 static NetClientInfo net_socket_info = {
294     .type = NET_CLIENT_TYPE_SOCKET,
295     .size = sizeof(NetSocketState),
296     .receive = net_socket_receive,
297     .cleanup = net_socket_cleanup,
298 };
299
300 static NetSocketState *net_socket_fd_init_stream(VLANState *vlan,
301                                                  const char *model,
302                                                  const char *name,
303                                                  int fd, int is_connected)
304 {
305     VLANClientState *nc;
306     NetSocketState *s;
307
308     nc = qemu_new_net_client(&net_socket_info, vlan, NULL, model, name);
309
310     snprintf(nc->info_str, sizeof(nc->info_str), "socket: fd=%d", fd);
311
312     s = DO_UPCAST(NetSocketState, nc, nc);
313
314     s->fd = fd;
315
316     if (is_connected) {
317         net_socket_connect(s);
318     } else {
319         qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s);
320     }
321     return s;
322 }
323
324 static NetSocketState *net_socket_fd_init(VLANState *vlan,
325                                           const char *model, const char *name,
326                                           int fd, int is_connected)
327 {
328     int so_type = -1, optlen=sizeof(so_type);
329
330     if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type,
331         (socklen_t *)&optlen)< 0) {
332         fprintf(stderr, "qemu: error: getsockopt(SO_TYPE) for fd=%d failed\n", fd);
333         return NULL;
334     }
335     switch(so_type) {
336     case SOCK_DGRAM:
337         return net_socket_fd_init_dgram(vlan, model, name, fd, is_connected);
338     case SOCK_STREAM:
339         return net_socket_fd_init_stream(vlan, model, name, fd, is_connected);
340     default:
341         /* who knows ... this could be a eg. a pty, do warn and continue as stream */
342         fprintf(stderr, "qemu: warning: socket type=%d for fd=%d is not SOCK_DGRAM or SOCK_STREAM\n", so_type, fd);
343         return net_socket_fd_init_stream(vlan, model, name, fd, is_connected);
344     }
345     return NULL;
346 }
347
348 static void net_socket_accept(void *opaque)
349 {
350     NetSocketListenState *s = opaque;
351     NetSocketState *s1;
352     struct sockaddr_in saddr;
353     socklen_t len;
354     int fd;
355
356     for(;;) {
357         len = sizeof(saddr);
358         fd = qemu_accept(s->fd, (struct sockaddr *)&saddr, &len);
359         if (fd < 0 && errno != EINTR) {
360             return;
361         } else if (fd >= 0) {
362             break;
363         }
364     }
365     s1 = net_socket_fd_init(s->vlan, s->model, s->name, fd, 1);
366     if (!s1) {
367         closesocket(fd);
368     } else {
369         snprintf(s1->nc.info_str, sizeof(s1->nc.info_str),
370                  "socket: connection from %s:%d",
371                  inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
372     }
373 }
374
375 static int net_socket_listen_init(VLANState *vlan,
376                                   const char *model,
377                                   const char *name,
378                                   const char *host_str)
379 {
380     NetSocketListenState *s;
381     int fd, val, ret;
382     struct sockaddr_in saddr;
383
384     if (parse_host_port(&saddr, host_str) < 0)
385         return -1;
386
387     s = qemu_mallocz(sizeof(NetSocketListenState));
388
389     fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
390     if (fd < 0) {
391         perror("socket");
392         return -1;
393     }
394     socket_set_nonblock(fd);
395
396     /* allow fast reuse */
397     val = 1;
398     setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
399
400     ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));
401     if (ret < 0) {
402         perror("bind");
403         return -1;
404     }
405     ret = listen(fd, 0);
406     if (ret < 0) {
407         perror("listen");
408         return -1;
409     }
410     s->vlan = vlan;
411     s->model = qemu_strdup(model);
412     s->name = name ? qemu_strdup(name) : NULL;
413     s->fd = fd;
414     qemu_set_fd_handler(fd, net_socket_accept, NULL, s);
415     return 0;
416 }
417
418 static int net_socket_connect_init(VLANState *vlan,
419                                    const char *model,
420                                    const char *name,
421                                    const char *host_str)
422 {
423     NetSocketState *s;
424     int fd, connected, ret, err;
425     struct sockaddr_in saddr;
426
427     if (parse_host_port(&saddr, host_str) < 0)
428         return -1;
429
430     fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
431     if (fd < 0) {
432         perror("socket");
433         return -1;
434     }
435     socket_set_nonblock(fd);
436
437     connected = 0;
438     for(;;) {
439         ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
440         if (ret < 0) {
441             err = socket_error();
442             if (err == EINTR || err == EWOULDBLOCK) {
443             } else if (err == EINPROGRESS) {
444                 break;
445 #ifdef _WIN32
446             } else if (err == WSAEALREADY) {
447                 break;
448 #endif
449             } else {
450                 perror("connect");
451                 closesocket(fd);
452                 return -1;
453             }
454         } else {
455             connected = 1;
456             break;
457         }
458     }
459     s = net_socket_fd_init(vlan, model, name, fd, connected);
460     if (!s)
461         return -1;
462     snprintf(s->nc.info_str, sizeof(s->nc.info_str),
463              "socket: connect to %s:%d",
464              inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
465     return 0;
466 }
467
468 static int net_socket_mcast_init(VLANState *vlan,
469                                  const char *model,
470                                  const char *name,
471                                  const char *host_str)
472 {
473     NetSocketState *s;
474     int fd;
475     struct sockaddr_in saddr;
476
477     if (parse_host_port(&saddr, host_str) < 0)
478         return -1;
479
480
481     fd = net_socket_mcast_create(&saddr);
482     if (fd < 0)
483         return -1;
484
485     s = net_socket_fd_init(vlan, model, name, fd, 0);
486     if (!s)
487         return -1;
488
489     s->dgram_dst = saddr;
490
491     snprintf(s->nc.info_str, sizeof(s->nc.info_str),
492              "socket: mcast=%s:%d",
493              inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
494     return 0;
495
496 }
497
498 int net_init_socket(QemuOpts *opts,
499                     Monitor *mon,
500                     const char *name,
501                     VLANState *vlan)
502 {
503     if (qemu_opt_get(opts, "fd")) {
504         int fd;
505
506         if (qemu_opt_get(opts, "listen") ||
507             qemu_opt_get(opts, "connect") ||
508             qemu_opt_get(opts, "mcast")) {
509             qemu_error("listen=, connect= and mcast= is invalid with fd=\n");
510             return -1;
511         }
512
513         fd = net_handle_fd_param(mon, qemu_opt_get(opts, "fd"));
514         if (fd == -1) {
515             return -1;
516         }
517
518         if (!net_socket_fd_init(vlan, "socket", name, fd, 1)) {
519             close(fd);
520             return -1;
521         }
522     } else if (qemu_opt_get(opts, "listen")) {
523         const char *listen;
524
525         if (qemu_opt_get(opts, "fd") ||
526             qemu_opt_get(opts, "connect") ||
527             qemu_opt_get(opts, "mcast")) {
528             qemu_error("fd=, connect= and mcast= is invalid with listen=\n");
529             return -1;
530         }
531
532         listen = qemu_opt_get(opts, "listen");
533
534         if (net_socket_listen_init(vlan, "socket", name, listen) == -1) {
535             return -1;
536         }
537     } else if (qemu_opt_get(opts, "connect")) {
538         const char *connect;
539
540         if (qemu_opt_get(opts, "fd") ||
541             qemu_opt_get(opts, "listen") ||
542             qemu_opt_get(opts, "mcast")) {
543             qemu_error("fd=, listen= and mcast= is invalid with connect=\n");
544             return -1;
545         }
546
547         connect = qemu_opt_get(opts, "connect");
548
549         if (net_socket_connect_init(vlan, "socket", name, connect) == -1) {
550             return -1;
551         }
552     } else if (qemu_opt_get(opts, "mcast")) {
553         const char *mcast;
554
555         if (qemu_opt_get(opts, "fd") ||
556             qemu_opt_get(opts, "connect") ||
557             qemu_opt_get(opts, "listen")) {
558             qemu_error("fd=, connect= and listen= is invalid with mcast=\n");
559             return -1;
560         }
561
562         mcast = qemu_opt_get(opts, "mcast");
563
564         if (net_socket_mcast_init(vlan, "socket", name, mcast) == -1) {
565             return -1;
566         }
567     } else {
568         qemu_error("-socket requires fd=, listen=, connect= or mcast=\n");
569         return -1;
570     }
571
572     if (vlan) {
573         vlan->nb_host_devs++;
574     }
575
576     return 0;
577 }
This page took 0.057906 seconds and 4 git commands to generate.