1 /* Cycript - Optimizing JavaScript Compiler/Runtime
 
   2  * Copyright (C) 2009-2014  Jay Freeman (saurik)
 
   5 /* GNU Affero General Public License, Version 3 {{{ */
 
   7  * This program is free software: you can redistribute it and/or modify
 
   8  * it under the terms of the GNU Affero General Public License as published by
 
   9  * the Free Software Foundation, either version 3 of the License, or
 
  10  * (at your option) any later version.
 
  12  * This program is distributed in the hope that it will be useful,
 
  13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  15  * GNU Affero General Public License for more details.
 
  17  * You should have received a copy of the GNU Affero General Public License
 
  18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
  22 #include <Foundation/Foundation.h>
 
  28 #include <sys/types.h>
 
  29 #include <sys/socket.h>
 
  30 #include <netinet/in.h>
 
  33 #include "cycript.hpp"
 
  35 #include "JavaScript.hpp"
 
  37 #include "Pooling.hpp"
 
  39 #include "Cycript.tab.hh"
 
  44     const char * volatile data_;
 
  47 // XXX: this is "tre lame"
 
  48 @interface CYClient_ : NSObject {
 
  51 - (void) execute:(NSValue *)value;
 
  55 @implementation CYClient_
 
  57 - (void) execute:(NSValue *)value {
 
  58     CYExecute_ *execute(reinterpret_cast<CYExecute_ *>([value pointerValue]));
 
  59     const char *data(execute->data_);
 
  60     execute->data_ = NULL;
 
  61     execute->data_ = CYExecute(CYGetJSContext(), execute->pool_, CYUTF8String(data));
 
  72     CYClient(int socket) :
 
  78         _syscall(close(socket_));
 
  82         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 
  84         CYClient_ *client = [[[CYClient_ alloc] init] autorelease];
 
  87         if (CFStringRef mode = CFRunLoopCopyCurrentMode(CFRunLoopGetMain())) {
 
  95             if (!CYRecvAll(socket_, &size, sizeof(size)))
 
  99             char *data(new(pool) char[size + 1]);
 
 100             if (!CYRecvAll(socket_, data, size))
 
 104             NSAutoreleasePool *ar = [[NSAutoreleasePool alloc] init];
 
 106             std::string code(data, size);
 
 107             CYExecute_ execute = {pool, code.c_str()};
 
 108             NSValue *value([NSValue valueWithPointer:&execute]);
 
 110                 [client performSelectorOnMainThread:@selector(execute:) withObject:value waitUntilDone:YES];
 
 112                 [client execute:value];
 
 114             const char *json(execute.data_);
 
 115             size = json == NULL ? _not(uint32_t) : strlen(json);
 
 119             if (!CYSendAll(socket_, &size, sizeof(size)))
 
 122                 if (!CYSendAll(socket_, json, size))
 
 130 static void *OnClient(void *data) {
 
 131     CYClient *client(reinterpret_cast<CYClient *>(data));
 
 137 extern "C" void CYHandleClient(int socket) {
 
 138     // XXX: this leaks memory... really?
 
 139     CYPool *pool(new CYPool());
 
 140     CYClient *client(new(*pool) CYClient(socket));
 
 141     _assert(pthread_create(&client->thread_, NULL, &OnClient, client) == 0);
 
 144 static void CYHandleProcess(pid_t pid) {
 
 145     CYInitializeDynamic();
 
 147     int socket(_syscall(::socket(PF_UNIX, SOCK_STREAM, 0)));
 
 149     struct sockaddr_un address;
 
 150     memset(&address, 0, sizeof(address));
 
 151     address.sun_family = AF_UNIX;
 
 152     sprintf(address.sun_path, "/tmp/.s.cy.%u", pid);
 
 154     _syscall(connect(socket, reinterpret_cast<sockaddr *>(&address), SUN_LEN(&address)));
 
 155     CYHandleClient(socket);
 
 158 extern "C" void CYHandleServer(pid_t pid) { try {
 
 159     CYHandleProcess(pid);
 
 160 } catch (const CYException &error) {
 
 162     fprintf(stderr, "%s\n", error.PoolCString(pool));
 
 165 extern "C" char *MSmain0(int argc, char *argv[]) { try {
 
 170     pid_t pid(strtoul(arg, &end, 10));
 
 171     _assert(end == arg + strlen(arg));
 
 173     static void *handle(NULL);
 
 174     if (handle == NULL) {
 
 176         _assert(dladdr(reinterpret_cast<void *>(&MSmain0), &info) != 0);
 
 177         handle = dlopen(info.dli_fname, RTLD_NOLOAD);
 
 180     CYHandleProcess(pid);
 
 183 } catch (const CYException &error) {
 
 185     return strdup(error.PoolCString(pool));
 
 193     CYServer(uint16_t port) :
 
 201             _syscall(close(socket_));
 
 205         socket_ = _syscall(::socket(PF_INET, SOCK_STREAM, 0)); try {
 
 207             address.sin_family = AF_INET;
 
 208             address.sin_addr.s_addr = INADDR_ANY;
 
 209             address.sin_port = htons(port_);
 
 210             _syscall(::bind(socket_, reinterpret_cast<sockaddr *>(&address), sizeof(address)));
 
 212             _syscall(::listen(socket_, -1));
 
 215                 socklen_t length(sizeof(address));
 
 216                 int socket(_syscall(::accept(socket_, reinterpret_cast<sockaddr *>(&address), &length)));
 
 217                 CYHandleClient(socket);
 
 219         } catch (const CYException &error) {
 
 221             fprintf(stderr, "%s\n", error.PoolCString(pool));
 
 226 static void *OnServer(void *data) {
 
 227     CYServer *server(reinterpret_cast<CYServer *>(data));
 
 233 extern "C" void CYListenServer(short port) {
 
 234     CYInitializeDynamic();
 
 236     CYServer *server(new CYServer(port));
 
 237     _assert(pthread_create(&server->thread_, NULL, &OnServer, server) == 0);