Merge branch 'master' into release_0_8_9
[gnash.git] / plugin / npapi / pluginScriptObject.cpp
blob345533f410bffcf0492b5365e0b3b5658af93daf
1 //
2 // Copyright (C) 2010, 2011 Free Software Foundation, Inc
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 #ifdef HAVE_CONFIG_H
20 #include "gnashconfig.h"
21 #endif
23 #include <iostream>
24 #include <fstream>
25 #include <sstream>
26 #include <map>
27 #include <string>
28 #include <fcntl.h>
29 #include <cstring>
30 #include <cstdlib>
31 #include <cstdio>
32 #include <cerrno>
33 #include <sys/types.h>
34 #include <unistd.h>
35 #if defined(HAVE_WINSOCK_H) && !defined(__OS2__)
36 # include <winsock2.h>
37 # include <windows.h>
38 # include <sys/stat.h>
39 # include <io.h>
40 # include <ws2tcpip.h>
41 #else
42 # include <sys/un.h>
43 # include <sys/ioctl.h>
44 # include <unistd.h>
45 # include <sys/select.h>
46 # include <netinet/in.h>
47 # include <arpa/inet.h>
48 # include <sys/socket.h>
49 #endif
50 #include "npapi.h"
51 #include "npruntime.h"
52 #include "plugin.h"
53 #include "callbacks.h"
54 #include "external.h"
55 #include "pluginScriptObject.h"
57 extern NPNetscapeFuncs NPNFuncs;
59 namespace gnash {
61 // NPClass of GnashPluginScriptObject
62 static NPClass GnashPluginScriptObjectClass = {
63 NP_CLASS_STRUCT_VERSION,
64 GnashPluginScriptObject::marshalAllocate,
65 GnashPluginScriptObject::marshalDeallocate,
66 GnashPluginScriptObject::marshalInvalidate,
67 GnashPluginScriptObject::marshalHasMethod,
68 GnashPluginScriptObject::marshalInvoke,
69 GnashPluginScriptObject::marshalInvokeDefault,
70 GnashPluginScriptObject::marshalHasProperty,
71 GnashPluginScriptObject::marshalGetProperty,
72 GnashPluginScriptObject::marshalSetProperty,
73 GnashPluginScriptObject::marshalRemoveProperty,
74 GnashPluginScriptObject::marshalEnumerate,
75 GnashPluginScriptObject::marshalConstruct
78 /// The HostFD is the file descriptor for the socket connection
79 /// to the standalone player. This is used by this plugin when reading
80 /// messages from the standalone player.
81 static int hostfd = -1;
83 /// The ControlFD is the file descriptor for the socket connection
84 /// to the standalone player. This is used when writing to the
85 /// standalone player from this plugin.
86 static int controlfd = -1;
88 void
89 printNPVariant(const NPVariant *value)
91 if (NPVARIANT_IS_DOUBLE(*value)) {
92 double num = NPVARIANT_TO_DOUBLE(*value);
93 log_debug("is double, value %g", num);
94 } else if (NPVARIANT_IS_STRING(*value)) {
95 std::string str = NPStringToString(NPVARIANT_TO_STRING(*value));
96 log_debug("is string, value %s", str);
97 } else if (NPVARIANT_IS_BOOLEAN(*value)) {
98 bool flag = NPVARIANT_TO_BOOLEAN(*value);
99 log_debug("is boolean, value %d", flag);
100 } else if (NPVARIANT_IS_INT32(*value)) {
101 int num = NPVARIANT_TO_INT32(*value);
102 log_debug("is int, value %d", num);
103 } else if (NPVARIANT_IS_NULL(*value)) {
104 log_debug("value is null");
105 } else if (NPVARIANT_IS_VOID(*value)) {
106 log_debug("value is void");
107 } else if (NPVARIANT_IS_OBJECT(*value)) {
108 log_debug("value is object");
113 // The methods for GnashPluginScriptObject start here.
116 void
117 GnashPluginScriptObject::AddProperty(const std::string &name,
118 const std::string &val)
120 NPIdentifier id = NPN_GetStringIdentifier(name.c_str());
122 NPVariant strvar;
123 STRINGN_TO_NPVARIANT(val.c_str(), static_cast<int>(val.size()), strvar);
124 SetProperty(id, strvar);
127 void
128 GnashPluginScriptObject::AddProperty(const std::string &name, double num)
130 NPIdentifier id = NPN_GetStringIdentifier(name.c_str());
131 NPVariant value;
132 DOUBLE_TO_NPVARIANT(num, value);
133 SetProperty(id, value);
136 void
137 GnashPluginScriptObject::AddProperty(const std::string &name, int num)
139 NPIdentifier id = NPN_GetStringIdentifier(name.c_str());
140 NPVariant value;
141 INT32_TO_NPVARIANT(num, value);
142 SetProperty(id, value);
145 // Sets up the property and method identifier arrays used by the browser
146 // via the hasProperty and hasMethod fuction pointers
147 void
148 GnashPluginScriptObject::initializeIdentifiers()
150 // log_debug("initializeIdentifiers");
152 // NPN_Status(_nppinstance, __FUNCTION__);
154 // http://www.adobe.com/support/flash/publishexport/scriptingwithflash/scriptingwithflash_04.html
156 // We maintain an internal property for our version number, rather
157 // than asking the player.
158 AddProperty("$version", "10,1,r999");
159 // id and name appear to be the same tag, but differeing browsers access
160 // one or the other, or both.
161 // name=send_this_page_swf
162 AddProperty("name", "Hello World");
163 // id=send_this_page_swf
164 AddProperty("id", "Hello World");
166 // http://s.ytimg.com/yt/swf/watch-vfl161193.swf
167 AddProperty("src", "example");
168 AddProperty("align", "middle");
169 AddProperty("quality", "high");
170 AddProperty("bgcolor", "#FFFFFF");
171 AddProperty("allowScriptAccess", "sameDomain");
172 AddProperty("type", "application/x-shockwave-flash");
173 AddProperty("codebase", "http://www.getgnash.org");
174 AddProperty("pluginspage", "http://www.getgnash.org");
176 AddProperty("classid", "2b70f2b1-fc72-4734-bb81-4eb2a7713e49");
177 AddProperty("movie", "unknown");
178 AddProperty("width", 0);
179 AddProperty("height", 0);
180 AddProperty("vspace", 0);
181 AddProperty("hspace", 0);
182 AddProperty("class", "class unknown");
183 AddProperty("title", "title unknown");
184 AddProperty("accesskey", 0);
185 AddProperty("name", "name unknown");
186 AddProperty("tabindex", 8);
187 AddProperty("FlashVars", "flashVars unknown");
189 // Javascript and flash events
190 AddProperty("onafterupdate", "unknown");
191 AddProperty("onbeforeupdate", "unknown");
192 AddProperty("onblur", "unknown");
193 AddProperty("oncellchange", "unknown");
194 AddProperty("onclick", "unknown");
195 AddProperty("ondblClick", "unknown");
196 AddProperty("ondrag", "unknown");
197 AddProperty("ondragend", "unknown");
198 AddProperty("ondragenter", "unknown");
199 AddProperty("ondragleave", "unknown");
200 AddProperty("ondragover", "unknown");
201 AddProperty("ondrop", "unknown");
202 AddProperty("onfinish", "unknown");
203 AddProperty("onfocus", "unknown");
204 AddProperty("onhelp", "unknown");
205 AddProperty("onmousedown", "unknown");
206 AddProperty("onmouseup", "unknown");
207 AddProperty("onmouseover", "unknown");
208 AddProperty("onmousemove", "unknown");
209 AddProperty("onmouseout", "unknown");
210 AddProperty("onkeypress", "unknown");
211 AddProperty("onkeydown", "unknown");
212 AddProperty("onkeyup", "unknown");
213 AddProperty("onload", "unknown");
214 AddProperty("onlosecapture", "unknown");
215 AddProperty("onpropertychange", "unknown");
216 AddProperty("onreadystatechange", "unknown");
217 AddProperty("onrowsdelete", "unknown");
218 AddProperty("onrowenter", "unknown");
219 AddProperty("onrowexit", "unknown");
220 AddProperty("onrowsinserted", "unknown");
221 AddProperty("onstart", "");
222 AddProperty("onscroll", "unknown");
223 AddProperty("onbeforeeditfocus", "unknown");
224 AddProperty("onactivate", "unknown");
225 AddProperty("onbeforedeactivate", "unknown");
226 AddProperty("ondeactivate", "unknown");
228 // Add the default methods
229 NPIdentifier id = NPN_GetStringIdentifier("SetVariable");
230 AddMethod(id, SetVariableCallback);
232 id = NPN_GetStringIdentifier("GetVariable");
233 AddMethod(id, GetVariableCallback);
235 id = NPN_GetStringIdentifier("GotoFrame");
236 AddMethod(id, GotoFrame);
238 id = NPN_GetStringIdentifier("IsPlaying");
239 AddMethod(id, IsPlaying);
241 id = NPN_GetStringIdentifier("LoadMovie");
242 AddMethod(id, LoadMovie);
244 id = NPN_GetStringIdentifier("Pan");
245 AddMethod(id, Pan);
247 id = NPN_GetStringIdentifier("PercentLoaded");
248 AddMethod(id, PercentLoaded);
250 id = NPN_GetStringIdentifier("Play");
251 AddMethod(id, Play);
253 id = NPN_GetStringIdentifier("Rewind");
254 AddMethod(id, Rewind);
256 id = NPN_GetStringIdentifier("SetZoomRect");
257 AddMethod(id, SetZoomRect);
259 id = NPN_GetStringIdentifier("StopPlay");
260 AddMethod(id, StopPlay);
262 id = NPN_GetStringIdentifier("Zoom");
263 AddMethod(id, Zoom);
265 id = NPN_GetStringIdentifier("TotalFrames");
266 AddMethod(id, TotalFrames);
268 // id = NPN_GetStringIdentifier("TestASMethod");
269 // AddMethod(id, remoteCallback);
272 // Constructor
273 GnashPluginScriptObject::GnashPluginScriptObject()
274 : _nppinstance (0)
276 // log_debug(__PRETTY_FUNCTION__);
278 initializeIdentifiers();
280 _sockfds[READFD] = 0;
281 _sockfds[WRITEFD] = 0;
284 // Constructor
285 GnashPluginScriptObject::GnashPluginScriptObject(NPP npp)
286 : _nppinstance (npp)
288 // log_debug(__PRETTY_FUNCTION__);
290 initializeIdentifiers();
292 _sockfds[READFD] = 0;
293 _sockfds[WRITEFD] = 0;
296 // Destructor
297 GnashPluginScriptObject::~GnashPluginScriptObject()
299 // log_debug(__PRETTY_FUNCTION__);
300 // Should be automatically shutdown by GIO
301 // closePipe();
304 // Marshal Functions
305 NPClass *
306 GnashPluginScriptObject::marshalGetNPClass()
308 // log_debug(__PRETTY_FUNCTION__);
309 return &GnashPluginScriptObjectClass;
312 NPObject *
313 GnashPluginScriptObject::marshalAllocate (NPP npp, NPClass */* aClass */)
315 // log_debug(__PRETTY_FUNCTION__);
316 #if 0
317 GnashPluginScriptObject *npobj = reinterpret_cast<GnashPluginScriptObject *>
318 (NPN_MemAlloc(sizeof(GnashPluginScriptObject)));
319 npobj->setInstance(npp);
320 return npobj;
321 #else
322 return new GnashPluginScriptObject(npp);
323 #endif
327 void
328 GnashPluginScriptObject::marshalDeallocate (NPObject *npobj)
330 // log_debug(__PRETTY_FUNCTION__);
331 #if 0
332 NPN_MemFree(reinterpret_cast<void *>(npobj));
333 #else
334 delete (GnashPluginScriptObject *)npobj;
335 #endif
338 void
339 GnashPluginScriptObject::marshalInvalidate (NPObject */* npobj */)
341 // log_debug(__PRETTY_FUNCTION__);
343 // gpso->Invalidate();
346 bool
347 GnashPluginScriptObject::marshalHasMethod (NPObject *npobj, NPIdentifier name)
349 // log_debug(__PRETTY_FUNCTION__);
351 GnashPluginScriptObject *gpso = (GnashPluginScriptObject *)npobj;
353 #if 0
354 log_debug("Checking for Method: ");
355 if (NPN_IdentifierIsString(name)) {
356 log_debug("%s", NPN_UTF8FromIdentifier(name));
357 } else {
358 log_debug("%d", NPN_IntFromIdentifier(name));
360 #endif
362 return gpso->HasMethod(name);
365 bool
366 GnashPluginScriptObject::marshalInvoke (NPObject *npobj, NPIdentifier name,
367 const NPVariant *args, uint32_t argCount,
368 NPVariant *result)
370 GnashPluginScriptObject *gpso = (GnashPluginScriptObject *)npobj;
372 return gpso->Invoke(npobj, name, args, argCount, result);
375 bool
376 GnashPluginScriptObject::marshalInvokeDefault (NPObject *npobj,
377 const NPVariant *args,
378 uint32_t argCount,
379 NPVariant *result)
381 GnashPluginScriptObject *gpso = (GnashPluginScriptObject *)npobj;
383 return gpso->InvokeDefault(args, argCount, result);
386 bool
387 GnashPluginScriptObject::marshalHasProperty (NPObject *npobj, NPIdentifier name)
389 GnashPluginScriptObject *gpso = (GnashPluginScriptObject *)npobj;
391 return gpso->HasProperty(name);
394 bool
395 GnashPluginScriptObject::marshalGetProperty (NPObject *npobj, NPIdentifier name,
396 NPVariant *result)
398 GnashPluginScriptObject *gpso = (GnashPluginScriptObject *)npobj;
400 return gpso->GetProperty(name, result);
403 bool
404 GnashPluginScriptObject::marshalSetProperty (NPObject *npobj, NPIdentifier name,
405 const NPVariant *value)
407 GnashPluginScriptObject *gpso = (GnashPluginScriptObject *)npobj;
408 return gpso->SetProperty(name, *value);
411 bool
412 GnashPluginScriptObject::marshalRemoveProperty (NPObject *npobj, NPIdentifier name)
414 GnashPluginScriptObject *gpso = (GnashPluginScriptObject *)npobj;
415 return gpso->RemoveProperty(name);
418 bool
419 GnashPluginScriptObject::marshalEnumerate (NPObject *npobj, void***identifier,
420 uint32_t *count)
422 log_debug(__PRETTY_FUNCTION__);
424 GnashPluginScriptObject *gpso = (GnashPluginScriptObject *)npobj;
425 return gpso->Enumerate(identifier, count);
427 return false;
430 bool
431 GnashPluginScriptObject::marshalConstruct (NPObject *npobj, const NPVariant *data,
432 uint32_t count, NPVariant *result)
434 log_debug(__PRETTY_FUNCTION__);
436 GnashPluginScriptObject *gpso = (GnashPluginScriptObject *)npobj;
437 return gpso->Construct(data, count, result);
439 return false;
442 bool
443 GnashPluginScriptObject::HasProperty(NPIdentifier name)
445 #if 0
446 log_debug("Checking for Property \"");
447 if (NPN_IdentifierIsString(name)) {
448 log_debug("%s\"...", NPN_UTF8FromIdentifier(name));
449 } else {
450 log_debug("%d\"...", NPN_IntFromIdentifier(name));
452 #endif
454 return _properties.find(name) != _properties.end();
457 bool
458 GnashPluginScriptObject::GetProperty(NPIdentifier name, NPVariant *result)
460 if (NPN_IdentifierIsString(name)) {
461 log_debug("Getting Property \"%s\"...", NPN_UTF8FromIdentifier(name));
462 } else {
463 log_debug("Getting Property \"%d\"...", NPN_IntFromIdentifier(name));
466 std::map<NPIdentifier, GnashNPVariant>::const_iterator it;
467 it = _properties.find(name);
468 if (it == _properties.end()) {
469 return false;
472 const GnashNPVariant& val = it->second;
473 val.copy(*result);
475 return true;
478 bool
479 GnashPluginScriptObject::SetProperty(NPIdentifier name, const NPVariant& value)
481 _properties[name] = value;
483 return false;
486 bool
487 GnashPluginScriptObject::RemoveProperty(NPIdentifier name)
489 std::map<NPIdentifier, GnashNPVariant>::iterator it;
490 it = _properties.find(name);
491 if (it != _properties.end()) {
492 _properties.erase(it);
493 return true;
496 return false;
499 bool
500 GnashPluginScriptObject::Enumerate(NPIdentifier **/*identifier */, uint32_t */* count */)
502 log_debug(__PRETTY_FUNCTION__);
504 return false;
507 bool
508 GnashPluginScriptObject::Construct(const NPVariant */* args */, uint32_t /* argCount */,
509 NPVariant */* result */)
511 log_debug(__PRETTY_FUNCTION__);
513 return false;
516 bool
517 GnashPluginScriptObject::HasMethod(NPIdentifier name)
519 #if 0
520 log_debug("Checking for Method \"");
521 if (NPN_IdentifierIsString(name)) {
522 log_debug("%s\"...", NPN_UTF8FromIdentifier(name));
523 } else {
524 log_debug("%d\"...", NPN_IntFromIdentifier(name));
526 #endif
528 return _methods.find(name) != _methods.end();
531 bool
532 GnashPluginScriptObject::Invoke(NPObject */* npobj */, NPIdentifier name,
533 const NPVariant *args, uint32_t argCount,
534 NPVariant *result)
536 // log_debug(__PRETTY_FUNCTION__);
538 #if 1
539 if (NPN_IdentifierIsString(name)) {
540 log_debug("Invoking Method \"%s\"...", NPN_UTF8FromIdentifier(name));
541 } else {
542 log_debug("Invoking Method: \"%d\"...", NPN_IntFromIdentifier(name));
544 // log_debug("SCRIPT OBJECT invoke %s: %x", NPN_UTF8FromIdentifier(name),
545 // (void *)npobj);
546 #endif
548 std::map<NPIdentifier, NPInvokeFunctionPtr>::iterator it;
549 it = _methods.find(name);
550 if (it != _methods.end()) {
551 // log_debug("FOUND Method \"%s\"!", NPN_UTF8FromIdentifier(name));
552 NPInvokeFunctionPtr func = it->second;
553 return func(NULL, name, args, argCount, result);
554 } else {
555 log_error("Couldn't find Method \"%s\"", NPN_UTF8FromIdentifier(name));
558 return false;
560 // return NPN_Invoke(_nppinstance, this, name, args, argCount, result);
563 bool
564 GnashPluginScriptObject::InvokeDefault(const NPVariant */* args */,
565 uint32_t /* argCount */, NPVariant */* result */)
567 log_debug(__PRETTY_FUNCTION__);
568 #if 0
569 log_debug("Invoking Default Method \"");
570 if (NPN_IdentifierIsString(name)) {
571 log_debug("%s\"...", NPN_UTF8FromIdentifier(name));
572 } else {
573 log_debug("%d\"...", NPN_IntFromIdentifier(name));
575 #endif
577 return false;
580 bool
581 GnashPluginScriptObject::AddMethod(NPIdentifier name, NPInvokeFunctionPtr func)
583 // log_debug(__PRETTY_FUNCTION__);
585 #if 0
586 if (NPN_IdentifierIsString(name)) {
587 log_debug("Adding Method \"%s\"...", NPN_UTF8FromIdentifier(name));
588 } else {
589 log_debug("Adding Method \"%d\"...", NPN_IntFromIdentifier(name));
591 #endif
593 _methods[name] = func;
595 return true;
598 // SetVariable sends a message to the player that looks like this:
599 // "Command Name Type value\n", ie... "SetVariable var1 string value1\n"
600 bool
601 GnashPluginScriptObject::SetVariable(const std::string &name,
602 const NPVariant& value)
604 std::vector<std::string> iargs;
605 std::string str = plugin::ExternalInterface::makeString(name);
606 iargs.push_back(str);
607 str = plugin::ExternalInterface::convertNPVariant(&value);
608 iargs.push_back(str);
609 str = plugin::ExternalInterface::makeInvoke("SetVariable", iargs);
611 log_debug("Trying to set a value for %s.", name);
613 // Write the message to the Control FD.
614 size_t ret = writePlayer(str);
615 // Unless we wrote the same amount of data as the message contained,
616 // something went wrong.
617 if (ret != str.size()) {
618 log_error("Couldn't set the variable, network problems.");
619 return false;
622 return true;
625 // GetVariable sends a message to the player that looks like this:
626 // "Command Name\n", ie... "GetVariable var1\n". Then it waits
627 // for the response with the type and value.
628 GnashNPVariant
629 GnashPluginScriptObject::GetVariable(const std::string &name)
631 std::vector<std::string> iargs;
632 std::string str = plugin::ExternalInterface::makeString(name);
633 iargs.push_back(str);
634 str = plugin::ExternalInterface::makeInvoke("GetVariable", iargs);
636 log_debug("Trying to get a value for %s.", name);
638 size_t ret = writePlayer(str);
639 if (ret != str.size()) {
640 // If all the browser wants is the version, we don't need to
641 // ask the standalone player for this value. YouTube at
642 // least depends on this for some pages which want this to
643 // be greater than 8.0.0. This appears to potentially be
644 // Google's way of trying to revent downloaders, as this requires
645 // plugin support.
646 NPVariant value;
647 if (name == "$version") {
648 STRINGN_TO_NPVARIANT("LNX 10,0,r999", 13, value);
649 } else {
650 log_error("Couldn't send GetVariable request, network problems.");
651 NULL_TO_NPVARIANT(value);
653 return value;
656 // Have the read function allocate the memory
657 std::string data = readPlayer();
658 if (data.empty()) {
659 return GnashNPVariant();
662 GnashNPVariant parsed = plugin::ExternalInterface::parseXML(data);
664 printNPVariant(&parsed.get());
666 return parsed;
669 void
670 GnashPluginScriptObject::setControlFD(int x)
672 // log_debug("%s: %d", __FUNCTION__, x);
673 #if 0
674 if (_iochan == 0) {
675 _iochan[WRITEFD] = g_io_channel_unix_new(x);
677 #endif
678 controlfd = x; // FIXME: this should go away
682 GnashPluginScriptObject::getControlFD()
684 // log_debug("getControlFD: %d", controlfd);
686 #if 0
687 return g_io_channel_unix_get_fd (_iochan);
688 #endif
689 return controlfd;
692 void
693 GnashPluginScriptObject::setHostFD(int x)
695 // log_debug("%s: %d", __FUNCTION__, x);
696 #if 0
697 if (_iochan == 0) {
698 _iochan[WRITEFD] = g_io_channel_unix_new(x);
700 #endif
701 hostfd = x; // FIXME: this should go away
705 GnashPluginScriptObject::getHostFD()
707 // log_debug("getControlFD: %d", controlfd);
709 #if 0
710 return g_io_channel_unix_get_fd (_iochan);
711 #endif
712 return hostfd;
716 // Write to the standalone player over the control socket
718 GnashPluginScriptObject::writePlayer(const std::string &data)
720 return writePlayer(controlfd, data);
724 GnashPluginScriptObject::writePlayer(int fd, const std::string &data)
726 // log_debug(__PRETTY_FUNCTION__);
728 // log_debug("Writing data to fd #%d:\n %s", fd, data);
730 if (fd > 2) {
731 return ::write(fd, data.c_str(), data.size());
734 return 0;
737 std::string
738 GnashPluginScriptObject::readPlayer()
740 return readPlayer(hostfd);
743 std::string
744 GnashPluginScriptObject::readPlayer(int fd)
746 // log_debug(__PRETTY_FUNCTION__);
748 std::string empty;
750 if (fd <= 0) {
751 log_error("Invalid fd passed");
752 return empty;
755 // Wait for some data from the player
756 int bytes = 0;
757 fd_set fdset;
758 FD_ZERO(&fdset);
759 FD_SET(fd, &fdset);
760 struct timeval tval;
761 tval.tv_sec = 2;
762 tval.tv_usec = 0;
763 // log_debug("Waiting for data... ");
764 if (select(fd+1, &fdset, NULL, NULL, &tval)) {
765 // log_debug("There is data in the network");
766 #ifndef _WIN32
767 ioctl(fd, FIONREAD, &bytes);
768 #else
769 ioctlSocket(fd, FIONREAD, &bytes);
770 #endif
773 // No data yet
774 if (bytes == 0) {
775 return empty;
778 log_debug("There are %d bytes in the network buffer", bytes);
780 std::string buf(bytes, '\0');
782 int ret = ::read(fd, &buf[0], bytes);
783 if (ret <= 0) {
784 return empty;
787 if (ret < bytes) {
788 buf.resize(ret);
791 return buf;
795 // Close the socket
796 bool
797 GnashPluginScriptObject::closePipe(int fd)
799 // log_debug(__FUNCTION__);
801 if (fd > 0) {
802 // Send a Quit message to the player before closing the pipe.
803 std::vector<std::string> args;
804 std::string str = plugin::ExternalInterface::makeInvoke("Quit", args);
805 writePlayer(fd, str);
807 ::shutdown(fd, SHUT_RDWR);
808 ::close(fd);
811 return true;
814 // Create a socket so we can talk to the player.
815 bool
816 GnashPluginScriptObject::createPipe()
818 log_debug(__PRETTY_FUNCTION__);
819 #if 0
820 int p2c_pipe[2];
821 int c2p_pipe[2];
822 int p2c_controlpipe[2];
824 int ret = socketpair(AF_UNIX, SOCK_STREAM, 0, p2c_pipe);
825 if (ret == -1) {
826 gnash::log_error("ERROR: socketpair(p2c) failed: %s", strerror(errno));
827 return;
829 _streamfd = p2c_pipe[1];
831 ret = socketpair(AF_UNIX, SOCK_STREAM, 0, c2p_pipe);
832 if (ret == -1) {
833 gnash::log_error("ERROR: socketpair(c2p) failed: %s", strerror(errno));
834 return;
837 ret = socketpair(AF_UNIX, SOCK_STREAM, 0, p2c_controlpipe);
838 if (ret == -1) {
839 gnash::log_error("ERROR: socketpair(control) failed: %s", strerror(errno));
840 return;
842 _controlfd = p2c_controlpipe[1];
843 #endif
845 #if 0
846 if ((_sockfds[READFD] == 0) && (_sockfds[WRITEFD] == 0)) {
847 int ret = socketpair(AF_UNIX, SOCK_STREAM, 0, _sockfds);
849 if (ret == 0) {
850 // Set up the Glib IO Channel for reading from the plugin
851 // log_debug("Read fd for socketpair is: %d", _sockfds[READFD]);
853 _iochan[READFD] = g_io_channel_unix_new(_sockfds[READFD]);
854 g_io_channel_set_close_on_unref(_iochan[READFD], true);
855 _watchid = g_io_add_watch(_iochan[READFD],
856 (GIOCondition)(G_IO_IN|G_IO_HUP),
857 (GIOFunc)handleInvokeWrapper, this);
859 // Set up the Glib IO Channel for writing to the plugin
860 // log_debug("Write fd for socketpair is: %d", _sockfds[WRITEFD]);
861 _iochan[WRITEFD] = g_io_channel_unix_new(_sockfds[WRITEFD]);
862 g_io_channel_set_close_on_unref(_iochan[WRITEFD], true);
863 return true;
866 #endif
868 #if 0
869 std::stringstream ss;
870 static int count = 0;
871 ss << "/tmp/gnash-" << getpid() << count++;
873 return createPipe(ss.str());
874 #endif
876 return false;
879 #if 0
880 bool
881 GnashPluginScriptObject::createPipe(const std::string &name)
883 log_debug(__PRETTY_FUNCTION__);
885 mode_t mode = S_IRUSR|S_IWUSR;
886 if (!name.empty()) {
887 int ret = mkfifo(name.c_str(), mode);
888 if (ret == 0) {
889 _sockfd = ::open(name.c_str(), O_RDWR|O_NONBLOCK, mode);
890 if (_sockfd < 0) {
891 log_error("Couldn't open the pipe: \"%s\"", strerror(errno));
893 } else {
894 log_error("Couldn't create fifo: s\n", strerror(errno));
898 _pipename = name;
900 return false;
902 #endif
905 // Close the socketpair
906 bool
907 GnashPluginScriptObject::closePipe()
909 // log_debug(__FUNCTION__);
911 bool ret = closePipe(_sockfds[READFD]);
912 if (ret) {
913 ret = closePipe(_sockfds[WRITEFD]);
914 } else {
915 return false;
918 GError *error;
919 GIOStatus rstatus = g_io_channel_shutdown(_iochan[READFD], true, &error);
920 GIOStatus wstatus = g_io_channel_shutdown(_iochan[WRITEFD], true, &error);
921 if ((rstatus == G_IO_STATUS_NORMAL)
922 && (wstatus == G_IO_STATUS_NORMAL)) {
923 return true;
924 } else {
925 return false;
928 return false;
931 // Check the pipe to see if it's ready, ie... is gnash connected yet ?
932 bool
933 GnashPluginScriptObject::checkPipe()
935 return checkPipe(_sockfds[WRITEFD]);
938 bool
939 GnashPluginScriptObject::checkPipe(int fd)
941 // log_debug(__PRETTY_FUNCTION__);
943 fd_set fdset;
945 if (fd > 2) {
946 FD_ZERO(&fdset);
947 FD_SET(fd, &fdset);
948 struct timeval tval;
949 tval.tv_sec = 0;
950 tval.tv_usec = 100;
951 errno = 0;
952 int ret = select(fd+1, &fdset, NULL, NULL, &tval);
953 if (ret == 0) {
954 log_debug ("The pipe for #fd %d timed out waiting to read", fd);
955 return false;
956 } else if (ret == 1) {
957 log_debug ("The pipe for #fd is ready", fd);
958 controlfd = fd;
959 return true;
960 } else {
961 log_error("The pipe has this error: %s", strerror(errno));
965 return false;
968 bool
969 GnashPluginScriptObject::handleInvoke(GIOChannel *iochan, GIOCondition cond)
971 log_debug(__PRETTY_FUNCTION__);
973 if ( cond & G_IO_HUP ) {
974 log_debug("Player control channel hang up");
975 // Returning false here will cause the "watch" to be removed. This watch
976 // is the only reference held to the GIOChannel, so it will be
977 // destroyed. We must make sure we don't attempt to destroy it again.
978 _watchid = 0;
979 return false;
982 assert(cond & G_IO_IN);
984 log_debug("Checking player requests on fd #%d",
985 g_io_channel_unix_get_fd(iochan));
987 do {
988 GError* error=NULL;
989 gchar* request;
990 gsize requestSize=0;
991 GIOStatus status = g_io_channel_read_line(iochan, &request,
992 &requestSize, NULL, &error);
994 switch ( status ) {
995 case G_IO_STATUS_ERROR:
996 log_error("Error reading request line: %s", error->message);
998 g_error_free(error);
999 return false;
1000 case G_IO_STATUS_EOF:
1001 log_error("EOF (error: %s", error->message);
1002 return false;
1003 case G_IO_STATUS_AGAIN:
1004 log_error("Read again(error: %s", error->message);
1005 break;
1006 case G_IO_STATUS_NORMAL:
1007 // process request
1008 log_debug("Normal read: %s" + std::string(request));
1009 break;
1010 default:
1011 log_error("Abnormal status!");
1012 return false;
1016 // process request..
1017 processPlayerRequest(request, requestSize);
1018 g_free(request);
1020 } while (g_io_channel_get_buffer_condition(iochan) & G_IO_IN);
1022 return true;
1025 bool
1026 GnashPluginScriptObject::processPlayerRequest(gchar */* buf */, gsize /* len */)
1028 log_debug(__PRETTY_FUNCTION__);
1030 return false;
1033 bool
1034 GnashPluginScriptObject::handleInvokeWrapper(GIOChannel *iochan,
1035 GIOCondition cond,
1036 GnashPluginScriptObject* plugin)
1038 log_debug(__PRETTY_FUNCTION__);
1040 return plugin->handleInvoke(iochan, cond);
1043 } // end of gnash namespace
1045 // local Variables:
1046 // mode: C++
1047 // indent-tabs-mode: nil
1048 // End: