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/>.
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 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
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
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 _syscall(::setsockopt(socket_
, SOL_SOCKET
, SO_REUSEADDR
, &(value
= 1), sizeof(value
)));
225 address
.sin_family
= AF_INET
;
226 address
.sin_addr
.s_addr
= INADDR_ANY
;
227 address
.sin_port
= htons(port_
);
228 _syscall(::bind(socket_
, reinterpret_cast<sockaddr
*>(&address
), sizeof(address
)));
230 _syscall(::listen(socket_
, -1));
233 socklen_t
length(sizeof(address
));
234 int socket(_syscall(::accept(socket_
, reinterpret_cast<sockaddr
*>(&address
), &length
)));
235 CYHandleClient(socket
);
237 } catch (const CYException
&error
) {
239 fprintf(stderr
, "%s\n", error
.PoolCString(pool
));
244 static void *OnServer(void *data
) {
245 CYServer
*server(reinterpret_cast<CYServer
*>(data
));
251 _extern
void CYListenServer(short port
) {
252 CYInitializeDynamic();
254 CYServer
*server(new CYServer(port
));
255 _assert(pthread_create(&server
->thread_
, NULL
, &OnServer
, server
) == 0);