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/>. 
  28 #include <sys/types.h> 
  29 #include <sys/socket.h> 
  30 #include <netinet/in.h> 
  34 #include <CoreFoundation/CoreFoundation.h> 
  37 #include "cycript.hpp" 
  39 #include "JavaScript.hpp" 
  41 #include "Pooling.hpp" 
  43 #include "Cycript.tab.hh" 
  48     const char * volatile data_
; 
  49     pthread_mutex_t mutex_
; 
  50     pthread_cond_t condition_
; 
  53 void CYPerform(void *arg
) { 
  54     CYExecute_ 
*execute(reinterpret_cast<CYExecute_ 
*>(arg
)); 
  56     const char *data(execute
->data_
); 
  57     execute
->data_ 
= NULL
; 
  58     execute
->data_ 
= CYExecute(CYGetJSContext(), execute
->pool_
, CYUTF8String(data
)); 
  60     pthread_mutex_lock(&execute
->mutex_
); 
  61     pthread_cond_signal(&execute
->condition_
); 
  62     pthread_mutex_unlock(&execute
->mutex_
); 
  71     CYClient(int socket
) : 
  77         _syscall(close(socket_
)); 
  83         CFRunLoopRef 
loop(CFRunLoopGetMain()); 
  84         if (CFStringRef mode 
= CFRunLoopCopyCurrentMode(loop
)) { 
  93             if (!CYRecvAll(socket_
, &size
, sizeof(size
))) 
  97             char *data(new(pool
) char[size 
+ 1]); 
  98             if (!CYRecvAll(socket_
, data
, size
)) 
 102             std::string 
code(data
, size
); 
 103             CYExecute_ execute 
= {pool
, code
.c_str()}; 
 105             pthread_mutex_init(&execute
.mutex_
, NULL
); 
 106             pthread_cond_init(&execute
.condition_
, NULL
); 
 112                 CFRunLoopSourceContext context
; 
 113                 memset(&context
, 0, sizeof(context
)); 
 115                 context
.info 
= &execute
; 
 116                 context
.perform 
= &CYPerform
; 
 118                 CFRunLoopSourceRef 
source(CFRunLoopSourceCreate(kCFAllocatorDefault
, 0, &context
)); 
 120                 pthread_mutex_lock(&execute
.mutex_
); 
 122                 CFRunLoopAddSource(loop
, source
, kCFRunLoopCommonModes
); 
 123                 CFRunLoopSourceSignal(source
); 
 125                 CFRunLoopWakeUp(loop
); 
 126                 pthread_cond_wait(&execute
.condition_
, &execute
.mutex_
); 
 127                 pthread_mutex_unlock(&execute
.mutex_
); 
 129                 CFRunLoopRemoveSource(loop
, source
, kCFRunLoopCommonModes
); 
 134             pthread_cond_destroy(&execute
.condition_
); 
 135             pthread_mutex_destroy(&execute
.mutex_
); 
 137             const char *json(execute
.data_
); 
 138             size 
= json 
== NULL 
? _not(uint32_t) : strlen(json
); 
 140             if (!CYSendAll(socket_
, &size
, sizeof(size
))) 
 143                 if (!CYSendAll(socket_
, json
, size
)) 
 149 static void *OnClient(void *data
) { 
 150     CYClient 
*client(reinterpret_cast<CYClient 
*>(data
)); 
 156 extern "C" void CYHandleClient(int socket
) { 
 157     // XXX: this leaks memory... really? 
 158     CYPool 
*pool(new CYPool()); 
 159     CYClient 
*client(new(*pool
) CYClient(socket
)); 
 160     _assert(pthread_create(&client
->thread_
, NULL
, &OnClient
, client
) == 0); 
 163 static void CYHandleSocket(const char *path
) { 
 164     int socket(_syscall(::socket(PF_UNIX
, SOCK_STREAM
, 0))); 
 166     struct sockaddr_un address
; 
 167     memset(&address
, 0, sizeof(address
)); 
 168     address
.sun_family 
= AF_UNIX
; 
 169     strcpy(address
.sun_path
, path
); 
 171     _syscall(connect(socket
, reinterpret_cast<sockaddr 
*>(&address
), SUN_LEN(&address
))); 
 173     CYInitializeDynamic(); 
 174     CYHandleClient(socket
); 
 177 extern "C" void CYHandleServer(pid_t pid
) { try { 
 179     sprintf(path
, "/tmp/.s.cy.%u", pid
); 
 180     CYHandleSocket(path
); 
 181 } catch (const CYException 
&error
) { 
 183     fprintf(stderr
, "%s\n", error
.PoolCString(pool
)); 
 186 extern "C" char *MSmain0(int argc
, char *argv
[]) { try { 
 188     CYHandleSocket(argv
[1]); 
 190     static void *handle(NULL
); 
 191     if (handle 
== NULL
) { 
 193         _assert(dladdr(reinterpret_cast<void *>(&MSmain0
), &info
) != 0); 
 194         handle 
= dlopen(info
.dli_fname
, RTLD_NOLOAD
); 
 198 } catch (const CYException 
&error
) { 
 200     return strdup(error
.PoolCString(pool
)); 
 208     CYServer(uint16_t port
) : 
 216             _syscall(close(socket_
)); 
 220         socket_ 
= _syscall(::socket(PF_INET
, SOCK_STREAM
, 0)); try { 
 222             address
.sin_family 
= AF_INET
; 
 223             address
.sin_addr
.s_addr 
= INADDR_ANY
; 
 224             address
.sin_port 
= htons(port_
); 
 225             _syscall(::bind(socket_
, reinterpret_cast<sockaddr 
*>(&address
), sizeof(address
))); 
 227             _syscall(::listen(socket_
, -1)); 
 230                 socklen_t 
length(sizeof(address
)); 
 231                 int socket(_syscall(::accept(socket_
, reinterpret_cast<sockaddr 
*>(&address
), &length
))); 
 232                 CYHandleClient(socket
); 
 234         } catch (const CYException 
&error
) { 
 236             fprintf(stderr
, "%s\n", error
.PoolCString(pool
)); 
 241 static void *OnServer(void *data
) { 
 242     CYServer 
*server(reinterpret_cast<CYServer 
*>(data
)); 
 248 extern "C" void CYListenServer(short port
) { 
 249     CYInitializeDynamic(); 
 251     CYServer 
*server(new CYServer(port
)); 
 252     _assert(pthread_create(&server
->thread_
, NULL
, &OnServer
, server
) == 0);