xref: /openbmc/qemu/net/socket.c (revision 7267c094)
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-error.h"
32 #include "qemu-option.h"
33 #include "qemu_socket.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 = qemu_recv(s->fd, 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 = qemu_recv(s->fd, 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, struct in_addr *localaddr)
153 {
154     struct ip_mreq imr;
155     int fd;
156     int val, ret;
157 #ifdef __OpenBSD__
158     unsigned char loop;
159 #else
160     int loop;
161 #endif
162 
163     if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) {
164 	fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) does not contain a multicast address\n",
165 		inet_ntoa(mcastaddr->sin_addr),
166                 (int)ntohl(mcastaddr->sin_addr.s_addr));
167 	return -1;
168 
169     }
170     fd = qemu_socket(PF_INET, SOCK_DGRAM, 0);
171     if (fd < 0) {
172         perror("socket(PF_INET, SOCK_DGRAM)");
173         return -1;
174     }
175 
176     val = 1;
177     ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
178                    (const char *)&val, sizeof(val));
179     if (ret < 0) {
180 	perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
181 	goto fail;
182     }
183 
184     ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr));
185     if (ret < 0) {
186         perror("bind");
187         goto fail;
188     }
189 
190     /* Add host to multicast group */
191     imr.imr_multiaddr = mcastaddr->sin_addr;
192     if (localaddr) {
193         imr.imr_interface = *localaddr;
194     } else {
195         imr.imr_interface.s_addr = htonl(INADDR_ANY);
196     }
197 
198     ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
199                      (const char *)&imr, sizeof(struct ip_mreq));
200     if (ret < 0) {
201 	perror("setsockopt(IP_ADD_MEMBERSHIP)");
202 	goto fail;
203     }
204 
205     /* Force mcast msgs to loopback (eg. several QEMUs in same host */
206     loop = 1;
207     ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
208                    (const char *)&loop, sizeof(loop));
209     if (ret < 0) {
210 	perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)");
211 	goto fail;
212     }
213 
214     /* If a bind address is given, only send packets from that address */
215     if (localaddr != NULL) {
216         ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
217                          (const char *)localaddr, sizeof(*localaddr));
218         if (ret < 0) {
219             perror("setsockopt(IP_MULTICAST_IF)");
220             goto fail;
221         }
222     }
223 
224     socket_set_nonblock(fd);
225     return fd;
226 fail:
227     if (fd >= 0)
228         closesocket(fd);
229     return -1;
230 }
231 
232 static void net_socket_cleanup(VLANClientState *nc)
233 {
234     NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
235     qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
236     close(s->fd);
237 }
238 
239 static NetClientInfo net_dgram_socket_info = {
240     .type = NET_CLIENT_TYPE_SOCKET,
241     .size = sizeof(NetSocketState),
242     .receive = net_socket_receive_dgram,
243     .cleanup = net_socket_cleanup,
244 };
245 
246 static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan,
247                                                 const char *model,
248                                                 const char *name,
249                                                 int fd, int is_connected)
250 {
251     struct sockaddr_in saddr;
252     int newfd;
253     socklen_t saddr_len;
254     VLANClientState *nc;
255     NetSocketState *s;
256 
257     /* fd passed: multicast: "learn" dgram_dst address from bound address and save it
258      * Because this may be "shared" socket from a "master" process, datagrams would be recv()
259      * by ONLY ONE process: we must "clone" this dgram socket --jjo
260      */
261 
262     if (is_connected) {
263 	if (getsockname(fd, (struct sockaddr *) &saddr, &saddr_len) == 0) {
264 	    /* must be bound */
265 	    if (saddr.sin_addr.s_addr==0) {
266 		fprintf(stderr, "qemu: error: init_dgram: fd=%d unbound, cannot setup multicast dst addr\n",
267 			fd);
268 		return NULL;
269 	    }
270 	    /* clone dgram socket */
271 	    newfd = net_socket_mcast_create(&saddr, NULL);
272 	    if (newfd < 0) {
273 		/* error already reported by net_socket_mcast_create() */
274 		close(fd);
275 		return NULL;
276 	    }
277 	    /* clone newfd to fd, close newfd */
278 	    dup2(newfd, fd);
279 	    close(newfd);
280 
281 	} else {
282 	    fprintf(stderr, "qemu: error: init_dgram: fd=%d failed getsockname(): %s\n",
283 		    fd, strerror(errno));
284 	    return NULL;
285 	}
286     }
287 
288     nc = qemu_new_net_client(&net_dgram_socket_info, vlan, NULL, model, name);
289 
290     snprintf(nc->info_str, sizeof(nc->info_str),
291 	    "socket: fd=%d (%s mcast=%s:%d)",
292 	    fd, is_connected ? "cloned" : "",
293 	    inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
294 
295     s = DO_UPCAST(NetSocketState, nc, nc);
296 
297     s->fd = fd;
298 
299     qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s);
300 
301     /* mcast: save bound address as dst */
302     if (is_connected) s->dgram_dst=saddr;
303 
304     return s;
305 }
306 
307 static void net_socket_connect(void *opaque)
308 {
309     NetSocketState *s = opaque;
310     qemu_set_fd_handler(s->fd, net_socket_send, NULL, s);
311 }
312 
313 static NetClientInfo net_socket_info = {
314     .type = NET_CLIENT_TYPE_SOCKET,
315     .size = sizeof(NetSocketState),
316     .receive = net_socket_receive,
317     .cleanup = net_socket_cleanup,
318 };
319 
320 static NetSocketState *net_socket_fd_init_stream(VLANState *vlan,
321                                                  const char *model,
322                                                  const char *name,
323                                                  int fd, int is_connected)
324 {
325     VLANClientState *nc;
326     NetSocketState *s;
327 
328     nc = qemu_new_net_client(&net_socket_info, vlan, NULL, model, name);
329 
330     snprintf(nc->info_str, sizeof(nc->info_str), "socket: fd=%d", fd);
331 
332     s = DO_UPCAST(NetSocketState, nc, nc);
333 
334     s->fd = fd;
335 
336     if (is_connected) {
337         net_socket_connect(s);
338     } else {
339         qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s);
340     }
341     return s;
342 }
343 
344 static NetSocketState *net_socket_fd_init(VLANState *vlan,
345                                           const char *model, const char *name,
346                                           int fd, int is_connected)
347 {
348     int so_type = -1, optlen=sizeof(so_type);
349 
350     if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type,
351         (socklen_t *)&optlen)< 0) {
352 	fprintf(stderr, "qemu: error: getsockopt(SO_TYPE) for fd=%d failed\n", fd);
353 	return NULL;
354     }
355     switch(so_type) {
356     case SOCK_DGRAM:
357         return net_socket_fd_init_dgram(vlan, model, name, fd, is_connected);
358     case SOCK_STREAM:
359         return net_socket_fd_init_stream(vlan, model, name, fd, is_connected);
360     default:
361         /* who knows ... this could be a eg. a pty, do warn and continue as stream */
362         fprintf(stderr, "qemu: warning: socket type=%d for fd=%d is not SOCK_DGRAM or SOCK_STREAM\n", so_type, fd);
363         return net_socket_fd_init_stream(vlan, model, name, fd, is_connected);
364     }
365     return NULL;
366 }
367 
368 static void net_socket_accept(void *opaque)
369 {
370     NetSocketListenState *s = opaque;
371     NetSocketState *s1;
372     struct sockaddr_in saddr;
373     socklen_t len;
374     int fd;
375 
376     for(;;) {
377         len = sizeof(saddr);
378         fd = qemu_accept(s->fd, (struct sockaddr *)&saddr, &len);
379         if (fd < 0 && errno != EINTR) {
380             return;
381         } else if (fd >= 0) {
382             break;
383         }
384     }
385     s1 = net_socket_fd_init(s->vlan, s->model, s->name, fd, 1);
386     if (!s1) {
387         closesocket(fd);
388     } else {
389         snprintf(s1->nc.info_str, sizeof(s1->nc.info_str),
390                  "socket: connection from %s:%d",
391                  inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
392     }
393 }
394 
395 static int net_socket_listen_init(VLANState *vlan,
396                                   const char *model,
397                                   const char *name,
398                                   const char *host_str)
399 {
400     NetSocketListenState *s;
401     int fd, val, ret;
402     struct sockaddr_in saddr;
403 
404     if (parse_host_port(&saddr, host_str) < 0)
405         return -1;
406 
407     s = g_malloc0(sizeof(NetSocketListenState));
408 
409     fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
410     if (fd < 0) {
411         perror("socket");
412         return -1;
413     }
414     socket_set_nonblock(fd);
415 
416     /* allow fast reuse */
417     val = 1;
418     setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
419 
420     ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));
421     if (ret < 0) {
422         perror("bind");
423         return -1;
424     }
425     ret = listen(fd, 0);
426     if (ret < 0) {
427         perror("listen");
428         return -1;
429     }
430     s->vlan = vlan;
431     s->model = g_strdup(model);
432     s->name = name ? g_strdup(name) : NULL;
433     s->fd = fd;
434     qemu_set_fd_handler(fd, net_socket_accept, NULL, s);
435     return 0;
436 }
437 
438 static int net_socket_connect_init(VLANState *vlan,
439                                    const char *model,
440                                    const char *name,
441                                    const char *host_str)
442 {
443     NetSocketState *s;
444     int fd, connected, ret, err;
445     struct sockaddr_in saddr;
446 
447     if (parse_host_port(&saddr, host_str) < 0)
448         return -1;
449 
450     fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
451     if (fd < 0) {
452         perror("socket");
453         return -1;
454     }
455     socket_set_nonblock(fd);
456 
457     connected = 0;
458     for(;;) {
459         ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
460         if (ret < 0) {
461             err = socket_error();
462             if (err == EINTR || err == EWOULDBLOCK) {
463             } else if (err == EINPROGRESS) {
464                 break;
465 #ifdef _WIN32
466             } else if (err == WSAEALREADY || err == WSAEINVAL) {
467                 break;
468 #endif
469             } else {
470                 perror("connect");
471                 closesocket(fd);
472                 return -1;
473             }
474         } else {
475             connected = 1;
476             break;
477         }
478     }
479     s = net_socket_fd_init(vlan, model, name, fd, connected);
480     if (!s)
481         return -1;
482     snprintf(s->nc.info_str, sizeof(s->nc.info_str),
483              "socket: connect to %s:%d",
484              inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
485     return 0;
486 }
487 
488 static int net_socket_mcast_init(VLANState *vlan,
489                                  const char *model,
490                                  const char *name,
491                                  const char *host_str,
492                                  const char *localaddr_str)
493 {
494     NetSocketState *s;
495     int fd;
496     struct sockaddr_in saddr;
497     struct in_addr localaddr, *param_localaddr;
498 
499     if (parse_host_port(&saddr, host_str) < 0)
500         return -1;
501 
502     if (localaddr_str != NULL) {
503         if (inet_aton(localaddr_str, &localaddr) == 0)
504             return -1;
505         param_localaddr = &localaddr;
506     } else {
507         param_localaddr = NULL;
508     }
509 
510     fd = net_socket_mcast_create(&saddr, param_localaddr);
511     if (fd < 0)
512 	return -1;
513 
514     s = net_socket_fd_init(vlan, model, name, fd, 0);
515     if (!s)
516         return -1;
517 
518     s->dgram_dst = saddr;
519 
520     snprintf(s->nc.info_str, sizeof(s->nc.info_str),
521              "socket: mcast=%s:%d",
522              inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
523     return 0;
524 
525 }
526 
527 int net_init_socket(QemuOpts *opts,
528                     Monitor *mon,
529                     const char *name,
530                     VLANState *vlan)
531 {
532     if (qemu_opt_get(opts, "fd")) {
533         int fd;
534 
535         if (qemu_opt_get(opts, "listen") ||
536             qemu_opt_get(opts, "connect") ||
537             qemu_opt_get(opts, "mcast") ||
538             qemu_opt_get(opts, "localaddr")) {
539             error_report("listen=, connect=, mcast= and localaddr= is invalid with fd=");
540             return -1;
541         }
542 
543         fd = net_handle_fd_param(mon, qemu_opt_get(opts, "fd"));
544         if (fd == -1) {
545             return -1;
546         }
547 
548         if (!net_socket_fd_init(vlan, "socket", name, fd, 1)) {
549             close(fd);
550             return -1;
551         }
552     } else if (qemu_opt_get(opts, "listen")) {
553         const char *listen;
554 
555         if (qemu_opt_get(opts, "fd") ||
556             qemu_opt_get(opts, "connect") ||
557             qemu_opt_get(opts, "mcast") ||
558             qemu_opt_get(opts, "localaddr")) {
559             error_report("fd=, connect=, mcast= and localaddr= is invalid with listen=");
560             return -1;
561         }
562 
563         listen = qemu_opt_get(opts, "listen");
564 
565         if (net_socket_listen_init(vlan, "socket", name, listen) == -1) {
566             return -1;
567         }
568     } else if (qemu_opt_get(opts, "connect")) {
569         const char *connect;
570 
571         if (qemu_opt_get(opts, "fd") ||
572             qemu_opt_get(opts, "listen") ||
573             qemu_opt_get(opts, "mcast") ||
574             qemu_opt_get(opts, "localaddr")) {
575             error_report("fd=, listen=, mcast= and localaddr= is invalid with connect=");
576             return -1;
577         }
578 
579         connect = qemu_opt_get(opts, "connect");
580 
581         if (net_socket_connect_init(vlan, "socket", name, connect) == -1) {
582             return -1;
583         }
584     } else if (qemu_opt_get(opts, "mcast")) {
585         const char *mcast, *localaddr;
586 
587         if (qemu_opt_get(opts, "fd") ||
588             qemu_opt_get(opts, "connect") ||
589             qemu_opt_get(opts, "listen")) {
590             error_report("fd=, connect= and listen= is invalid with mcast=");
591             return -1;
592         }
593 
594         mcast = qemu_opt_get(opts, "mcast");
595         localaddr = qemu_opt_get(opts, "localaddr");
596 
597         if (net_socket_mcast_init(vlan, "socket", name, mcast, localaddr) == -1) {
598             return -1;
599         }
600     } else {
601         error_report("-socket requires fd=, listen=, connect= or mcast=");
602         return -1;
603     }
604 
605     return 0;
606 }
607