]> git.saurik.com Git - cycript.git/blob - Handler.cpp
Unix domain sockets are often walled by sandboxes.
[cycript.git] / Handler.cpp
1 /* Cycript - The Truly Universal Scripting Language
2 * Copyright (C) 2009-2016 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 const char *CYHandleCommand(CYPool &pool, const std::string &code) {
64 bool dispatch;
65 #ifdef __APPLE__
66 CFRunLoopRef loop(CFRunLoopGetMain());
67 if (CFStringRef mode = CFRunLoopCopyCurrentMode(loop)) {
68 dispatch = true;
69 CFRelease(mode);
70 } else
71 #endif
72 dispatch = false;
73
74 CYExecute_ execute = {pool, code.c_str()};
75
76 pthread_mutex_init(&execute.mutex_, NULL);
77 pthread_cond_init(&execute.condition_, NULL);
78
79 if (!dispatch)
80 CYPerform(&execute);
81 #ifdef __APPLE__
82 else {
83 CFRunLoopSourceContext context;
84 memset(&context, 0, sizeof(context));
85 context.version = 0;
86 context.info = &execute;
87 context.perform = &CYPerform;
88
89 CFRunLoopSourceRef source(CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context));
90
91 pthread_mutex_lock(&execute.mutex_);
92
93 CFRunLoopAddSource(loop, source, kCFRunLoopCommonModes);
94 CFRunLoopSourceSignal(source);
95
96 CFRunLoopWakeUp(loop);
97 pthread_cond_wait(&execute.condition_, &execute.mutex_);
98 pthread_mutex_unlock(&execute.mutex_);
99
100 CFRunLoopRemoveSource(loop, source, kCFRunLoopCommonModes);
101 CFRelease(source);
102 }
103 #endif
104
105 pthread_cond_destroy(&execute.condition_);
106 pthread_mutex_destroy(&execute.mutex_);
107
108 return execute.data_;
109 }
110
111 struct CYClient :
112 CYData
113 {
114 int socket_;
115 pthread_t thread_;
116
117 CYClient(int socket) :
118 socket_(socket)
119 {
120 }
121
122 ~CYClient() {
123 _syscall(close(socket_));
124 }
125
126 void Handle() {
127 for (;;) {
128 uint32_t size;
129 if (!CYRecvAll(socket_, &size, sizeof(size)))
130 return;
131
132 CYLocalPool pool;
133 char *data(new(pool) char[size + 1]);
134 if (!CYRecvAll(socket_, data, size))
135 return;
136 data[size] = '\0';
137
138 std::string code(data, size);
139 const char *json(CYHandleCommand(pool, code));
140 size = json == NULL ? _not(uint32_t) : strlen(json);
141
142 if (!CYSendAll(socket_, &size, sizeof(size)))
143 return;
144 if (json != NULL)
145 if (!CYSendAll(socket_, json, size))
146 return;
147 }
148 }
149 };
150
151 static void *OnClient(void *data) {
152 CYClient *client(reinterpret_cast<CYClient *>(data));
153 client->Handle();
154 delete client;
155 return NULL;
156 }
157
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);
163 }
164
165 static void CYHandleSocket(const char *path) {
166 int socket(_syscall(::socket(PF_UNIX, SOCK_STREAM, 0)));
167
168 struct sockaddr_un address;
169 memset(&address, 0, sizeof(address));
170 address.sun_family = AF_UNIX;
171 strcpy(address.sun_path, path);
172
173 _syscall(connect(socket, reinterpret_cast<sockaddr *>(&address), sizeof(address)));
174
175 CYInitializeDynamic();
176 CYHandleClient(socket);
177 }
178
179 _extern void CYHandleServer(pid_t pid) { try {
180 char path[1024];
181 sprintf(path, "/tmp/.s.cy.%u", pid);
182 CYHandleSocket(path);
183 } catch (const CYException &error) {
184 CYPool pool;
185 fprintf(stderr, "%s\n", error.PoolCString(pool));
186 } }
187
188 _extern char *MSmain0(int argc, char *argv[]) { try {
189 char *error(NULL);
190
191 switch (argc) {
192 case 2:
193 CYHandleSocket(argv[1]);
194 break;
195
196 case 3:
197 if (false);
198 else if (strcmp(argv[1], "-e") == 0) {
199 CYPool pool;
200 error = strdup(CYHandleCommand(pool, argv[2]) ?: "");
201 } else _assert(false);
202 break;
203
204 default:
205 _assert(false);
206 }
207
208 static void *handle(NULL);
209 if (handle == NULL) {
210 Dl_info info;
211 _assert(dladdr(reinterpret_cast<void *>(&MSmain0), &info) != 0);
212 #ifdef __ANDROID__
213 handle = dlopen(info.dli_fname, 0);
214 #else
215 handle = dlopen(info.dli_fname, RTLD_NOLOAD);
216 #endif
217 }
218
219 return error;
220 } catch (const CYException &error) {
221 CYPool pool;
222 return strdup(error.PoolCString(pool));
223 } }
224
225 struct CYServer {
226 pthread_t thread_;
227 uint16_t port_;
228 int socket_;
229
230 CYServer(uint16_t port) :
231 port_(port),
232 socket_(-1)
233 {
234 }
235
236 ~CYServer() {
237 if (socket_ != -1)
238 _syscall(close(socket_));
239 }
240
241 void Listen() {
242 socket_ = _syscall(::socket(PF_INET, SOCK_STREAM, 0)); try {
243 int value;
244 _syscall(::setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &(value = 1), sizeof(value)));
245
246 sockaddr_in address;
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)));
251
252 _syscall(::listen(socket_, -1));
253
254 for (;;) {
255 socklen_t length(sizeof(address));
256 int socket(_syscall(::accept(socket_, reinterpret_cast<sockaddr *>(&address), &length)));
257 CYHandleClient(socket);
258 }
259 } catch (const CYException &error) {
260 CYPool pool;
261 fprintf(stderr, "%s\n", error.PoolCString(pool));
262 }
263 }
264 };
265
266 static void *OnServer(void *data) {
267 CYServer *server(reinterpret_cast<CYServer *>(data));
268 server->Listen();
269 delete server;
270 return NULL;
271 }
272
273 _extern void CYListenServer(short port) {
274 CYInitializeDynamic();
275
276 CYServer *server(new CYServer(port));
277 _assert(pthread_create(&server->thread_, NULL, &OnServer, server) == 0);
278 }