]> git.saurik.com Git - cycript.git/blob - Handler.mm
ebd96b9031c3c57de84ef110455c464144a5c974
[cycript.git] / Handler.mm
1 /* Cycript - Optimizing JavaScript Compiler/Runtime
2 * Copyright (C) 2009-2014 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 <Foundation/Foundation.h>
23 #include <dlfcn.h>
24 #include <pthread.h>
25 #include <unistd.h>
26 #include <sstream>
27
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <sys/un.h>
32
33 #include "cycript.hpp"
34
35 #include "JavaScript.hpp"
36 #include "Parser.hpp"
37 #include "Pooling.hpp"
38
39 #include "Cycript.tab.hh"
40 #include "Driver.hpp"
41
42 struct CYExecute_ {
43 CYPool &pool_;
44 const char * volatile data_;
45 };
46
47 // XXX: this is "tre lame"
48 @interface CYClient_ : NSObject {
49 }
50
51 - (void) execute:(NSValue *)value;
52
53 @end
54
55 @implementation CYClient_
56
57 - (void) execute:(NSValue *)value {
58 CYExecute_ *execute(reinterpret_cast<CYExecute_ *>([value pointerValue]));
59 const char *data(execute->data_);
60 execute->data_ = NULL;
61 execute->data_ = CYExecute(CYGetJSContext(), execute->pool_, CYUTF8String(data));
62 }
63
64 @end
65
66 struct CYClient :
67 CYData
68 {
69 int socket_;
70 pthread_t thread_;
71
72 CYClient(int socket) :
73 socket_(socket)
74 {
75 }
76
77 ~CYClient() {
78 _syscall(close(socket_));
79 }
80
81 void Handle() {
82 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
83
84 CYClient_ *client = [[[CYClient_ alloc] init] autorelease];
85
86 bool dispatch;
87 if (CFStringRef mode = CFRunLoopCopyCurrentMode(CFRunLoopGetMain())) {
88 dispatch = true;
89 CFRelease(mode);
90 } else
91 dispatch = false;
92
93 for (;;) {
94 uint32_t size;
95 if (!CYRecvAll(socket_, &size, sizeof(size)))
96 return;
97
98 CYLocalPool pool;
99 char *data(new(pool) char[size + 1]);
100 if (!CYRecvAll(socket_, data, size))
101 return;
102 data[size] = '\0';
103
104 NSAutoreleasePool *ar = [[NSAutoreleasePool alloc] init];
105
106 std::string code(data, size);
107 CYExecute_ execute = {pool, code.c_str()};
108 NSValue *value([NSValue valueWithPointer:&execute]);
109 if (dispatch)
110 [client performSelectorOnMainThread:@selector(execute:) withObject:value waitUntilDone:YES];
111 else
112 [client execute:value];
113
114 const char *json(execute.data_);
115 size = json == NULL ? _not(uint32_t) : strlen(json);
116
117 [ar release];
118
119 if (!CYSendAll(socket_, &size, sizeof(size)))
120 return;
121 if (json != NULL)
122 if (!CYSendAll(socket_, json, size))
123 return;
124 }
125
126 [pool release];
127 }
128 };
129
130 static void *OnClient(void *data) {
131 CYClient *client(reinterpret_cast<CYClient *>(data));
132 client->Handle();
133 delete client;
134 return NULL;
135 }
136
137 extern "C" void CYHandleClient(int socket) {
138 // XXX: this leaks memory... really?
139 CYPool *pool(new CYPool());
140 CYClient *client(new(*pool) CYClient(socket));
141 _assert(pthread_create(&client->thread_, NULL, &OnClient, client) == 0);
142 }
143
144 static void CYHandleProcess(pid_t pid) {
145 CYInitializeDynamic();
146
147 int socket(_syscall(::socket(PF_UNIX, SOCK_STREAM, 0)));
148
149 struct sockaddr_un address;
150 memset(&address, 0, sizeof(address));
151 address.sun_family = AF_UNIX;
152 sprintf(address.sun_path, "/tmp/.s.cy.%u", pid);
153
154 _syscall(connect(socket, reinterpret_cast<sockaddr *>(&address), SUN_LEN(&address)));
155 CYHandleClient(socket);
156 }
157
158 extern "C" void CYHandleServer(pid_t pid) { try {
159 CYHandleProcess(pid);
160 } catch (const CYException &error) {
161 CYPool pool;
162 fprintf(stderr, "%s\n", error.PoolCString(pool));
163 } }
164
165 extern "C" char *MSmain0(int argc, char *argv[]) { try {
166 _assert(argc == 2);
167 auto arg(argv[1]);
168
169 char *end;
170 pid_t pid(strtoul(arg, &end, 10));
171 _assert(end == arg + strlen(arg));
172
173 static void *handle(NULL);
174 if (handle == NULL) {
175 Dl_info info;
176 _assert(dladdr(reinterpret_cast<void *>(&MSmain0), &info) != 0);
177 handle = dlopen(info.dli_fname, RTLD_NOLOAD);
178 }
179
180 CYHandleProcess(pid);
181
182 return NULL;
183 } catch (const CYException &error) {
184 CYPool pool;
185 return strdup(error.PoolCString(pool));
186 } }
187
188 struct CYServer {
189 pthread_t thread_;
190 uint16_t port_;
191 int socket_;
192
193 CYServer(uint16_t port) :
194 port_(port),
195 socket_(-1)
196 {
197 }
198
199 ~CYServer() {
200 if (socket_ != -1)
201 _syscall(close(socket_));
202 }
203
204 void Listen() {
205 socket_ = _syscall(::socket(PF_INET, SOCK_STREAM, 0)); try {
206 sockaddr_in address;
207 address.sin_family = AF_INET;
208 address.sin_addr.s_addr = INADDR_ANY;
209 address.sin_port = htons(port_);
210 _syscall(::bind(socket_, reinterpret_cast<sockaddr *>(&address), sizeof(address)));
211
212 _syscall(::listen(socket_, -1));
213
214 for (;;) {
215 socklen_t length(sizeof(address));
216 int socket(_syscall(::accept(socket_, reinterpret_cast<sockaddr *>(&address), &length)));
217 CYHandleClient(socket);
218 }
219 } catch (const CYException &error) {
220 CYPool pool;
221 fprintf(stderr, "%s\n", error.PoolCString(pool));
222 }
223 }
224 };
225
226 static void *OnServer(void *data) {
227 CYServer *server(reinterpret_cast<CYServer *>(data));
228 server->Listen();
229 delete server;
230 return NULL;
231 }
232
233 extern "C" void CYListenServer(short port) {
234 CYInitializeDynamic();
235
236 CYServer *server(new CYServer(port));
237 _assert(pthread_create(&server->thread_, NULL, &OnServer, server) == 0);
238 }