]> Git Repo - qemu.git/blob - slirp/src/misc.c
Makefile: install the edk2 firmware images and their descriptors
[qemu.git] / slirp / src / misc.c
1 /* SPDX-License-Identifier: BSD-3-Clause */
2 /*
3  * Copyright (c) 1995 Danny Gasparovski.
4  */
5
6 #include "slirp.h"
7
8 inline void
9 insque(void *a, void *b)
10 {
11         register struct quehead *element = (struct quehead *) a;
12         register struct quehead *head = (struct quehead *) b;
13         element->qh_link = head->qh_link;
14         head->qh_link = (struct quehead *)element;
15         element->qh_rlink = (struct quehead *)head;
16         ((struct quehead *)(element->qh_link))->qh_rlink
17         = (struct quehead *)element;
18 }
19
20 inline void
21 remque(void *a)
22 {
23   register struct quehead *element = (struct quehead *) a;
24   ((struct quehead *)(element->qh_link))->qh_rlink = element->qh_rlink;
25   ((struct quehead *)(element->qh_rlink))->qh_link = element->qh_link;
26   element->qh_rlink = NULL;
27 }
28
29 /* TODO: IPv6 */
30 struct gfwd_list *
31 add_guestfwd(struct gfwd_list **ex_ptr,
32              SlirpWriteCb write_cb, void *opaque,
33              struct in_addr addr, int port)
34 {
35     struct gfwd_list *f = g_new0(struct gfwd_list, 1);
36
37     f->write_cb = write_cb;
38     f->opaque = opaque;
39     f->ex_fport = port;
40     f->ex_addr = addr;
41     f->ex_next = *ex_ptr;
42     *ex_ptr = f;
43
44     return f;
45 }
46
47 struct gfwd_list *
48 add_exec(struct gfwd_list **ex_ptr, const char *cmdline,
49          struct in_addr addr, int port)
50 {
51     struct gfwd_list *f = add_guestfwd(ex_ptr, NULL, NULL, addr, port);
52
53     f->ex_exec = g_strdup(cmdline);
54
55     return f;
56 }
57
58 static int
59 slirp_socketpair_with_oob(int sv[2])
60 {
61     struct sockaddr_in addr = {
62         .sin_family = AF_INET,
63         .sin_port = 0,
64         .sin_addr.s_addr = INADDR_ANY,
65     };
66     socklen_t addrlen = sizeof(addr);
67     int ret, s;
68
69     sv[1] = -1;
70     s = slirp_socket(AF_INET, SOCK_STREAM, 0);
71     if (s < 0 || bind(s, (struct sockaddr *)&addr, addrlen) < 0 ||
72         listen(s, 1) < 0 ||
73         getsockname(s, (struct sockaddr *)&addr, &addrlen) < 0) {
74         goto err;
75     }
76
77     sv[1] = slirp_socket(AF_INET, SOCK_STREAM, 0);
78     if (sv[1] < 0) {
79         goto err;
80     }
81     /*
82      * This connect won't block because we've already listen()ed on
83      * the server end (even though we won't accept() the connection
84      * until later on).
85      */
86     do {
87         ret = connect(sv[1], (struct sockaddr *)&addr, addrlen);
88     } while (ret < 0 && errno == EINTR);
89     if (ret < 0) {
90         goto err;
91     }
92
93     do {
94         sv[0] = accept(s, (struct sockaddr *)&addr, &addrlen);
95     } while (sv[0] < 0 && errno == EINTR);
96     if (sv[0] < 0) {
97         goto err;
98     }
99
100     closesocket(s);
101     return 0;
102
103 err:
104     g_critical("slirp_socketpair(): %s", strerror(errno));
105     if (s >= 0) {
106         closesocket(s);
107     }
108     if (sv[1] >= 0) {
109         closesocket(sv[1]);
110     }
111     return -1;
112 }
113
114 static void
115 fork_exec_child_setup(gpointer data)
116 {
117 #ifndef _WIN32
118     setsid();
119 #endif
120 }
121
122 #pragma GCC diagnostic push
123 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
124
125 #if !GLIB_CHECK_VERSION(2, 58, 0)
126 typedef struct SlirpGSpawnFds {
127     GSpawnChildSetupFunc child_setup;
128     gpointer user_data;
129     gint stdin_fd;
130     gint stdout_fd;
131     gint stderr_fd;
132 } SlirpGSpawnFds;
133
134 static inline void
135 slirp_gspawn_fds_setup(gpointer user_data)
136 {
137     SlirpGSpawnFds *q = (SlirpGSpawnFds *)user_data;
138
139     dup2(q->stdin_fd, 0);
140     dup2(q->stdout_fd, 1);
141     dup2(q->stderr_fd, 2);
142     q->child_setup(q->user_data);
143 }
144 #endif
145
146 static inline gboolean
147 g_spawn_async_with_fds_slirp(const gchar *working_directory,
148                             gchar **argv,
149                             gchar **envp,
150                             GSpawnFlags flags,
151                             GSpawnChildSetupFunc child_setup,
152                             gpointer user_data,
153                             GPid *child_pid,
154                             gint stdin_fd,
155                             gint stdout_fd,
156                             gint stderr_fd,
157                             GError **error)
158 {
159 #if GLIB_CHECK_VERSION(2, 58, 0)
160     return g_spawn_async_with_fds(working_directory, argv, envp, flags,
161                                   child_setup, user_data,
162                                   child_pid, stdin_fd, stdout_fd, stderr_fd,
163                                   error);
164 #else
165     SlirpGSpawnFds setup = {
166         .child_setup = child_setup,
167         .user_data = user_data,
168         .stdin_fd = stdin_fd,
169         .stdout_fd = stdout_fd,
170         .stderr_fd = stderr_fd,
171     };
172
173     return g_spawn_async(working_directory, argv, envp, flags,
174                          slirp_gspawn_fds_setup, &setup,
175                          child_pid, error);
176 #endif
177 }
178
179 #define g_spawn_async_with_fds(wd, argv, env, f, c, d, p, ifd, ofd, efd, err) \
180     g_spawn_async_with_fds_slirp(wd, argv, env, f, c, d, p, ifd, ofd, efd, err)
181
182 #pragma GCC diagnostic pop
183
184 int
185 fork_exec(struct socket *so, const char *ex)
186 {
187     GError *err = NULL;
188     char **argv;
189     int opt, sp[2];
190
191     DEBUG_CALL("fork_exec");
192     DEBUG_ARG("so = %p", so);
193     DEBUG_ARG("ex = %p", ex);
194
195     if (slirp_socketpair_with_oob(sp) < 0) {
196         return 0;
197     }
198
199     argv = g_strsplit(ex, " ", -1);
200     g_spawn_async_with_fds(NULL /* cwd */,
201                            argv,
202                            NULL /* env */,
203                            G_SPAWN_SEARCH_PATH,
204                            fork_exec_child_setup, NULL /* data */,
205                            NULL /* child_pid */,
206                            sp[1], sp[1], sp[1],
207                            &err);
208     g_strfreev(argv);
209
210     if (err) {
211         g_critical("fork_exec: %s", err->message);
212         g_error_free(err);
213         closesocket(sp[0]);
214         closesocket(sp[1]);
215         return 0;
216     }
217
218     so->s = sp[0];
219     closesocket(sp[1]);
220     slirp_socket_set_fast_reuse(so->s);
221     opt = 1;
222     setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
223     slirp_set_nonblock(so->s);
224     so->slirp->cb->register_poll_fd(so->s, so->slirp->opaque);
225     return 1;
226 }
227
228 char *slirp_connection_info(Slirp *slirp)
229 {
230     GString *str = g_string_new(NULL);
231     const char * const tcpstates[] = {
232         [TCPS_CLOSED]       = "CLOSED",
233         [TCPS_LISTEN]       = "LISTEN",
234         [TCPS_SYN_SENT]     = "SYN_SENT",
235         [TCPS_SYN_RECEIVED] = "SYN_RCVD",
236         [TCPS_ESTABLISHED]  = "ESTABLISHED",
237         [TCPS_CLOSE_WAIT]   = "CLOSE_WAIT",
238         [TCPS_FIN_WAIT_1]   = "FIN_WAIT_1",
239         [TCPS_CLOSING]      = "CLOSING",
240         [TCPS_LAST_ACK]     = "LAST_ACK",
241         [TCPS_FIN_WAIT_2]   = "FIN_WAIT_2",
242         [TCPS_TIME_WAIT]    = "TIME_WAIT",
243     };
244     struct in_addr dst_addr;
245     struct sockaddr_in src;
246     socklen_t src_len;
247     uint16_t dst_port;
248     struct socket *so;
249     const char *state;
250     char buf[20];
251
252     g_string_append_printf(str,
253         "  Protocol[State]    FD  Source Address  Port   "
254         "Dest. Address  Port RecvQ SendQ\n");
255
256     /* TODO: IPv6 */
257
258     for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) {
259         if (so->so_state & SS_HOSTFWD) {
260             state = "HOST_FORWARD";
261         } else if (so->so_tcpcb) {
262             state = tcpstates[so->so_tcpcb->t_state];
263         } else {
264             state = "NONE";
265         }
266         if (so->so_state & (SS_HOSTFWD | SS_INCOMING)) {
267             src_len = sizeof(src);
268             getsockname(so->s, (struct sockaddr *)&src, &src_len);
269             dst_addr = so->so_laddr;
270             dst_port = so->so_lport;
271         } else {
272             src.sin_addr = so->so_laddr;
273             src.sin_port = so->so_lport;
274             dst_addr = so->so_faddr;
275             dst_port = so->so_fport;
276         }
277         snprintf(buf, sizeof(buf), "  TCP[%s]", state);
278         g_string_append_printf(str, "%-19s %3d %15s %5d ", buf, so->s,
279                        src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*",
280                        ntohs(src.sin_port));
281         g_string_append_printf(str, "%15s %5d %5d %5d\n",
282                        inet_ntoa(dst_addr), ntohs(dst_port),
283                        so->so_rcv.sb_cc, so->so_snd.sb_cc);
284     }
285
286     for (so = slirp->udb.so_next; so != &slirp->udb; so = so->so_next) {
287         if (so->so_state & SS_HOSTFWD) {
288             snprintf(buf, sizeof(buf), "  UDP[HOST_FORWARD]");
289             src_len = sizeof(src);
290             getsockname(so->s, (struct sockaddr *)&src, &src_len);
291             dst_addr = so->so_laddr;
292             dst_port = so->so_lport;
293         } else {
294             snprintf(buf, sizeof(buf), "  UDP[%d sec]",
295                          (so->so_expire - curtime) / 1000);
296             src.sin_addr = so->so_laddr;
297             src.sin_port = so->so_lport;
298             dst_addr = so->so_faddr;
299             dst_port = so->so_fport;
300         }
301         g_string_append_printf(str, "%-19s %3d %15s %5d ", buf, so->s,
302                        src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*",
303                        ntohs(src.sin_port));
304         g_string_append_printf(str, "%15s %5d %5d %5d\n",
305                        inet_ntoa(dst_addr), ntohs(dst_port),
306                        so->so_rcv.sb_cc, so->so_snd.sb_cc);
307     }
308
309     for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so->so_next) {
310         snprintf(buf, sizeof(buf), "  ICMP[%d sec]",
311                      (so->so_expire - curtime) / 1000);
312         src.sin_addr = so->so_laddr;
313         dst_addr = so->so_faddr;
314         g_string_append_printf(str, "%-19s %3d %15s  -    ", buf, so->s,
315                        src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*");
316         g_string_append_printf(str, "%15s  -    %5d %5d\n", inet_ntoa(dst_addr),
317                        so->so_rcv.sb_cc, so->so_snd.sb_cc);
318     }
319
320     return g_string_free(str, FALSE);
321 }
This page took 0.042066 seconds and 4 git commands to generate.