aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2012-07-22 22:01:56 +0000
committerChristian Grothoff <christian@grothoff.org>2012-07-22 22:01:56 +0000
commit929bfb08deeab0db8345f144d03e388891695995 (patch)
treed446f614926e6835f9023b0e605f5c1869bcdfa3
parent375ead169d33210a0e3088f410f93bdcece8c99d (diff)
downloadlibextractor-929bfb08deeab0db8345f144d03e388891695995.tar.gz
libextractor-929bfb08deeab0db8345f144d03e388891695995.zip
-stuff
-rw-r--r--src/main/extractor.c24
-rw-r--r--src/main/extractor_ipc.c38
-rw-r--r--src/main/extractor_ipc.h222
-rw-r--r--src/main/extractor_ipc_gnu.c21
-rw-r--r--src/main/extractor_plugin_main.c48
-rw-r--r--src/main/extractor_plugins.c18
-rw-r--r--src/main/extractor_plugins.h36
7 files changed, 281 insertions, 126 deletions
diff --git a/src/main/extractor.c b/src/main/extractor.c
index 210308c..e012753 100644
--- a/src/main/extractor.c
+++ b/src/main/extractor.c
@@ -44,30 +44,6 @@
44 44
45 45
46/** 46/**
47 * Client provided a memory buffer, analyze it. Creates a shm, copies
48 * buffer contents into it. Does not support seeking (all data comes
49 * in one [big] chunk.
50 */
51#define OPMODE_MEMORY 1
52
53/**
54 * Client provided a memory buffer or a file, which contains compressed data.
55 * Creates a shm of limited size and repeatedly fills it with uncompressed
56 * data. Never skips data (has to uncompress every byte, discards unwanted bytes),
57 * can't efficiently seek backwards. Uses MESSAGE_UPDATED_SHM and MESSAGE_SEEK.
58 */
59#define OPMODE_DECOMPRESS 2
60
61/**
62 * Client provided a filename. Creates a file-backed shm (on W32) or just
63 * communicates the file name to each plugin, and plugin opens its own file
64 * descriptor of the file (POSIX). Each plugin maps different parts of the
65 * file into its memory independently.
66 */
67#define OPMODE_FILE 3
68
69
70/**
71 * Writes 'size' bytes from 'buf' to 'fd', returns only when 47 * Writes 'size' bytes from 'buf' to 'fd', returns only when
72 * writing is not possible, or when all 'size' bytes were written 48 * writing is not possible, or when all 'size' bytes were written
73 * (never does partial writes). 49 * (never does partial writes).
diff --git a/src/main/extractor_ipc.c b/src/main/extractor_ipc.c
index eb21993..4c8a14d 100644
--- a/src/main/extractor_ipc.c
+++ b/src/main/extractor_ipc.c
@@ -46,8 +46,8 @@ EXTRACTOR_IPC_process_reply_ (struct EXTRACTOR_PluginList *plugin,
46{ 46{
47 const char *cdata = data; 47 const char *cdata = data;
48 unsigned char code; 48 unsigned char code;
49 int64_t seek_position; 49 struct SeekRequestMessage seek;
50 struct IpcHeader hdr; 50 struct MetaMessage meta;
51 const char *mime_type; 51 const char *mime_type;
52 const char *value; 52 const char *value;
53 53
@@ -60,49 +60,51 @@ EXTRACTOR_IPC_process_reply_ (struct EXTRACTOR_PluginList *plugin,
60 plugin->seek_request = -1; 60 plugin->seek_request = -1;
61 plugin->round_finished = 1; 61 plugin->round_finished = 1;
62 return 1; 62 return 1;
63 case MESSAGE_SEEK: /* Seek */ 63 case MESSAGE_SEEK: /* Seek */
64 if (size < 1 + sizeof (int64_t)) 64 if (size < sizeof (struct SeekRequestMessage))
65 { 65 {
66 plugin->seek_request = -1; 66 plugin->seek_request = -1;
67 return 0; 67 return 0;
68 } 68 }
69 memcpy (&seek_position, &cdata[1], sizeof (int64_t)); 69 memcpy (&seek, cdata, sizeof (seek));
70 plugin->seek_request = seek_position; 70 plugin->seek_request = seek.file_offset;
71 return 1 + sizeof (int64_t); 71 return sizeof (struct SeekRequestMessage);
72 case MESSAGE_META: /* Meta */ 72 case MESSAGE_META: /* Meta */
73 if (size < 1 + sizeof (hdr) ) 73 if (size < sizeof (struct MetaMessage))
74 { 74 {
75 plugin->seek_request = -1; 75 plugin->seek_request = -1;
76 return 0; 76 return 0;
77 } 77 }
78 memcpy (&hdr, &cdata[1], sizeof (hdr)); 78 memcpy (&meta, cdata, sizeof (meta));
79 /* check hdr for sanity */ 79 /* check hdr for sanity */
80 if (hdr.data_len > MAX_META_DATA) 80 if (meta.value_size > MAX_META_DATA)
81 return -1; /* not allowing more than MAX_META_DATA meta data */ 81 return -1; /* not allowing more than MAX_META_DATA meta data */
82 if (size < 1 + sizeof (hdr) + hdr.mime_len + hdr.data_len) 82 if (size < sizeof (meta) + meta.mime_length + meta.value_size)
83 { 83 {
84 plugin->seek_request = -1; 84 plugin->seek_request = -1;
85 return 0; 85 return 0;
86 } 86 }
87 if (0 == hdr.mime_len) 87 if (0 == meta.mime_length)
88 { 88 {
89 mime_type = NULL; 89 mime_type = NULL;
90 } 90 }
91 else 91 else
92 { 92 {
93 mime_type = &cdata[1 + sizeof (hdr)]; 93 mime_type = &cdata[sizeof (struct MetaMessage)];
94 if ('\0' != mime_type[hdr.mime_len-1]) 94 if ('\0' != mime_type[meta.mime_length - 1])
95 return -1; 95 return -1;
96 } 96 }
97 if (0 == hdr.data_len) 97 if (0 == meta.value_size)
98 value = NULL; 98 value = NULL;
99 else 99 else
100 value = &cdata[1 + sizeof (hdr) + hdr.mime_len]; 100 value = &cdata[sizeof (struct MetaMessage) + meta.mime_length];
101 proc (proc_cls, 101 proc (proc_cls,
102 plugin, 102 plugin,
103 &hdr, 103 (enum EXTRACTOR_MetaType) meta.meta_type,
104 (enum EXTRACTOR_MetaFormat) meta.meta_format,
105 meta.value_size,
104 mime_type, value); 106 mime_type, value);
105 return 1 + sizeof (hdr) + hdr.mime_len + hdr.data_len; 107 return sizeof (struct MetaMessage) + meta.mime_length + meta.value_size;
106 default: 108 default:
107 return -1; 109 return -1;
108 } 110 }
diff --git a/src/main/extractor_ipc.h b/src/main/extractor_ipc.h
index 2b1ea47..212d30d 100644
--- a/src/main/extractor_ipc.h
+++ b/src/main/extractor_ipc.h
@@ -41,20 +41,120 @@
41#define MAX_SHM_NAME 255 41#define MAX_SHM_NAME 255
42 42
43/** 43/**
44 * Sent from LE to a plugin to initialize it (open shm, 44 * Sent from LE to a plugin to initialize it (opens shm).
45 * reset position counters etc).
46 */ 45 */
47#define MESSAGE_INIT_STATE 0x01 46#define MESSAGE_INIT_STATE 0x00
47
48/**
49 * IPC message send to plugin to initialize SHM.
50 */
51struct InitMessage
52{
53 /**
54 * Set to MESSAGE_INIT_STATE.
55 */
56 unsigned char opcode;
57
58 /**
59 * Always zero.
60 */
61 unsigned char reserved;
62
63 /**
64 * Name of the shared-memory name.
65 */
66 uint32_t shm_name_length;
67
68 /**
69 * Maximum size of the shm map.
70 */
71 uint32_t shm_map_size;
72
73 /* followed by name of the SHM */
74};
75
76
77/**
78 * Sent from LE to a plugin to tell it extracting
79 * can now start. The SHM will point to offset 0
80 * of the file.
81 */
82#define MESSAGE_EXTRACT_START 0x01
83
84/**
85 * IPC message send to plugin to start extracting.
86 */
87struct StartMessage
88{
89 /**
90 * Set to MESSAGE_EXTRACT_START.
91 */
92 unsigned char opcode;
93
94 /**
95 * Always zero.
96 */
97 unsigned char reserved;
98
99 /**
100 * Always zero.
101 */
102 uint16_t reserved2;
103
104 /**
105 * Number of bytes ready in SHM.
106 */
107 uint32_t shm_ready_bytes;
108
109 /**
110 * Overall size of the file.
111 */
112 uint64_t file_size;
113
114};
48 115
49/** 116/**
50 * Sent from LE to a plugin to tell it that shm contents 117 * Sent from LE to a plugin to tell it that shm contents
51 * were updated. Only used for OPMODE_COMPRESS. 118 * were updated.
52 */ 119 */
53#define MESSAGE_UPDATED_SHM 0x02 120#define MESSAGE_UPDATED_SHM 0x02
54 121
55/** 122/**
123 * IPC message send to plugin to notify it about a change in the SHM.
124 */
125struct UpdateMessage
126{
127 /**
128 * Set to MESSAGE_UPDATED_SHM.
129 */
130 unsigned char opcode;
131
132 /**
133 * Always zero.
134 */
135 unsigned char reserved;
136
137 /**
138 * Always zero.
139 */
140 uint16_t reserved2;
141
142 /**
143 * Number of bytes ready in SHM.
144 */
145 uint32_t shm_ready_bytes;
146
147 /**
148 * Overall size of the file.
149 */
150 uint64_t file_size;
151
152};
153
154/**
56 * Sent from plugin to LE to tell LE that plugin is done 155 * Sent from plugin to LE to tell LE that plugin is done
57 * analyzing current file and will send no more data. 156 * analyzing current file and will send no more data.
157 * No message format as this is only one byte.
58 */ 158 */
59#define MESSAGE_DONE 0x03 159#define MESSAGE_DONE 0x03
60 160
@@ -65,58 +165,103 @@
65#define MESSAGE_SEEK 0x04 165#define MESSAGE_SEEK 0x04
66 166
67/** 167/**
68 * Sent from plugin to LE to tell LE about metadata discovered. 168 * IPC message send to plugin to start extracting.
69 */ 169 */
70#define MESSAGE_META 0x05 170struct SeekRequestMessage
171{
172 /**
173 * Set to MESSAGE_SEEK.
174 */
175 unsigned char opcode;
71 176
72/** 177 /**
73 * Sent from LE to plugin to make plugin discard its state (unmap 178 * Always zero.
74 * and close shm). 179 */
75 */ 180 unsigned char reserved;
76#define MESSAGE_DISCARD_STATE 0x06
77 181
182 /**
183 * Always zero.
184 */
185 uint16_t reserved2;
78 186
79/** 187 /**
80 * Definition of an IPC communication channel with 188 * Number of bytes requested for SHM.
81 * some plugin. 189 */
82 */ 190 uint32_t requested_bytes;
83struct EXTRACTOR_Channel; 191
192 /**
193 * Requested offset.
194 */
195 uint64_t file_offset;
196
197};
84 198
85/** 199/**
86 * Definition of a shared memory area. 200 * Sent from plugin to LE to tell LE about metadata discovered.
87 */ 201 */
88struct EXTRACTOR_SharedMemory; 202#define MESSAGE_META 0x05
89
90 203
91/** 204/**
92 * Header used for our IPC replies. A header 205 * Plugin to parent: metadata discovered
93 * with all fields being zero is used to indicate
94 * the end of the stream.
95 */ 206 */
96struct IpcHeader 207struct MetaMessage
97{ 208{
98 /** 209 /**
99 * Type of the meta data. 210 * Set to MESSAGE_META.
100 */ 211 */
101 enum EXTRACTOR_MetaType meta_type; 212 unsigned char opcode;
102 213
103 /** 214 /**
104 * Format of the meta data. 215 * Always zero.
105 */ 216 */
106 enum EXTRACTOR_MetaFormat meta_format; 217 unsigned char reserved;
107 218
108 /** 219 /**
109 * Number of bytes of meta data (value) 220 * An 'enum EXTRACTOR_MetaFormat' in 16 bits.
110 */ 221 */
111 size_t data_len; 222 uint16_t meta_format;
112 223
224 /**
225 * An 'enum EXTRACTOR_MetaType' in 16 bits.
226 */
227 uint16_t meta_type;
228
113 /** 229 /**
114 * Length of the mime type string describing the meta data value's mime type, 230 * Length of the mime type string.
115 * including 0-terminator, 0 for mime type of "NULL".
116 */ 231 */
117 size_t mime_len; 232 uint16_t mime_length;
233
234 /**
235 * Size of the value.
236 */
237 uint32_t value_size;
238
239 /* followed by mime_length bytes of 0-terminated
240 mime-type (unless mime_length is 0) */
241
242 /* followed by value_size bytes of value */
243
118}; 244};
119 245
246/**
247 * Sent from LE to plugin to make plugin discard its state
248 * (extraction aborted by application). Only one byte.
249 * Plugin should get ready for next 'StartMessage' after this.
250 */
251#define MESSAGE_DISCARD_STATE 0x06
252
253
254/**
255 * Definition of an IPC communication channel with
256 * some plugin.
257 */
258struct EXTRACTOR_Channel;
259
260/**
261 * Definition of a shared memory area.
262 */
263struct EXTRACTOR_SharedMemory;
264
120 265
121/** 266/**
122 * Create a shared memory area. 267 * Create a shared memory area.
@@ -196,17 +341,22 @@ EXTRACTOR_IPC_channel_send_ (struct EXTRACTOR_Channel *channel,
196 * Handler for a message from one of the plugins. 341 * Handler for a message from one of the plugins.
197 * 342 *
198 * @param cls closure 343 * @param cls closure
199 * @param short_libname library name of the channel sending the message 344 * @param plugin plugin of the channel sending the message
200 * @param msg header of the message from the plugin 345 * @param meta_type type of the meta data
346 * @param meta_format format of the meta data
347 * @param value_len number of bytes in 'value'
201 * @param value 'data' send from the plugin 348 * @param value 'data' send from the plugin
202 * @param mime mime string send from the plugin 349 * @param mime mime string send from the plugin
203 */ 350 */
204typedef void (*EXTRACTOR_ChannelMessageProcessor) (void *cls, 351typedef void (*EXTRACTOR_ChannelMessageProcessor) (void *cls,
205 struct EXTRACTOR_PluginList *plugin, 352 struct EXTRACTOR_PluginList *plugin,
206 const struct IpcHeader *msg, 353 enum EXTRACTOR_MetaType meta_type,
354 enum EXTRACTOR_MetaFormat meta_format,
355 size_t value_len,
207 const void *value, 356 const void *value,
208 const char *mime); 357 const char *mime);
209 358
359
210/** 360/**
211 * Process a reply from channel (seek request, metadata and done message) 361 * Process a reply from channel (seek request, metadata and done message)
212 * 362 *
diff --git a/src/main/extractor_ipc_gnu.c b/src/main/extractor_ipc_gnu.c
index 0c255fd..b56cc40 100644
--- a/src/main/extractor_ipc_gnu.c
+++ b/src/main/extractor_ipc_gnu.c
@@ -225,6 +225,8 @@ EXTRACTOR_IPC_channel_create_ (struct EXTRACTOR_PluginList *plugin,
225 int p1[2]; 225 int p1[2];
226 int p2[2]; 226 int p2[2];
227 pid_t pid; 227 pid_t pid;
228 struct InitMessage *init;
229 size_t slen;
228 230
229 if (NULL == (channel = malloc (sizeof (struct EXTRACTOR_Channel)))) 231 if (NULL == (channel = malloc (sizeof (struct EXTRACTOR_Channel))))
230 return NULL; 232 return NULL;
@@ -264,6 +266,25 @@ EXTRACTOR_IPC_channel_create_ (struct EXTRACTOR_PluginList *plugin,
264 channel->cpipe_in = p1[1]; 266 channel->cpipe_in = p1[1];
265 channel->cpipe_out = p2[0]; 267 channel->cpipe_out = p2[0];
266 channel->cpid = pid; 268 channel->cpid = pid;
269 slen = strlen (shm->shm_name) + 1;
270 if (NULL == (init = malloc (sizeof (struct InitMessage) + slen)))
271 {
272 EXTRACTOR_IPC_channel_destroy_ (channel);
273 return NULL;
274 }
275 init->opcode = MESSAGE_INIT_STATE;
276 init->reserved = 0;
277 init->shm_name_length = slen;
278 init->shm_map_size = shm->shm_size;
279 memcpy (&init[1], shm->shm_name, slen);
280 if (sizeof (init) !=
281 EXTRACTOR_IPC_channel_send_ (channel,
282 init,
283 sizeof (init) + slen) )
284 {
285 EXTRACTOR_IPC_channel_destroy_ (channel);
286 return NULL;
287 }
267 return channel; 288 return channel;
268} 289}
269 290
diff --git a/src/main/extractor_plugin_main.c b/src/main/extractor_plugin_main.c
index 03269fb..9cf7624 100644
--- a/src/main/extractor_plugin_main.c
+++ b/src/main/extractor_plugin_main.c
@@ -27,6 +27,7 @@
27#include "plibc.h" 27#include "plibc.h"
28#include "extractor.h" 28#include "extractor.h"
29#include "extractor_datasource.h" 29#include "extractor_datasource.h"
30#include "extractor_ipc.h"
30#include "extractor_plugin_main.h" 31#include "extractor_plugin_main.h"
31#include <dirent.h> 32#include <dirent.h>
32#include <sys/types.h> 33#include <sys/types.h>
@@ -493,6 +494,36 @@ process_requests (struct EXTRACTOR_PluginList *plugin,
493} 494}
494 495
495 496
497#ifndef WINDOWS
498/**
499 * Open '/dev/null' and make the result the given
500 * file descriptor.
501 *
502 * @param target_fd desired FD to point to /dev/null
503 * @param flags open flags (O_RDONLY, O_WRONLY)
504 */
505static void
506open_dev_null (int target_fd,
507 int flags)
508{
509 int fd;
510
511 fd = open ("/dev/null", flags);
512 if (-1 == fd)
513 return; /* good luck */
514 if (fd == target_fd)
515 return; /* already done */
516 if (-1 == dup2 (fd, target_fd))
517 {
518 (void) close (fd);
519 return; /* good luck */
520 }
521 /* close original result from 'open' */
522 (void) close (fd);
523}
524#endif
525
526
496/** 527/**
497 * 'main' function of the child process. Loads the plugin, 528 * 'main' function of the child process. Loads the plugin,
498 * sets up its in and out pipes, then runs the request serving function. 529 * sets up its in and out pipes, then runs the request serving function.
@@ -508,16 +539,27 @@ EXTRACTOR_plugin_main_ (struct EXTRACTOR_PluginList *plugin,
508 if (0 != EXTRACTOR_plugin_load_ (plugin)) 539 if (0 != EXTRACTOR_plugin_load_ (plugin))
509 { 540 {
510#if DEBUG 541#if DEBUG
511 fprintf (stderr, "Plugin `%s' failed to load!\n", plugin->short_libname); 542 fprintf (stderr, "Plugin `%s' failed to load!\n",
543 plugin->short_libname);
512#endif 544#endif
513 return; 545 return;
514 } 546 }
515 if ( (NULL != plugin->specials) && 547 if ( (NULL != plugin->specials) &&
516 (NULL != strstr (plugin->specials, "close-stderr"))) 548 (NULL != strstr (plugin->specials, "close-stderr")))
517 close (2); 549 {
550 (void) close (2);
551#ifndef WINDOWS
552 open_dev_null (2, O_WRONLY);
553#endif
554 }
518 if ( (NULL != plugin->specials) && 555 if ( (NULL != plugin->specials) &&
519 (NULL != strstr (plugin->specials, "close-stdout"))) 556 (NULL != strstr (plugin->specials, "close-stdout")))
520 close (1); 557 {
558 (void) close (1);
559#ifndef WINDOWS
560 open_dev_null (1, O_WRONLY);
561#endif
562 }
521 process_requests (plugin, in, out); 563 process_requests (plugin, in, out);
522} 564}
523 565
diff --git a/src/main/extractor_plugins.c b/src/main/extractor_plugins.c
index edefc47..9a16a33 100644
--- a/src/main/extractor_plugins.c
+++ b/src/main/extractor_plugins.c
@@ -89,7 +89,7 @@ get_symbol_with_prefix (void *lib_handle,
89 lt_dlerror()); 89 lt_dlerror());
90 } 90 }
91 if (NULL != first_error) 91 if (NULL != first_error)
92 free(first_error); 92 free (first_error);
93#endif 93#endif
94 } 94 }
95 95
@@ -158,11 +158,11 @@ EXTRACTOR_plugin_load_ (struct EXTRACTOR_PluginList *plugin)
158 "Loading `%s' plugin failed: %s\n", 158 "Loading `%s' plugin failed: %s\n",
159 plugin->short_libname, 159 plugin->short_libname,
160 "can't convert plugin name to local encoding"); 160 "can't convert plugin name to local encoding");
161#endif
161 free (plugin->libname); 162 free (plugin->libname);
162 plugin->libname = NULL; 163 plugin->libname = NULL;
163 plugin->flags = EXTRACTOR_OPTION_DISABLED; 164 plugin->flags = EXTRACTOR_OPTION_DISABLED;
164 return -1; 165 return -1;
165#endif
166 } 166 }
167 plugin->libraryHandle = lt_dlopenadvise (llibname, 167 plugin->libraryHandle = lt_dlopenadvise (llibname,
168 advise); 168 advise);
@@ -249,20 +249,6 @@ EXTRACTOR_plugin_add (struct EXTRACTOR_PluginList *prev,
249 result->plugin_options = strdup (options); 249 result->plugin_options = strdup (options);
250 else 250 else
251 result->plugin_options = NULL; 251 result->plugin_options = NULL;
252 /* This is kinda weird, but it allows us to not to call GetSystemInfo()
253 * or sysconf() every time we need allocation granularity - just once
254 * for each plugin.
255 * The only alternative is to keep it in a global variable...
256 */
257#if WINDOWS
258 {
259 SYSTEM_INFO si;
260 GetSystemInfo (&si);
261 result->allocation_granularity = si.dwAllocationGranularity;
262 }
263#else
264 result->allocation_granularity = sysconf (_SC_PAGE_SIZE);
265#endif
266 return result; 252 return result;
267} 253}
268 254
diff --git a/src/main/extractor_plugins.h b/src/main/extractor_plugins.h
index 2fd57d7..0903f55 100644
--- a/src/main/extractor_plugins.h
+++ b/src/main/extractor_plugins.h
@@ -34,8 +34,8 @@
34 34
35/** 35/**
36 * Linked list of extractor plugins. An application builds this list 36 * Linked list of extractor plugins. An application builds this list
37 * by telling libextractor to load various keyword-extraction 37 * by telling libextractor to load various meta data extraction
38 * plugins. Libraries can also be unloaded (removed from this list, 38 * plugins. Plugins can also be unloaded (removed from this list,
39 * see EXTRACTOR_plugin_remove). 39 * see EXTRACTOR_plugin_remove).
40 */ 40 */
41struct EXTRACTOR_PluginList 41struct EXTRACTOR_PluginList
@@ -83,44 +83,22 @@ struct EXTRACTOR_PluginList
83 struct EXTRACTOR_Channel *channel; 83 struct EXTRACTOR_Channel *channel;
84 84
85 /** 85 /**
86 * Flags to control how the plugin is executed. 86 * A position this plugin wants us to seek to. -1 if it's finished.
87 */ 87 * Starts at 0.
88 enum EXTRACTOR_Options flags;
89
90#if WINDOWS
91 /**
92 * Page size. Mmap offset is a multiple of this number.
93 */
94 DWORD allocation_granularity;
95#else
96 /**
97 * Page size. Mmap offset is a multiple of this number.
98 */ 88 */
99 long allocation_granularity; 89 int64_t seek_request;
100#endif
101 90
102 /** 91 /**
103 * A position this plugin wants us to seek to. -1 if it's finished. 92 * Flags to control how the plugin is executed.
104 * Starts at 0;
105 */ 93 */
106 int64_t seek_request; 94 enum EXTRACTOR_Options flags;
107 95
108 /** 96 /**
109 * Is this plugin finished extracting for this round? 97 * Is this plugin finished extracting for this round?
110 * 0: no, 1: yes 98 * 0: no, 1: yes
111 */ 99 */
112 int round_finished; 100 int round_finished;
113
114 /**
115 * Mode of operation. One of the OPMODE_* constants
116 */
117 uint8_t operation_mode;
118 101
119 /**
120 * 1 if plugin is currently in a recursive process_requests() call,
121 * 0 otherwise
122 */
123 int waiting_for_update;
124}; 102};
125 103
126 104