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_
);
63 const char *CYHandleCommand(CYPool
&pool
, const std::string
&code
) {
66 CFRunLoopRef
loop(CFRunLoopGetMain());
67 if (CFStringRef mode
= CFRunLoopCopyCurrentMode(loop
)) {
74 CYExecute_ execute
= {pool
, code
.c_str()};
76 pthread_mutex_init(&execute
.mutex_
, NULL
);
77 pthread_cond_init(&execute
.condition_
, NULL
);
83 CFRunLoopSourceContext context
;
84 memset(&context
, 0, sizeof(context
));
86 context
.info
= &execute
;
87 context
.perform
= &CYPerform
;
89 CFRunLoopSourceRef
source(CFRunLoopSourceCreate(kCFAllocatorDefault
, 0, &context
));
91 pthread_mutex_lock(&execute
.mutex_
);
93 CFRunLoopAddSource(loop
, source
, kCFRunLoopCommonModes
);
94 CFRunLoopSourceSignal(source
);
96 CFRunLoopWakeUp(loop
);
97 pthread_cond_wait(&execute
.condition_
, &execute
.mutex_
);
98 pthread_mutex_unlock(&execute
.mutex_
);
100 CFRunLoopRemoveSource(loop
, source
, kCFRunLoopCommonModes
);
105 pthread_cond_destroy(&execute
.condition_
);
106 pthread_mutex_destroy(&execute
.mutex_
);
108 return execute
.data_
;
117 CYClient(int socket
) :
123 _syscall(close(socket_
));
129 if (!CYRecvAll(socket_
, &size
, sizeof(size
)))
133 char *data(new(pool
) char[size
+ 1]);
134 if (!CYRecvAll(socket_
, data
, size
))
138 std::string
code(data
, size
);
139 const char *json(CYHandleCommand(pool
, code
));
140 size
= json
== NULL
? _not(uint32_t) : strlen(json
);
142 if (!CYSendAll(socket_
, &size
, sizeof(size
)))
145 if (!CYSendAll(socket_
, json
, size
))
151 static void *OnClient(void *data
) {
152 CYClient
*client(reinterpret_cast<CYClient
*>(data
));
158 void CYHandleClient(int socket
) {
159 // XXX: this leaks memory... really?
160 CYPool
*pool(new CYPool());
161 CYClient
*client(new(*pool
) CYClient(socket
));
162 _assert(pthread_create(&client
->thread_
, NULL
, &OnClient
, client
) == 0);
165 static void CYHandleSocket(const char *path
) {
166 int socket(_syscall(::socket(PF_UNIX
, SOCK_STREAM
, 0)));
168 struct sockaddr_un address
;
169 memset(&address
, 0, sizeof(address
));
170 address
.sun_family
= AF_UNIX
;
171 strcpy(address
.sun_path
, path
);
173 _syscall(connect(socket
, reinterpret_cast<sockaddr
*>(&address
), sizeof(address
)));
175 CYInitializeDynamic();
176 CYHandleClient(socket
);
179 _extern
void CYHandleServer(pid_t pid
) { try {
181 sprintf(path
, "/tmp/.s.cy.%u", pid
);
182 CYHandleSocket(path
);
183 } catch (const CYException
&error
) {
185 fprintf(stderr
, "%s\n", error
.PoolCString(pool
));
188 _extern
char *MSmain0(int argc
, char *argv
[]) { try {
193 CYHandleSocket(argv
[1]);
198 else if (strcmp(argv
[1], "-e") == 0) {
200 error
= strdup(CYHandleCommand(pool
, argv
[2]) ?: "");
201 } else _assert(false);
208 static void *handle(NULL
);
209 if (handle
== NULL
) {
211 _assert(dladdr(reinterpret_cast<void *>(&MSmain0
), &info
) != 0);
213 handle
= dlopen(info
.dli_fname
, 0);
215 handle
= dlopen(info
.dli_fname
, RTLD_NOLOAD
);
220 } catch (const CYException
&error
) {
222 return strdup(error
.PoolCString(pool
));
230 CYServer(uint16_t port
) :
238 _syscall(close(socket_
));
242 socket_
= _syscall(::socket(PF_INET
, SOCK_STREAM
, 0)); try {
244 _syscall(::setsockopt(socket_
, SOL_SOCKET
, SO_REUSEADDR
, &(value
= 1), sizeof(value
)));
247 address
.sin_family
= AF_INET
;
248 address
.sin_addr
.s_addr
= INADDR_ANY
;
249 address
.sin_port
= htons(port_
);
250 _syscall(::bind(socket_
, reinterpret_cast<sockaddr
*>(&address
), sizeof(address
)));
252 _syscall(::listen(socket_
, -1));
255 socklen_t
length(sizeof(address
));
256 int socket(_syscall(::accept(socket_
, reinterpret_cast<sockaddr
*>(&address
), &length
)));
257 CYHandleClient(socket
);
259 } catch (const CYException
&error
) {
261 fprintf(stderr
, "%s\n", error
.PoolCString(pool
));
266 static void *OnServer(void *data
) {
267 CYServer
*server(reinterpret_cast<CYServer
*>(data
));
273 _extern
void CYListenServer(short port
) {
274 CYInitializeDynamic();
276 CYServer
*server(new CYServer(port
));
277 _assert(pthread_create(&server
->thread_
, NULL
, &OnServer
, server
) == 0);