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