1 /* Cycript - Optimizing JavaScript Compiler/Runtime
2 * Copyright (C) 2009-2015 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
), SUN_LEN(&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);
192 handle
= dlopen(info
.dli_fname
, RTLD_NOLOAD
);
196 } catch (const CYException
&error
) {
198 return strdup(error
.PoolCString(pool
));
206 CYServer(uint16_t port
) :
214 _syscall(close(socket_
));
218 socket_
= _syscall(::socket(PF_INET
, SOCK_STREAM
, 0)); try {
220 _syscall(::setsockopt(socket_
, SOL_SOCKET
, SO_REUSEADDR
, &(value
= 1), sizeof(value
)));
223 address
.sin_family
= AF_INET
;
224 address
.sin_addr
.s_addr
= INADDR_ANY
;
225 address
.sin_port
= htons(port_
);
226 _syscall(::bind(socket_
, reinterpret_cast<sockaddr
*>(&address
), sizeof(address
)));
228 _syscall(::listen(socket_
, -1));
231 socklen_t
length(sizeof(address
));
232 int socket(_syscall(::accept(socket_
, reinterpret_cast<sockaddr
*>(&address
), &length
)));
233 CYHandleClient(socket
);
235 } catch (const CYException
&error
) {
237 fprintf(stderr
, "%s\n", error
.PoolCString(pool
));
242 static void *OnServer(void *data
) {
243 CYServer
*server(reinterpret_cast<CYServer
*>(data
));
249 _extern
void CYListenServer(short port
) {
250 CYInitializeDynamic();
252 CYServer
*server(new CYServer(port
));
253 _assert(pthread_create(&server
->thread_
, NULL
, &OnServer
, server
) == 0);