]> git.saurik.com Git - cycript.git/blob - Handler.mm
Find location of libcycript at runtime with dladdr.
[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 "cycript.hpp"
23 #include "JavaScript.hpp"
24
25 #include "Pooling.hpp"
26 #include "Parser.hpp"
27
28 #include "Cycript.tab.hh"
29
30 #include <Foundation/Foundation.h>
31 #include <pthread.h>
32 #include <unistd.h>
33 #include <sstream>
34
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <sys/un.h>
39
40 struct CYExecute_ {
41 CYPool &pool_;
42 const char * volatile data_;
43 };
44
45 // XXX: this is "tre lame"
46 @interface CYClient_ : NSObject {
47 }
48
49 - (void) execute:(NSValue *)value;
50
51 @end
52
53 @implementation CYClient_
54
55 - (void) execute:(NSValue *)value {
56 CYExecute_ *execute(reinterpret_cast<CYExecute_ *>([value pointerValue]));
57 const char *data(execute->data_);
58 execute->data_ = NULL;
59 execute->data_ = CYExecute(execute->pool_, CYUTF8String(data));
60 }
61
62 @end
63
64 struct CYClient :
65 CYData
66 {
67 int socket_;
68 pthread_t thread_;
69
70 CYClient(int socket) :
71 socket_(socket)
72 {
73 }
74
75 ~CYClient() {
76 _syscall(close(socket_));
77 }
78
79 void Handle() {
80 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
81
82 CYClient_ *client = [[[CYClient_ alloc] init] autorelease];
83
84 bool dispatch;
85 if (CFStringRef mode = CFRunLoopCopyCurrentMode(CFRunLoopGetMain())) {
86 dispatch = true;
87 CFRelease(mode);
88 } else
89 dispatch = false;
90
91 for (;;) {
92 uint32_t size;
93 if (!CYRecvAll(socket_, &size, sizeof(size)))
94 return;
95
96 CYLocalPool pool;
97 char *data(new(pool) char[size + 1]);
98 if (!CYRecvAll(socket_, data, size))
99 return;
100 data[size] = '\0';
101
102 CYStream stream(data, data + size);
103 CYDriver driver(stream);
104
105 cy::parser parser(driver);
106
107 const char *json;
108 if (parser.parse() != 0 || !driver.errors_.empty()) {
109 json = NULL;
110 size = _not(uint32_t);
111 } else {
112 NSAutoreleasePool *ar = [[NSAutoreleasePool alloc] init];
113
114 CYOptions options;
115 CYContext context(options);
116 driver.program_->Replace(context);
117 std::ostringstream str;
118 CYOutput out(str, options);
119 out << *driver.program_;
120 std::string code(str.str());
121 CYExecute_ execute = {pool, code.c_str()};
122 NSValue *value([NSValue valueWithPointer:&execute]);
123 if (dispatch)
124 [client performSelectorOnMainThread:@selector(execute:) withObject:value waitUntilDone:YES];
125 else
126 [client execute:value];
127 json = execute.data_;
128 size = json == NULL ? _not(uint32_t) : strlen(json);
129
130 [ar release];
131 }
132
133 if (!CYSendAll(socket_, &size, sizeof(size)))
134 return;
135 if (json != NULL)
136 if (!CYSendAll(socket_, json, size))
137 return;
138 }
139
140 [pool release];
141 }
142 };
143
144 static void *OnClient(void *data) {
145 CYClient *client(reinterpret_cast<CYClient *>(data));
146 client->Handle();
147 delete client;
148 return NULL;
149 }
150
151 extern "C" void CYHandleClient(CYPool &pool, int socket) {
152 CYClient *client(new(pool) CYClient(socket));
153 _assert(pthread_create(&client->thread_, NULL, &OnClient, client) == 0);
154 }
155
156 extern "C" void CYHandleServer(pid_t pid) {
157 CYInitializeDynamic();
158
159 int socket(_syscall(::socket(PF_UNIX, SOCK_STREAM, 0))); try {
160 struct sockaddr_un address;
161 memset(&address, 0, sizeof(address));
162 address.sun_family = AF_UNIX;
163 sprintf(address.sun_path, "/tmp/.s.cy.%u", pid);
164
165 _syscall(connect(socket, reinterpret_cast<sockaddr *>(&address), SUN_LEN(&address)));
166
167 // XXX: this leaks memory... really?
168 CYHandleClient(*new CYPool(), socket);
169 } catch (const CYException &error) {
170 CYPool pool;
171 fprintf(stderr, "%s\n", error.PoolCString(pool));
172 }
173 }