]> git.saurik.com Git - cycript.git/blob - Handler.cpp
Support Infinity (syntax highlighting and output).
[cycript.git] / Handler.cpp
1 /* Cycript - Optimizing JavaScript Compiler/Runtime
2 * Copyright (C) 2009-2015 Jay Freeman (saurik)
3 */
4
5 /* GNU Affero General Public License, Version 3 {{{ */
6 /*
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.
11
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.
16
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/>.
19 **/
20 /* }}} */
21
22 #include "cycript.hpp"
23
24 #include <dlfcn.h>
25 #include <pthread.h>
26 #include <unistd.h>
27 #include <sstream>
28
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <sys/un.h>
34
35 #ifdef __APPLE__
36 #include <CoreFoundation/CoreFoundation.h>
37 #endif
38
39 #include "Driver.hpp"
40 #include "JavaScript.hpp"
41 #include "Syntax.hpp"
42 #include "Pooling.hpp"
43
44 struct CYExecute_ {
45 CYPool &pool_;
46 const char * volatile data_;
47 pthread_mutex_t mutex_;
48 pthread_cond_t condition_;
49 };
50
51 void CYPerform(void *arg) {
52 CYExecute_ *execute(reinterpret_cast<CYExecute_ *>(arg));
53
54 const char *data(execute->data_);
55 execute->data_ = NULL;
56 execute->data_ = CYExecute(CYGetJSContext(), execute->pool_, CYUTF8String(data));
57
58 pthread_mutex_lock(&execute->mutex_);
59 pthread_cond_signal(&execute->condition_);
60 pthread_mutex_unlock(&execute->mutex_);
61 }
62
63 struct CYClient :
64 CYData
65 {
66 int socket_;
67 pthread_t thread_;
68
69 CYClient(int socket) :
70 socket_(socket)
71 {
72 }
73
74 ~CYClient() {
75 _syscall(close(socket_));
76 }
77
78 void Handle() {
79 bool dispatch;
80 #ifdef __APPLE__
81 CFRunLoopRef loop(CFRunLoopGetMain());
82 if (CFStringRef mode = CFRunLoopCopyCurrentMode(loop)) {
83 dispatch = true;
84 CFRelease(mode);
85 } else
86 #endif
87 dispatch = false;
88
89 for (;;) {
90 uint32_t size;
91 if (!CYRecvAll(socket_, &size, sizeof(size)))
92 return;
93
94 CYLocalPool pool;
95 char *data(new(pool) char[size + 1]);
96 if (!CYRecvAll(socket_, data, size))
97 return;
98 data[size] = '\0';
99
100 std::string code(data, size);
101 CYExecute_ execute = {pool, code.c_str()};
102
103 pthread_mutex_init(&execute.mutex_, NULL);
104 pthread_cond_init(&execute.condition_, NULL);
105
106 if (!dispatch)
107 CYPerform(&execute);
108 #ifdef __APPLE__
109 else {
110 CFRunLoopSourceContext context;
111 memset(&context, 0, sizeof(context));
112 context.version = 0;
113 context.info = &execute;
114 context.perform = &CYPerform;
115
116 CFRunLoopSourceRef source(CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context));
117
118 pthread_mutex_lock(&execute.mutex_);
119
120 CFRunLoopAddSource(loop, source, kCFRunLoopCommonModes);
121 CFRunLoopSourceSignal(source);
122
123 CFRunLoopWakeUp(loop);
124 pthread_cond_wait(&execute.condition_, &execute.mutex_);
125 pthread_mutex_unlock(&execute.mutex_);
126
127 CFRunLoopRemoveSource(loop, source, kCFRunLoopCommonModes);
128 CFRelease(source);
129 }
130 #endif
131
132 pthread_cond_destroy(&execute.condition_);
133 pthread_mutex_destroy(&execute.mutex_);
134
135 const char *json(execute.data_);
136 size = json == NULL ? _not(uint32_t) : strlen(json);
137
138 if (!CYSendAll(socket_, &size, sizeof(size)))
139 return;
140 if (json != NULL)
141 if (!CYSendAll(socket_, json, size))
142 return;
143 }
144 }
145 };
146
147 static void *OnClient(void *data) {
148 CYClient *client(reinterpret_cast<CYClient *>(data));
149 client->Handle();
150 delete client;
151 return NULL;
152 }
153
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);
159 }
160
161 static void CYHandleSocket(const char *path) {
162 int socket(_syscall(::socket(PF_UNIX, SOCK_STREAM, 0)));
163
164 struct sockaddr_un address;
165 memset(&address, 0, sizeof(address));
166 address.sun_family = AF_UNIX;
167 strcpy(address.sun_path, path);
168
169 _syscall(connect(socket, reinterpret_cast<sockaddr *>(&address), SUN_LEN(&address)));
170
171 CYInitializeDynamic();
172 CYHandleClient(socket);
173 }
174
175 _extern void CYHandleServer(pid_t pid) { try {
176 char path[1024];
177 sprintf(path, "/tmp/.s.cy.%u", pid);
178 CYHandleSocket(path);
179 } catch (const CYException &error) {
180 CYPool pool;
181 fprintf(stderr, "%s\n", error.PoolCString(pool));
182 } }
183
184 _extern char *MSmain0(int argc, char *argv[]) { try {
185 _assert(argc == 2);
186 CYHandleSocket(argv[1]);
187
188 static void *handle(NULL);
189 if (handle == NULL) {
190 Dl_info info;
191 _assert(dladdr(reinterpret_cast<void *>(&MSmain0), &info) != 0);
192 handle = dlopen(info.dli_fname, RTLD_NOLOAD);
193 }
194
195 return NULL;
196 } catch (const CYException &error) {
197 CYPool pool;
198 return strdup(error.PoolCString(pool));
199 } }
200
201 struct CYServer {
202 pthread_t thread_;
203 uint16_t port_;
204 int socket_;
205
206 CYServer(uint16_t port) :
207 port_(port),
208 socket_(-1)
209 {
210 }
211
212 ~CYServer() {
213 if (socket_ != -1)
214 _syscall(close(socket_));
215 }
216
217 void Listen() {
218 socket_ = _syscall(::socket(PF_INET, SOCK_STREAM, 0)); try {
219 int value;
220 _syscall(::setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &(value = 1), sizeof(value)));
221
222 sockaddr_in address;
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)));
227
228 _syscall(::listen(socket_, -1));
229
230 for (;;) {
231 socklen_t length(sizeof(address));
232 int socket(_syscall(::accept(socket_, reinterpret_cast<sockaddr *>(&address), &length)));
233 CYHandleClient(socket);
234 }
235 } catch (const CYException &error) {
236 CYPool pool;
237 fprintf(stderr, "%s\n", error.PoolCString(pool));
238 }
239 }
240 };
241
242 static void *OnServer(void *data) {
243 CYServer *server(reinterpret_cast<CYServer *>(data));
244 server->Listen();
245 delete server;
246 return NULL;
247 }
248
249 _extern void CYListenServer(short port) {
250 CYInitializeDynamic();
251
252 CYServer *server(new CYServer(port));
253 _assert(pthread_create(&server->thread_, NULL, &OnServer, server) == 0);
254 }