]> Git Repo - qemu.git/blob - net/socket.c
net: move socket backend code from net.c to net/socket.c
[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 *vc;
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 *vc, const uint8_t *buf, size_t size)
54 {
55     NetSocketState *s = vc->opaque;
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 *vc, const uint8_t *buf, size_t size)
64 {
65     NetSocketState *s = vc->opaque;
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->vc, 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->vc, 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 = 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 *vc)
213 {
214     NetSocketState *s = vc->opaque;
215     qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
216     close(s->fd);
217     qemu_free(s);
218 }
219
220 static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan,
221                                                 const char *model,
222                                                 const char *name,
223                                                 int fd, int is_connected)
224 {
225     struct sockaddr_in saddr;
226     int newfd;
227     socklen_t saddr_len;
228     NetSocketState *s;
229
230     /* fd passed: multicast: "learn" dgram_dst address from bound address and save it
231      * Because this may be "shared" socket from a "master" process, datagrams would be recv()
232      * by ONLY ONE process: we must "clone" this dgram socket --jjo
233      */
234
235     if (is_connected) {
236         if (getsockname(fd, (struct sockaddr *) &saddr, &saddr_len) == 0) {
237             /* must be bound */
238             if (saddr.sin_addr.s_addr==0) {
239                 fprintf(stderr, "qemu: error: init_dgram: fd=%d unbound, cannot setup multicast dst addr\n",
240                         fd);
241                 return NULL;
242             }
243             /* clone dgram socket */
244             newfd = net_socket_mcast_create(&saddr);
245             if (newfd < 0) {
246                 /* error already reported by net_socket_mcast_create() */
247                 close(fd);
248                 return NULL;
249             }
250             /* clone newfd to fd, close newfd */
251             dup2(newfd, fd);
252             close(newfd);
253
254         } else {
255             fprintf(stderr, "qemu: error: init_dgram: fd=%d failed getsockname(): %s\n",
256                     fd, strerror(errno));
257             return NULL;
258         }
259     }
260
261     s = qemu_mallocz(sizeof(NetSocketState));
262     s->fd = fd;
263
264     s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_SOCKET,
265                                  vlan, NULL, model, name, NULL,
266                                  net_socket_receive_dgram, NULL, NULL,
267                                  net_socket_cleanup, s);
268     qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s);
269
270     /* mcast: save bound address as dst */
271     if (is_connected) s->dgram_dst=saddr;
272
273     snprintf(s->vc->info_str, sizeof(s->vc->info_str),
274             "socket: fd=%d (%s mcast=%s:%d)",
275             fd, is_connected? "cloned" : "",
276             inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
277     return s;
278 }
279
280 static void net_socket_connect(void *opaque)
281 {
282     NetSocketState *s = opaque;
283     qemu_set_fd_handler(s->fd, net_socket_send, NULL, s);
284 }
285
286 static NetSocketState *net_socket_fd_init_stream(VLANState *vlan,
287                                                  const char *model,
288                                                  const char *name,
289                                                  int fd, int is_connected)
290 {
291     NetSocketState *s;
292     s = qemu_mallocz(sizeof(NetSocketState));
293     s->fd = fd;
294     s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_SOCKET,
295                                  vlan, NULL, model, name, NULL,
296                                  net_socket_receive, NULL, NULL,
297                                  net_socket_cleanup, s);
298     snprintf(s->vc->info_str, sizeof(s->vc->info_str),
299              "socket: fd=%d", fd);
300     if (is_connected) {
301         net_socket_connect(s);
302     } else {
303         qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s);
304     }
305     return s;
306 }
307
308 static NetSocketState *net_socket_fd_init(VLANState *vlan,
309                                           const char *model, const char *name,
310                                           int fd, int is_connected)
311 {
312     int so_type = -1, optlen=sizeof(so_type);
313
314     if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type,
315         (socklen_t *)&optlen)< 0) {
316         fprintf(stderr, "qemu: error: getsockopt(SO_TYPE) for fd=%d failed\n", fd);
317         return NULL;
318     }
319     switch(so_type) {
320     case SOCK_DGRAM:
321         return net_socket_fd_init_dgram(vlan, model, name, fd, is_connected);
322     case SOCK_STREAM:
323         return net_socket_fd_init_stream(vlan, model, name, fd, is_connected);
324     default:
325         /* who knows ... this could be a eg. a pty, do warn and continue as stream */
326         fprintf(stderr, "qemu: warning: socket type=%d for fd=%d is not SOCK_DGRAM or SOCK_STREAM\n", so_type, fd);
327         return net_socket_fd_init_stream(vlan, model, name, fd, is_connected);
328     }
329     return NULL;
330 }
331
332 static void net_socket_accept(void *opaque)
333 {
334     NetSocketListenState *s = opaque;
335     NetSocketState *s1;
336     struct sockaddr_in saddr;
337     socklen_t len;
338     int fd;
339
340     for(;;) {
341         len = sizeof(saddr);
342         fd = accept(s->fd, (struct sockaddr *)&saddr, &len);
343         if (fd < 0 && errno != EINTR) {
344             return;
345         } else if (fd >= 0) {
346             break;
347         }
348     }
349     s1 = net_socket_fd_init(s->vlan, s->model, s->name, fd, 1);
350     if (!s1) {
351         closesocket(fd);
352     } else {
353         snprintf(s1->vc->info_str, sizeof(s1->vc->info_str),
354                  "socket: connection from %s:%d",
355                  inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
356     }
357 }
358
359 static int net_socket_listen_init(VLANState *vlan,
360                                   const char *model,
361                                   const char *name,
362                                   const char *host_str)
363 {
364     NetSocketListenState *s;
365     int fd, val, ret;
366     struct sockaddr_in saddr;
367
368     if (parse_host_port(&saddr, host_str) < 0)
369         return -1;
370
371     s = qemu_mallocz(sizeof(NetSocketListenState));
372
373     fd = socket(PF_INET, SOCK_STREAM, 0);
374     if (fd < 0) {
375         perror("socket");
376         return -1;
377     }
378     socket_set_nonblock(fd);
379
380     /* allow fast reuse */
381     val = 1;
382     setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
383
384     ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));
385     if (ret < 0) {
386         perror("bind");
387         return -1;
388     }
389     ret = listen(fd, 0);
390     if (ret < 0) {
391         perror("listen");
392         return -1;
393     }
394     s->vlan = vlan;
395     s->model = qemu_strdup(model);
396     s->name = name ? qemu_strdup(name) : NULL;
397     s->fd = fd;
398     qemu_set_fd_handler(fd, net_socket_accept, NULL, s);
399     return 0;
400 }
401
402 static int net_socket_connect_init(VLANState *vlan,
403                                    const char *model,
404                                    const char *name,
405                                    const char *host_str)
406 {
407     NetSocketState *s;
408     int fd, connected, ret, err;
409     struct sockaddr_in saddr;
410
411     if (parse_host_port(&saddr, host_str) < 0)
412         return -1;
413
414     fd = socket(PF_INET, SOCK_STREAM, 0);
415     if (fd < 0) {
416         perror("socket");
417         return -1;
418     }
419     socket_set_nonblock(fd);
420
421     connected = 0;
422     for(;;) {
423         ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
424         if (ret < 0) {
425             err = socket_error();
426             if (err == EINTR || err == EWOULDBLOCK) {
427             } else if (err == EINPROGRESS) {
428                 break;
429 #ifdef _WIN32
430             } else if (err == WSAEALREADY) {
431                 break;
432 #endif
433             } else {
434                 perror("connect");
435                 closesocket(fd);
436                 return -1;
437             }
438         } else {
439             connected = 1;
440             break;
441         }
442     }
443     s = net_socket_fd_init(vlan, model, name, fd, connected);
444     if (!s)
445         return -1;
446     snprintf(s->vc->info_str, sizeof(s->vc->info_str),
447              "socket: connect to %s:%d",
448              inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
449     return 0;
450 }
451
452 static int net_socket_mcast_init(VLANState *vlan,
453                                  const char *model,
454                                  const char *name,
455                                  const char *host_str)
456 {
457     NetSocketState *s;
458     int fd;
459     struct sockaddr_in saddr;
460
461     if (parse_host_port(&saddr, host_str) < 0)
462         return -1;
463
464
465     fd = net_socket_mcast_create(&saddr);
466     if (fd < 0)
467         return -1;
468
469     s = net_socket_fd_init(vlan, model, name, fd, 0);
470     if (!s)
471         return -1;
472
473     s->dgram_dst = saddr;
474
475     snprintf(s->vc->info_str, sizeof(s->vc->info_str),
476              "socket: mcast=%s:%d",
477              inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
478     return 0;
479
480 }
481
482 int net_init_socket(QemuOpts *opts,
483                     Monitor *mon,
484                     const char *name,
485                     VLANState *vlan)
486 {
487     if (qemu_opt_get(opts, "fd")) {
488         int fd;
489
490         if (qemu_opt_get(opts, "listen") ||
491             qemu_opt_get(opts, "connect") ||
492             qemu_opt_get(opts, "mcast")) {
493             qemu_error("listen=, connect= and mcast= is invalid with fd=\n");
494             return -1;
495         }
496
497         fd = net_handle_fd_param(mon, qemu_opt_get(opts, "fd"));
498         if (fd == -1) {
499             return -1;
500         }
501
502         if (!net_socket_fd_init(vlan, "socket", name, fd, 1)) {
503             close(fd);
504             return -1;
505         }
506     } else if (qemu_opt_get(opts, "listen")) {
507         const char *listen;
508
509         if (qemu_opt_get(opts, "fd") ||
510             qemu_opt_get(opts, "connect") ||
511             qemu_opt_get(opts, "mcast")) {
512             qemu_error("fd=, connect= and mcast= is invalid with listen=\n");
513             return -1;
514         }
515
516         listen = qemu_opt_get(opts, "listen");
517
518         if (net_socket_listen_init(vlan, "socket", name, listen) == -1) {
519             return -1;
520         }
521     } else if (qemu_opt_get(opts, "connect")) {
522         const char *connect;
523
524         if (qemu_opt_get(opts, "fd") ||
525             qemu_opt_get(opts, "listen") ||
526             qemu_opt_get(opts, "mcast")) {
527             qemu_error("fd=, listen= and mcast= is invalid with connect=\n");
528             return -1;
529         }
530
531         connect = qemu_opt_get(opts, "connect");
532
533         if (net_socket_connect_init(vlan, "socket", name, connect) == -1) {
534             return -1;
535         }
536     } else if (qemu_opt_get(opts, "mcast")) {
537         const char *mcast;
538
539         if (qemu_opt_get(opts, "fd") ||
540             qemu_opt_get(opts, "connect") ||
541             qemu_opt_get(opts, "listen")) {
542             qemu_error("fd=, connect= and listen= is invalid with mcast=\n");
543             return -1;
544         }
545
546         mcast = qemu_opt_get(opts, "mcast");
547
548         if (net_socket_mcast_init(vlan, "socket", name, mcast) == -1) {
549             return -1;
550         }
551     } else {
552         qemu_error("-socket requires fd=, listen=, connect= or mcast=\n");
553         return -1;
554     }
555
556     if (vlan) {
557         vlan->nb_host_devs++;
558     }
559
560     return 0;
561 }
This page took 0.054844 seconds and 4 git commands to generate.