nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /* extcap_spawn.c
2 *
3 * Routines to spawn extcap external capture programs
4 * Copyright 2016, Roland Knall <rknall@gmail.com>
5 *
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 */
24  
25 #include <config.h>
26  
27 #include <stdio.h>
28 #include <glib.h>
29 #include <string.h>
30  
31 #include <wsutil/file_util.h>
32 #include <wsutil/filesystem.h>
33 #ifdef _WIN32
34 #include <wsutil/win32-utils.h>
35 #endif
36  
37 #include <log.h>
38  
39 #include "extcap.h"
40 #include "extcap_spawn.h"
41  
42 #ifdef _WIN32
43  
44 void win32_readfrompipe(HANDLE read_pipe, gint32 max_buffer, gchar * buffer)
45 {
46 gboolean bSuccess = FALSE;
47 gint32 bytes_written = 0;
48 gint32 max_bytes = 0;
49  
50 DWORD dwRead;
51 DWORD bytes_avail = 0;
52  
53 for (;;)
54 {
55 if (!PeekNamedPipe(read_pipe, NULL, 0, NULL, &bytes_avail, NULL)) break;
56 if (bytes_avail <= 0) break;
57  
58 max_bytes = max_buffer - bytes_written - 1;
59  
60 bSuccess = ReadFile(read_pipe, &buffer[bytes_written], max_bytes, &dwRead, NULL);
61 if (!bSuccess || dwRead == 0) break;
62  
63 bytes_written += dwRead;
64 if ((bytes_written + 1) >= max_buffer) break;
65 }
66  
67 buffer[bytes_written] = '\0';
68 }
69 #endif
70  
71 gboolean extcap_spawn_sync ( gchar * dirname, gchar * command, gint argc, gchar ** args, gchar ** command_output )
72 {
73 gboolean status = FALSE;
74 gboolean result = FALSE;
75 gchar ** argv = NULL;
76 gint cnt = 0;
77 gchar * local_output = NULL;
78 #ifdef _WIN32
79  
80 #define BUFFER_SIZE 4096
81 gchar buffer[BUFFER_SIZE];
82  
83 GString *winargs = g_string_sized_new(200);
84 gchar *quoted_arg;
85 gunichar2 *wcommandline;
86  
87 STARTUPINFO info;
88 PROCESS_INFORMATION processInfo;
89  
90 SECURITY_ATTRIBUTES sa;
91 HANDLE child_stdout_rd = NULL;
92 HANDLE child_stdout_wr = NULL;
93 HANDLE child_stderr_rd = NULL;
94 HANDLE child_stderr_wr = NULL;
95  
96 const gchar * oldpath = g_getenv("PATH");
97 gchar * newpath = NULL;
98 #else
99 gint exit_status = 0;
100 #endif
101  
102 argv = (gchar **) g_malloc0(sizeof(gchar *) * (argc + 2));
103  
104 #ifdef _WIN32
105 newpath = g_strdup_printf("%s;%s", g_strescape(get_progfile_dir(), NULL), oldpath);
106 g_setenv("PATH", newpath, TRUE);
107  
108 argv[0] = g_strescape(command, NULL);
109 #else
110 argv[0] = g_strdup(command);
111 #endif
112  
113 for ( cnt = 0; cnt < argc; cnt++ )
114 argv[cnt+1] = args[cnt];
115 argv[argc+1] = NULL;
116  
117 #ifdef _WIN32
118  
119 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
120 sa.bInheritHandle = TRUE;
121 sa.lpSecurityDescriptor = NULL;
122  
123 if (!CreatePipe(&child_stdout_rd, &child_stdout_wr, &sa, 0))
124 {
125 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create stdout handle");
126 return FALSE;
127 }
128  
129 if (!CreatePipe(&child_stderr_rd, &child_stderr_wr, &sa, 0))
130 {
131 CloseHandle(child_stdout_rd);
132 CloseHandle(child_stdout_wr);
133 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create stderr handle");
134 return FALSE;
135 }
136  
137 /* convert args array into a single string */
138 /* XXX - could change sync_pipe_add_arg() instead */
139 /* there is a drawback here: the length is internally limited to 1024 bytes */
140 for (cnt = 0; argv[cnt] != 0; cnt++) {
141 if (cnt != 0) g_string_append_c(winargs, ' '); /* don't prepend a space before the path!!! */
142 quoted_arg = protect_arg(argv[cnt]);
143 g_string_append(winargs, quoted_arg);
144 g_free(quoted_arg);
145 }
146  
147 wcommandline = g_utf8_to_utf16(winargs->str, (glong)winargs->len, NULL, NULL, NULL);
148  
149 memset(&processInfo, 0, sizeof(PROCESS_INFORMATION));
150 memset(&info, 0, sizeof(STARTUPINFO));
151  
152 info.cb = sizeof(STARTUPINFO);
153 info.hStdError = child_stderr_wr;
154 info.hStdOutput = child_stdout_wr;
155 info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
156 info.wShowWindow = SW_HIDE;
157  
158 if (CreateProcess(NULL, wcommandline, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &info, &processInfo))
159 {
160 WaitForSingleObject(processInfo.hProcess, INFINITE);
161 win32_readfrompipe(child_stdout_rd, BUFFER_SIZE, buffer);
162 local_output = g_strdup_printf("%s", buffer);
163  
164 CloseHandle(child_stdout_rd);
165 CloseHandle(child_stdout_wr);
166 CloseHandle(child_stderr_rd);
167 CloseHandle(child_stderr_wr);
168  
169 CloseHandle(processInfo.hProcess);
170 CloseHandle(processInfo.hThread);
171 status = TRUE;
172 }
173 else
174 status = FALSE;
175  
176 g_setenv("PATH", oldpath, TRUE);
177 #else
178  
179 status = g_spawn_sync(dirname, argv, NULL,
180 (GSpawnFlags) 0, NULL, NULL, &local_output, NULL, &exit_status, NULL);
181  
182 if (status && exit_status != 0)
183 status = FALSE;
184 #endif
185  
186 if (status)
187 {
188 if ( command_output != NULL && local_output != NULL )
189 *command_output = g_strdup(local_output);
190  
191 result = TRUE;
192 }
193  
194 g_free(local_output);
195 g_free(argv);
196  
197 return result;
198 }
199  
200 GPid extcap_spawn_async(extcap_userdata * userdata, GPtrArray * args)
201 {
202 GPid pid = INVALID_EXTCAP_PID;
203  
204 #ifdef _WIN32
205 gint cnt = 0;
206 gchar ** tmp = NULL;
207  
208 GString *winargs = g_string_sized_new(200);
209 gchar *quoted_arg;
210 gunichar2 *wcommandline;
211  
212 STARTUPINFO info;
213 PROCESS_INFORMATION processInfo;
214  
215 SECURITY_ATTRIBUTES sa;
216 HANDLE child_stdout_rd = NULL;
217 HANDLE child_stdout_wr = NULL;
218 HANDLE child_stderr_rd = NULL;
219 HANDLE child_stderr_wr = NULL;
220  
221 const gchar * oldpath = g_getenv("PATH");
222 gchar * newpath = NULL;
223  
224 newpath = g_strdup_printf("%s;%s", g_strescape(get_progfile_dir(), NULL), oldpath);
225 g_setenv("PATH", newpath, TRUE);
226  
227 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
228 sa.bInheritHandle = TRUE;
229 sa.lpSecurityDescriptor = NULL;
230  
231 if (!CreatePipe(&child_stdout_rd, &child_stdout_wr, &sa, 0))
232 {
233 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create stdout handle");
234 return FALSE;
235 }
236  
237 if (!CreatePipe(&child_stderr_rd, &child_stderr_wr, &sa, 0))
238 {
239 CloseHandle(child_stdout_rd);
240 CloseHandle(child_stdout_wr);
241 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create stderr handle");
242 return FALSE;
243 }
244  
245 /* convert args array into a single string */
246 /* XXX - could change sync_pipe_add_arg() instead */
247 /* there is a drawback here: the length is internally limited to 1024 bytes */
248 for (tmp = (gchar **)args->pdata, cnt = 0; *tmp && **tmp; ++cnt, ++tmp) {
249 if (cnt != 0) g_string_append_c(winargs, ' '); /* don't prepend a space before the path!!! */
250 quoted_arg = protect_arg(*tmp);
251 g_string_append(winargs, quoted_arg);
252 g_free(quoted_arg);
253 }
254  
255 wcommandline = g_utf8_to_utf16(winargs->str, (glong)winargs->len, NULL, NULL, NULL);
256  
257 memset(&processInfo, 0, sizeof(PROCESS_INFORMATION));
258 memset(&info, 0, sizeof(STARTUPINFO));
259  
260 info.cb = sizeof(STARTUPINFO);
261 info.hStdError = child_stderr_wr;
262 info.hStdOutput = child_stdout_wr;
263 info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
264 info.wShowWindow = SW_HIDE;
265  
266 if (CreateProcess(NULL, wcommandline, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &info, &processInfo))
267 {
268 userdata->extcap_stderr_rd = _open_osfhandle((intptr_t)(child_stderr_rd), _O_BINARY);
269 userdata->extcap_stdout_rd = _open_osfhandle((intptr_t)(child_stdout_rd), _O_BINARY);
270 userdata->threadId = processInfo.hThread;
271 pid = processInfo.hProcess;
272 }
273  
274 g_setenv("PATH", oldpath, TRUE);
275 #else
276 g_spawn_async_with_pipes(NULL, (gchar **)args->pdata, NULL,
277 (GSpawnFlags) G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL,
278 &pid, NULL, &userdata->extcap_stdout_rd, &userdata->extcap_stderr_rd, NULL);
279 #endif
280  
281 userdata->pid = pid;
282  
283 return pid;
284 }
285  
286 #ifdef _WIN32
287 gboolean
288 extcap_wait_for_pipe(HANDLE pipe_h, HANDLE pid)
289 {
290 DWORD dw;
291 HANDLE handles[2];
292 OVERLAPPED ov;
293 ov.Pointer = 0;
294 gboolean success = FALSE;
295 ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
296  
297 ConnectNamedPipe(pipe_h, &ov);
298 handles[0] = ov.hEvent;
299 handles[1] = pid;
300  
301 if (GetLastError() == ERROR_PIPE_CONNECTED)
302 {
303 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "extcap connected to pipe");
304 }
305 else
306 {
307 dw = WaitForMultipleObjects(2, handles, FALSE, 30000);
308 if (dw == WAIT_OBJECT_0)
309 {
310 /* ConnectNamedPipe finished. */
311 DWORD code;
312  
313 code = GetLastError();
314 if (code == ERROR_IO_PENDING)
315 {
316 DWORD dummy;
317 if (!GetOverlappedResult(ov.hEvent, &ov, &dummy, TRUE))
318 {
319 code = GetLastError();
320 }
321 else
322 {
323 code = ERROR_SUCCESS;
324 success = TRUE;
325 }
326 }
327  
328 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "ConnectNamedPipe code: %d", code);
329 }
330 else if (dw == (WAIT_OBJECT_0 + 1))
331 {
332 /* extcap process terminated. */
333 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "extcap terminated without connecting to pipe!");
334 }
335 else if (dw == WAIT_TIMEOUT)
336 {
337 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "extcap didn't connect to pipe within 30 seconds!");
338 }
339 else
340 {
341 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "WaitForMultipleObjects returned 0x%08X. Error %d", dw, GetLastError());
342 }
343 }
344  
345 CloseHandle(ov.hEvent);
346  
347 return success;
348 }
349 #endif
350  
351 /*
352 * Editor modelines - http://www.wireshark.org/tools/modelines.html
353 *
354 * Local variables:
355 * c-basic-offset: 4
356 * tab-width: 8
357 * indent-tabs-mode: nil
358 * End:
359 *
360 * vi: set shiftwidth=4 tabstop=8 expandtab:
361 * :indentSize=4:tabSize=8:noTabs=true:
362 */