source: trunk/icedtea-web/plugin/icedteanp/IcedTeaPluginUtils.h@ 429

Last change on this file since 429 was 429, checked in by dmik, 11 years ago

icedtea-web: Merge version 1.5.1 from vendor to trunk.

File size: 19.0 KB
Line 
1/* IcedTeaPluginUtils.h
2
3 Copyright (C) 2009, 2010 Red Hat
4
5This file is part of IcedTea.
6
7IcedTea is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12IcedTea is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with IcedTea; see the file COPYING. If not, write to the
19Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
2002110-1301 USA.
21
22Linking this library statically or dynamically with other modules is
23making a combined work based on this library. Thus, the terms and
24conditions of the GNU General Public License cover the whole
25combination.
26
27As a special exception, the copyright holders of this library give you
28permission to link this library with independent modules to produce an
29executable, regardless of the license terms of these independent
30modules, and to copy and distribute the resulting executable under
31terms of your choice, provided that you also meet, for each linked
32independent module, the terms and conditions of the license of that
33module. An independent module is a module which is not derived from
34or based on this library. If you modify this library, you may extend
35this exception to your version of the library, but you are not
36obligated to do so. If you do not wish to do so, delete this
37exception statement from your version. */
38
39/**
40 * Utility classes for the IcedTeaPlugin
41 */
42
43#ifndef __ICEDTEAPLUGINUTILS_H__
44#define __ICEDTEAPLUGINUTILS_H__
45
46#include <pthread.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include <time.h>
50#include <syslog.h>
51#include <sys/time.h>
52
53#include <fcntl.h>
54#include <cstring>
55#include <iostream>
56#include <list>
57#include <map>
58#include <queue>
59#include <sstream>
60#include <string>
61#include <vector>
62#include <queue>
63
64#include <npapi.h>
65#include <glib.h>
66#include <npruntime.h>
67
68#include "IcedTeaParseProperties.h"
69
70void *flush_pre_init_messages(void* data);
71void push_pre_init_messages(char * ldm);
72void reset_pre_init_messages();
73
74// debugging macro.
75#define initialize_debug() \
76 do \
77 { \
78 if (!debug_initiated) { \
79 debug_initiated = true; \
80 plugin_debug = getenv ("ICEDTEAPLUGIN_DEBUG") != NULL || is_debug_on(); \
81 plugin_debug_headers = is_debug_header_on(); \
82 plugin_debug_to_file = is_logging_to_file(); \
83 plugin_debug_to_streams = is_logging_to_stds(); \
84 plugin_debug_to_system = is_logging_to_system(); \
85 plugin_debug_to_console = is_java_console_enabled(); \
86 if (plugin_debug_to_file) { \
87 IcedTeaPluginUtilities::initFileLog(); \
88 } \
89 if (plugin_debug_to_console) { \
90 /*initialisation done during jvm startup*/ \
91 } \
92 IcedTeaPluginUtilities::printDebugStatus(); \
93 } \
94 } while (0)
95
96
97#define HEADER_SIZE 500
98#define BODY_SIZE 500
99#define MESSAGE_SIZE HEADER_SIZE + BODY_SIZE
100#define LDEBUG_MESSAGE_SIZE MESSAGE_SIZE+50
101
102//header is destination char array
103#define CREATE_HEADER(ldebug_header) \
104 do \
105 { \
106 char times[100]; \
107 time_t t = time(NULL); \
108 struct tm p; \
109 localtime_r(&t, &p); \
110 strftime(times, 100, "%a %b %d %H:%M:%S %Z %Y", &p);\
111 const char *userNameforDebug = (getenv("USERNAME") == NULL) ? "unknown user" : getenv("USERNAME"); \
112 /*this message is parsed in JavaConsole*/ \
113 snprintf(ldebug_header, HEADER_SIZE, "[%s][ITW-C-PLUGIN][MESSAGE_DEBUG][%s][%s:%d] ITNPP Thread# %ld, gthread %p: ", \
114 userNameforDebug, times, __FILE__, __LINE__, pthread_self(), g_thread_self ()); \
115 } while (0)
116
117
118#define PLUGIN_DEBUG(...) \
119 do \
120 { \
121 initialize_debug(); \
122 if (plugin_debug) { \
123 char ldebug_header[HEADER_SIZE]; \
124 char ldebug_body[BODY_SIZE]; \
125 char ldebug_message[MESSAGE_SIZE];\
126 if (plugin_debug_headers) { \
127 CREATE_HEADER(ldebug_header); \
128 } else { \
129 sprintf(ldebug_header,""); \
130 } \
131 snprintf(ldebug_body, BODY_SIZE, __VA_ARGS__); \
132 if (plugin_debug_to_streams) { \
133 snprintf(ldebug_message, MESSAGE_SIZE, "%s%s", ldebug_header, ldebug_body); \
134 fprintf (stdout, "%s", ldebug_message);\
135 } \
136 if (plugin_debug_to_file) { \
137 snprintf(ldebug_message, MESSAGE_SIZE, "%s%s", ldebug_header, ldebug_body); \
138 fprintf (plugin_file_log, "%s", ldebug_message); \
139 fflush(plugin_file_log); \
140 } \
141 if (plugin_debug_to_console) { \
142 /*headers are always going to console*/ \
143 if (!plugin_debug_headers){ \
144 CREATE_HEADER(ldebug_header); \
145 } \
146 snprintf(ldebug_message, MESSAGE_SIZE, "%s%s", ldebug_header, ldebug_body); \
147 char ldebug_channel_message[LDEBUG_MESSAGE_SIZE]; \
148 struct timeval current_time; \
149 gettimeofday (&current_time, NULL);\
150 if (jvm_up) { \
151 snprintf(ldebug_channel_message, LDEBUG_MESSAGE_SIZE, "%s %ld %s", "plugindebug", current_time.tv_sec*1000000L+current_time.tv_usec, ldebug_message); \
152 push_pre_init_messages(ldebug_channel_message); \
153 } else { \
154 snprintf(ldebug_channel_message, LDEBUG_MESSAGE_SIZE, "%s %ld %s", "preinit_plugindebug", current_time.tv_sec*1000000L+current_time.tv_usec, ldebug_message); \
155 push_pre_init_messages(ldebug_channel_message); \
156 } \
157 } \
158 if (plugin_debug_to_system){ \
159 /*no debug messages to systemlog*/\
160 } \
161 } \
162 } while (0)
163
164
165#define PLUGIN_ERROR(...) \
166 do \
167 { \
168 initialize_debug(); \
169 char ldebug_header[HEADER_SIZE]; \
170 char ldebug_body[BODY_SIZE]; \
171 char ldebug_message[MESSAGE_SIZE]; \
172 if (plugin_debug_headers) { \
173 CREATE_HEADER(ldebug_header); \
174 } else { \
175 sprintf(ldebug_header,""); \
176 } \
177 snprintf(ldebug_body, BODY_SIZE, __VA_ARGS__); \
178 if (plugin_debug_to_streams) { \
179 snprintf(ldebug_message, MESSAGE_SIZE, "%s%s", ldebug_header, ldebug_body); \
180 fprintf (stderr, "%s", ldebug_message); \
181 } \
182 if (plugin_debug_to_file) { \
183 snprintf(ldebug_message, MESSAGE_SIZE, "%s%s", ldebug_header, ldebug_body); \
184 fprintf (plugin_file_log, "%s", ldebug_message); \
185 fflush(plugin_file_log); \
186 } \
187 if (plugin_debug_to_console) { \
188 /*headers are always going to console*/ \
189 if (!plugin_debug_headers){ \
190 CREATE_HEADER(ldebug_header); \
191 } \
192 snprintf(ldebug_message, MESSAGE_SIZE, "%s%s", ldebug_header, ldebug_body); \
193 char ldebug_channel_message[LDEBUG_MESSAGE_SIZE]; \
194 struct timeval current_time; \
195 gettimeofday (&current_time, NULL);\
196 if (jvm_up) { \
197 snprintf(ldebug_channel_message, LDEBUG_MESSAGE_SIZE, "%s %ld %s", "pluginerror", current_time.tv_sec*1000000L+current_time.tv_usec, ldebug_message); \
198 push_pre_init_messages(ldebug_channel_message); \
199 } else { \
200 snprintf(ldebug_channel_message, LDEBUG_MESSAGE_SIZE, "%s %ld %s", "preinit_pluginerror", current_time.tv_sec*1000000L+current_time.tv_usec, ldebug_message); \
201 push_pre_init_messages(ldebug_channel_message); \
202 } \
203 } \
204 if (plugin_debug_to_system){ \
205 /*java can not have prefix*/ \
206 openlog("", LOG_NDELAY, LOG_USER);\
207 syslog(LOG_ERR, "%s", "IcedTea-Web c-plugin - for more info see itweb-settings debug options or console. See http://icedtea.classpath.org/wiki/IcedTea-Web#Filing_bugs for help.");\
208 syslog(LOG_ERR, "%s", "IcedTea-Web c-plugin error manual log:");\
209 /*no headers to syslog*/ \
210 syslog(LOG_ERR, "%s", ldebug_body); \
211 closelog(); \
212 } \
213 } while (0)
214
215
216#define CHECK_JAVA_RESULT(result_data) \
217{ \
218 if (((JavaResultData*) result_data)->error_occurred) \
219 { \
220 PLUGIN_ERROR("Error: Error occurred on Java side: %s.\n", \
221 ((JavaResultData*) result_data)->error_msg->c_str()); \
222 return; \
223 } \
224}
225
226#define HEX_TO_INT(c) \
227 ((*c >= 'a') ? *c - 'a' + 10 : \
228 (*c >= 'A') ? *c - 'A' + 10 : \
229 *c - '0')
230
231#define IS_VALID_HEX(c) \
232 ((*c >= '0' && *c <= '9') || \
233 (*c >= 'a' && *c <= 'f') || \
234 (*c >= 'A' && *c <= 'F'))
235
236//long long max ~ 19 chars + terminator
237//leave some room for converting strings like "<var> = %d"
238const size_t NUM_STR_BUFFER_SIZE = 32;
239
240/*
241 * This struct holds data specific to a Java operation requested by the plugin
242 */
243typedef struct java_result_data
244{
245
246 // Return identifier (if applicable)
247 int return_identifier;
248
249 // Return string (if applicable)
250 std::string* return_string;
251
252 // Return wide/mb string (if applicable)
253 std::wstring* return_wstring;
254
255 // Error message (if an error occurred)
256 std::string* error_msg;
257
258 // Boolean indicating if an error occurred
259 bool error_occurred;
260
261} JavaResultData;
262
263/**
264 * This struct holds data to do calls that need to be run in the plugin thread
265 */
266typedef struct plugin_thread_call
267{
268 // The plugin instance
269 NPP instance;
270
271 // The function to call
272 void (*func) (void *);
273
274 // The data to pass to the function
275 void *userData;
276
277} PluginThreadCall;
278
279/**
280 * Data structure passed to functions called in a new thread.
281 */
282
283typedef struct async_call_thread_data
284{
285 std::vector<void*> parameters;
286 std::string result;
287 bool result_ready;
288 bool call_successful;
289} AsyncCallThreadData;
290
291/*
292 * Misc. utility functions
293 *
294 * This class is never instantiated and should contain static functions only
295 */
296
297/* Function to process all pending async calls */
298void processAsyncCallQueue(void*);
299
300class IcedTeaPluginUtilities
301{
302
303 private:
304 static int reference; /* Reference count */
305
306 /* Mutex lock for updating reference count */
307 static pthread_mutex_t reference_mutex;
308
309 /* Map holding window pointer<->instance relationships */
310 static std::map<void*, NPP>* instance_map;
311
312 /* Map holding java-side-obj-key->NPObject relationship */
313 static std::map<std::string, NPObject*>* object_map;
314
315 /* Posts a call in the async call queue */
316 static bool postPluginThreadAsyncCall(NPP instance, void (*func) (void *), void* data);
317
318 public:
319
320 /* Constructs message prefix with given context */
321 static void constructMessagePrefix(int context,
322 std::string* result);
323
324 /* Constructs message prefix with given context and reference */
325 static void constructMessagePrefix(int context, int reference,
326 std::string* result);
327
328 /* Constructs message prefix with given context, reference and src */
329 static void constructMessagePrefix(int context, int reference,
330 std::string address,
331 std::string* result);
332
333 /* Converts given pointer to a string representation */
334 static void JSIDToString(void* id, std::string* result);
335
336 /* Converts the given string representation to a pointer */
337 static void* stringToJSID(std::string id_str);
338 static void* stringToJSID(std::string* id_str);
339
340 /* Increments reference count and returns it */
341 static int getReference();
342
343 /* Decrements reference count */
344 static void releaseReference();
345
346 /* Converts the given integer to a string */
347 static void itoa(int i, std::string* result);
348
349 /* Copies a variant data type into a C++ string */
350 static std::string NPVariantAsString(NPVariant variant);
351
352 /* This must be freed with browserfunctions.memfree */
353 static NPString NPStringCopy(const std::string& result);
354
355 /* This must be freed with browserfunctions.releasevariantvalue */
356 static NPVariant NPVariantStringCopy(const std::string& result);
357
358 /* Returns an std::string represented by the given identifier. */
359 static std::string NPIdentifierAsString(NPIdentifier id);
360
361 /* Frees the given vector and the strings that its contents point to */
362 static void freeStringPtrVector(std::vector<std::string*>* v);
363
364 /* Splits the given string based on the delimiter provided */
365 static std::vector<std::string*>* strSplit(const char* str,
366 const char* delim);
367
368 /* Converts given unicode integer byte array to UTF8 string */
369 static void getUTF8String(int length, int begin,
370 std::vector<std::string*>* unicode_byte_array,
371 std::string* result_unicode_str);
372
373 /* Converts given UTF8 string to unicode integer byte array */
374 static void convertStringToUTF8(std::string* str,
375 std::string* utf_str);
376
377 /* Converts given unicode integer byte array to UTF16LE/UCS-2 string */
378 static void getUTF16LEString(int length, int begin,
379 std::vector<std::string*>* unicode_byte_array,
380 std::wstring* result_unicode_str);
381
382 /* Prints contents of given string vector */
383 static void printStringVector(const char* prefix, std::vector<std::string>* cv);
384
385 /* Prints contents of given string pointer vector */
386 static void printStringPtrVector(const char* prefix, std::vector<std::string*>* cv);
387
388 static std::string* variantToClassName(NPVariant variant);
389
390 static void printNPVariant(NPVariant variant);
391
392 static void NPVariantToString(NPVariant variant, std::string* result);
393
394 static bool javaResultToNPVariant(NPP instance,
395 std::string* java_result,
396 NPVariant* variant);
397
398 static const char* getSourceFromInstance(NPP instance);
399
400 static void storeInstanceID(void* member_ptr, NPP instance);
401
402 static void removeInstanceID(void* member_ptr);
403
404 /* Clear object_map. Useful for tests. */
405 static void clearInstanceIDs();
406
407 static NPP getInstanceFromMemberPtr(void* member_ptr);
408
409 static NPObject* getNPObjectFromJavaKey(std::string key);
410
411 static void storeObjectMapping(std::string key, NPObject* object);
412
413 static void removeObjectMapping(std::string key);
414
415 /* Clear object_map. Useful for tests. */
416 static void clearObjectMapping();
417
418 static void invalidateInstance(NPP instance);
419
420 static bool isObjectJSArray(NPP instance, NPObject* object);
421
422 static void decodeURL(const char* url, char** decoded_url);
423
424 /* Returns a vector of gchar* pointing to the elements of the vector string passed in*/
425 static std::vector<gchar*> vectorStringToVectorGchar(const std::vector<std::string>* stringVec);
426
427 /* Posts call in async queue and waits till execution completes */
428 static void callAndWaitForResult(NPP instance, void (*func) (void *), AsyncCallThreadData* data);
429
430 /*cutting whitespaces from end and start of string*/
431 static void trim(std::string& str);
432 static bool file_exists(std::string filename);
433 //file-loggers helpers
434 static std::string generateLogFileName();
435 static void initFileLog();
436 static void printDebugStatus();
437 static std::string getTmpPath();
438 static std::string getRuntimePath();
439};
440
441/*
442 * A bus subscriber interface. Implementors must implement the newMessageOnBus
443 * method.
444 */
445class BusSubscriber
446{
447 private:
448
449 public:
450 BusSubscriber() {}
451
452 /* Notifies this subscriber that a new message as arrived */
453 virtual bool newMessageOnBus(const char* message) = 0;
454};
455
456/*
457 * This implementation is very simple and is therefore folded into this file
458 * rather than a new one.
459 */
460class JavaMessageSender : public BusSubscriber
461{
462 private:
463 public:
464
465 /* Sends given message to Java side */
466 virtual bool newMessageOnBus(const char* message);
467};
468
469/*
470 * Represents a message bus.
471 * The bus can also have subscribers who are notified when a new message
472 * arrives.
473 */
474class MessageBus
475{
476 private:
477 /* Mutex for locking the message queue */
478 pthread_mutex_t msg_queue_mutex;
479
480 /* Mutex used when adjusting subscriber list */
481 pthread_mutex_t subscriber_mutex;
482
483 /* Subscriber list */
484 std::list<BusSubscriber*> subscribers;
485
486 /* Queued messages */
487 std::queue<char*> msgQueue;
488
489 public:
490 MessageBus();
491
492 ~MessageBus();
493
494 /* subscribe to this bus */
495 void subscribe(BusSubscriber* b);
496
497 /* unsubscribe from this bus */
498 void unSubscribe(BusSubscriber* b);
499
500 /* Post a message on to the bus (it is safe to free the message pointer
501 after this function returns) */
502 void post(const char* message);
503};
504
505
506
507#endif // __ICEDTEAPLUGINUTILS_H__
Note: See TracBrowser for help on using the repository browser.