]> git.saurik.com Git - cycript.git/blob - Handler.mm
Provide a new ?destroy to release the JSContext.
[cycript.git] / Handler.mm
1 /* Cycript - Optimizing JavaScript Compiler/Runtime
2 * Copyright (C) 2009-2013 Jay Freeman (saurik)
3 */
4
5 /* GNU General Public License, Version 3 {{{ */
6 /*
7 * Cycript is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published
9 * by the Free Software Foundation, either version 3 of the License,
10 * or (at your option) any later version.
11 *
12 * Cycript is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with Cycript. If not, see <http://www.gnu.org/licenses/>.
19 **/
20 /* }}} */
21
22 #include <Foundation/Foundation.h>
23 #include <pthread.h>
24 #include <unistd.h>
25 #include <sstream>
26
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <sys/un.h>
31
32 #include "cycript.hpp"
33
34 #include "JavaScript.hpp"
35 #include "Parser.hpp"
36 #include "Pooling.hpp"
37
38 #include "Cycript.tab.hh"
39 #include "Driver.hpp"
40
41 struct CYExecute_ {
42 CYPool &pool_;
43 const char * volatile data_;
44 };
45
46 // XXX: this is "tre lame"
47 @interface CYClient_ : NSObject {
48 }
49
50 - (void) execute:(NSValue *)value;
51
52 @end
53
54 @implementation CYClient_
55
56 - (void) execute:(NSValue *)value {
57 CYExecute_ *execute(reinterpret_cast<CYExecute_ *>([value pointerValue]));
58 const char *data(execute->data_);
59 execute->data_ = NULL;
60 execute->data_ = CYExecute(CYGetJSContext(), execute->pool_, CYUTF8String(data));
61 }
62
63 @end
64
65 struct CYClient :
66 CYData
67 {
68 int socket_;
69 pthread_t thread_;
70
71 CYClient(int socket) :
72 socket_(socket)
73 {
74 }
75
76 ~CYClient() {
77 _syscall(close(socket_));
78 }
79
80 void Handle() {
81 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
82
83 CYClient_ *client = [[[CYClient_ alloc] init] autorelease];
84
85 bool dispatch;
86 if (CFStringRef mode = CFRunLoopCopyCurrentMode(CFRunLoopGetMain())) {
87 dispatch = true;
88 CFRelease(mode);
89 } else
90 dispatch = false;
91
92 for (;;) {
93 uint32_t size;
94 if (!CYRecvAll(socket_, &size, sizeof(size)))
95 return;
96
97 CYLocalPool pool;
98 char *data(new(pool) char[size + 1]);
99 if (!CYRecvAll(socket_, data, size))
100 return;
101 data[size] = '\0';
102
103 NSAutoreleasePool *ar = [[NSAutoreleasePool alloc] init];
104
105 std::string code(data, size);
106 CYExecute_ execute = {pool, code.c_str()};
107 NSValue *value([NSValue valueWithPointer:&execute]);
108 if (dispatch)
109 [client performSelectorOnMainThread:@selector(execute:) withObject:value waitUntilDone:YES];
110 else
111 [client execute:value];
112
113 const char *json(execute.data_);
114 size = json == NULL ? _not(uint32_t) : strlen(json);
115
116 [ar release];
117
118 if (!CYSendAll(socket_, &size, sizeof(size)))
119 return;
120 if (json != NULL)
121 if (!CYSendAll(socket_, json, size))
122 return;
123 }
124
125 [pool release];
126 }
127 };
128
129 static void *OnClient(void *data) {
130 CYClient *client(reinterpret_cast<CYClient *>(data));
131 client->Handle();
132 delete client;
133 return NULL;
134 }
135
136 extern "C" void CYHandleClient(int socket) {
137 // XXX: this leaks memory... really?
138 CYPool *pool(new CYPool());
139 CYClient *client(new(*pool) CYClient(socket));
140 _assert(pthread_create(&client->thread_, NULL, &OnClient, client) == 0);
141 }
142
143 extern "C" void CYHandleServer(pid_t pid, char *data, size_t size) {
144 CYInitializeDynamic();
145
146 int socket(_syscall(::socket(PF_UNIX, SOCK_STREAM, 0))); try {
147 struct sockaddr_un address;
148 memset(&address, 0, sizeof(address));
149 address.sun_family = AF_UNIX;
150 sprintf(address.sun_path, "/tmp/.s.cy.%u", pid);
151
152 _syscall(connect(socket, reinterpret_cast<sockaddr *>(&address), SUN_LEN(&address)));
153 CYHandleClient(socket);
154 } catch (const CYException &error) {
155 CYPool pool;
156 fprintf(stderr, "%s\n", error.PoolCString(pool));
157 }
158 }
159
160 struct CYServer {
161 pthread_t thread_;
162 uint16_t port_;
163 int socket_;
164
165 CYServer(uint16_t port) :
166 port_(port),
167 socket_(-1)
168 {
169 }
170
171 ~CYServer() {
172 if (socket_ != -1)
173 _syscall(close(socket_));
174 }
175
176 void Listen() {
177 socket_ = _syscall(::socket(PF_INET, SOCK_STREAM, 0)); try {
178 sockaddr_in address;
179 address.sin_family = AF_INET;
180 address.sin_addr.s_addr = INADDR_ANY;
181 address.sin_port = htons(port_);
182 _syscall(::bind(socket_, reinterpret_cast<sockaddr *>(&address), sizeof(address)));
183
184 _syscall(::listen(socket_, -1));
185
186 for (;;) {
187 socklen_t length(sizeof(address));
188 int socket(_syscall(::accept(socket_, reinterpret_cast<sockaddr *>(&address), &length)));
189 CYHandleClient(socket);
190 }
191 } catch (const CYException &error) {
192 CYPool pool;
193 fprintf(stderr, "%s\n", error.PoolCString(pool));
194 }
195 }
196 };
197
198 static void *OnServer(void *data) {
199 CYServer *server(reinterpret_cast<CYServer *>(data));
200 server->Listen();
201 delete server;
202 return NULL;
203 }
204
205 extern "C" void CYListenServer(short port) {
206 CYInitializeDynamic();
207
208 CYServer *server(new CYServer(port));
209 _assert(pthread_create(&server->thread_, NULL, &OnServer, server) == 0);
210 }