1 /* Cycript - The Truly Universal Scripting Language 
   2  * Copyright (C) 2009-2016  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 "cycript.hpp" 
  30 #include <sys/types.h> 
  31 #include <sys/socket.h> 
  32 #include <netinet/in.h> 
  36 #include <CoreFoundation/CoreFoundation.h> 
  40 #include "JavaScript.hpp" 
  42 #include "Pooling.hpp" 
  46     const char * volatile data_
; 
  47     pthread_mutex_t mutex_
; 
  48     pthread_cond_t condition_
; 
  51 void CYPerform(void *arg
) { 
  52     CYExecute_ 
*execute(reinterpret_cast<CYExecute_ 
*>(arg
)); 
  54     const char *data(execute
->data_
); 
  55     execute
->data_ 
= NULL
; 
  56     execute
->data_ 
= CYExecute(CYGetJSContext(), execute
->pool_
, CYUTF8String(data
)); 
  58     pthread_mutex_lock(&execute
->mutex_
); 
  59     pthread_cond_signal(&execute
->condition_
); 
  60     pthread_mutex_unlock(&execute
->mutex_
); 
  69     CYClient(int socket
) : 
  75         _syscall(close(socket_
)); 
  81         CFRunLoopRef 
loop(CFRunLoopGetMain()); 
  82         if (CFStringRef mode 
= CFRunLoopCopyCurrentMode(loop
)) { 
  91             if (!CYRecvAll(socket_
, &size
, sizeof(size
))) 
  95             char *data(new(pool
) char[size 
+ 1]); 
  96             if (!CYRecvAll(socket_
, data
, size
)) 
 100             std::string 
code(data
, size
); 
 101             CYExecute_ execute 
= {pool
, code
.c_str()}; 
 103             pthread_mutex_init(&execute
.mutex_
, NULL
); 
 104             pthread_cond_init(&execute
.condition_
, NULL
); 
 110                 CFRunLoopSourceContext context
; 
 111                 memset(&context
, 0, sizeof(context
)); 
 113                 context
.info 
= &execute
; 
 114                 context
.perform 
= &CYPerform
; 
 116                 CFRunLoopSourceRef 
source(CFRunLoopSourceCreate(kCFAllocatorDefault
, 0, &context
)); 
 118                 pthread_mutex_lock(&execute
.mutex_
); 
 120                 CFRunLoopAddSource(loop
, source
, kCFRunLoopCommonModes
); 
 121                 CFRunLoopSourceSignal(source
); 
 123                 CFRunLoopWakeUp(loop
); 
 124                 pthread_cond_wait(&execute
.condition_
, &execute
.mutex_
); 
 125                 pthread_mutex_unlock(&execute
.mutex_
); 
 127                 CFRunLoopRemoveSource(loop
, source
, kCFRunLoopCommonModes
); 
 132             pthread_cond_destroy(&execute
.condition_
); 
 133             pthread_mutex_destroy(&execute
.mutex_
); 
 135             const char *json(execute
.data_
); 
 136             size 
= json 
== NULL 
? _not(uint32_t) : strlen(json
); 
 138             if (!CYSendAll(socket_
, &size
, sizeof(size
))) 
 141                 if (!CYSendAll(socket_
, json
, size
)) 
 147 static void *OnClient(void *data
) { 
 148     CYClient 
*client(reinterpret_cast<CYClient 
*>(data
)); 
 154 void CYHandleClient(int socket
) { 
 155     // XXX: this leaks memory... really? 
 156     CYPool 
*pool(new CYPool()); 
 157     CYClient 
*client(new(*pool
) CYClient(socket
)); 
 158     _assert(pthread_create(&client
->thread_
, NULL
, &OnClient
, client
) == 0); 
 161 static void CYHandleSocket(const char *path
) { 
 162     int socket(_syscall(::socket(PF_UNIX
, SOCK_STREAM
, 0))); 
 164     struct sockaddr_un address
; 
 165     memset(&address
, 0, sizeof(address
)); 
 166     address
.sun_family 
= AF_UNIX
; 
 167     strcpy(address
.sun_path
, path
); 
 169     _syscall(connect(socket
, reinterpret_cast<sockaddr 
*>(&address
), sizeof(address
))); 
 171     CYInitializeDynamic(); 
 172     CYHandleClient(socket
); 
 175 _extern 
void CYHandleServer(pid_t pid
) { try { 
 177     sprintf(path
, "/tmp/.s.cy.%u", pid
); 
 178     CYHandleSocket(path
); 
 179 } catch (const CYException 
&error
) { 
 181     fprintf(stderr
, "%s\n", error
.PoolCString(pool
)); 
 184 _extern 
char *MSmain0(int argc
, char *argv
[]) { try { 
 186     CYHandleSocket(argv
[1]); 
 188     static void *handle(NULL
); 
 189     if (handle 
== NULL
) { 
 191         _assert(dladdr(reinterpret_cast<void *>(&MSmain0
), &info
) != 0); 
 193         handle 
= dlopen(info
.dli_fname
, 0); 
 195         handle 
= dlopen(info
.dli_fname
, RTLD_NOLOAD
); 
 200 } catch (const CYException 
&error
) { 
 202     return strdup(error
.PoolCString(pool
)); 
 210     CYServer(uint16_t port
) : 
 218             _syscall(close(socket_
)); 
 222         socket_ 
= _syscall(::socket(PF_INET
, SOCK_STREAM
, 0)); try { 
 224             _syscall(::setsockopt(socket_
, SOL_SOCKET
, SO_REUSEADDR
, &(value 
= 1), sizeof(value
))); 
 227             address
.sin_family 
= AF_INET
; 
 228             address
.sin_addr
.s_addr 
= INADDR_ANY
; 
 229             address
.sin_port 
= htons(port_
); 
 230             _syscall(::bind(socket_
, reinterpret_cast<sockaddr 
*>(&address
), sizeof(address
))); 
 232             _syscall(::listen(socket_
, -1)); 
 235                 socklen_t 
length(sizeof(address
)); 
 236                 int socket(_syscall(::accept(socket_
, reinterpret_cast<sockaddr 
*>(&address
), &length
))); 
 237                 CYHandleClient(socket
); 
 239         } catch (const CYException 
&error
) { 
 241             fprintf(stderr
, "%s\n", error
.PoolCString(pool
)); 
 246 static void *OnServer(void *data
) { 
 247     CYServer 
*server(reinterpret_cast<CYServer 
*>(data
)); 
 253 _extern 
void CYListenServer(short port
) { 
 254     CYInitializeDynamic(); 
 256     CYServer 
*server(new CYServer(port
)); 
 257     _assert(pthread_create(&server
->thread_
, NULL
, &OnServer
, server
) == 0);