]> git.saurik.com Git - cycript.git/blame - Handler.mm
Allow for connections from the client to the server.
[cycript.git] / Handler.mm
CommitLineData
b3378a02 1/* Cycript - Optimizing JavaScript Compiler/Runtime
c15969fd 2 * Copyright (C) 2009-2013 Jay Freeman (saurik)
b24eb750
JF
3*/
4
c15969fd 5/* GNU General Public License, Version 3 {{{ */
b24eb750 6/*
c15969fd
JF
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.
b24eb750 11 *
c15969fd
JF
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.
b24eb750 16 *
c15969fd 17 * You should have received a copy of the GNU General Public License
b3378a02
JF
18 * along with Cycript. If not, see <http://www.gnu.org/licenses/>.
19**/
b24eb750
JF
20/* }}} */
21
b24eb750 22#include <Foundation/Foundation.h>
63129b67 23#include <pthread.h>
b24eb750
JF
24#include <unistd.h>
25#include <sstream>
26
bb1c419c
JF
27#include <sys/types.h>
28#include <sys/socket.h>
29#include <netinet/in.h>
30#include <sys/un.h>
31
b12a9965
JF
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
b24eb750 41struct CYExecute_ {
b799113b 42 CYPool &pool_;
b24eb750
JF
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;
0ced2e47 60 execute->data_ = CYExecute(execute->pool_, CYUTF8String(data));
b24eb750
JF
61}
62
63@end
64
65struct CYClient :
66 CYData
67{
68 int socket_;
63129b67 69 pthread_t thread_;
b24eb750
JF
70
71 CYClient(int socket) :
72 socket_(socket)
73 {
74 }
75
76 ~CYClient() {
77 _syscall(close(socket_));
78 }
79
37954781 80 void Handle() {
d3760804
JF
81 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
82
83 CYClient_ *client = [[[CYClient_ alloc] init] autorelease];
b24eb750 84
bb1c419c
JF
85 bool dispatch;
86 if (CFStringRef mode = CFRunLoopCopyCurrentMode(CFRunLoopGetMain())) {
87 dispatch = true;
88 CFRelease(mode);
89 } else
90 dispatch = false;
91
b24eb750 92 for (;;) {
9d79cefc 93 uint32_t size;
b24eb750
JF
94 if (!CYRecvAll(socket_, &size, sizeof(size)))
95 return;
96
97f6a005 97 CYLocalPool pool;
b24eb750
JF
98 char *data(new(pool) char[size + 1]);
99 if (!CYRecvAll(socket_, data, size))
100 return;
101 data[size] = '\0';
102
d3b63265
JF
103 CYStream stream(data, data + size);
104 CYDriver driver(stream);
b24eb750 105
d3b63265 106 cy::parser parser(driver);
b24eb750
JF
107
108 const char *json;
109 if (parser.parse() != 0 || !driver.errors_.empty()) {
110 json = NULL;
9d79cefc 111 size = _not(uint32_t);
b24eb750 112 } else {
bb1c419c
JF
113 NSAutoreleasePool *ar = [[NSAutoreleasePool alloc] init];
114
69688ca1 115 CYOptions options;
97f6a005 116 CYContext context(options);
b24eb750
JF
117 driver.program_->Replace(context);
118 std::ostringstream str;
69688ca1 119 CYOutput out(str, options);
b24eb750
JF
120 out << *driver.program_;
121 std::string code(str.str());
122 CYExecute_ execute = {pool, code.c_str()};
bb1c419c
JF
123 NSValue *value([NSValue valueWithPointer:&execute]);
124 if (dispatch)
125 [client performSelectorOnMainThread:@selector(execute:) withObject:value waitUntilDone:YES];
126 else
127 [client execute:value];
b24eb750 128 json = execute.data_;
9d79cefc 129 size = json == NULL ? _not(uint32_t) : strlen(json);
bb1c419c
JF
130
131 [ar release];
b24eb750
JF
132 }
133
134 if (!CYSendAll(socket_, &size, sizeof(size)))
135 return;
136 if (json != NULL)
137 if (!CYSendAll(socket_, json, size))
138 return;
139 }
37954781 140
d3760804 141 [pool release];
b24eb750
JF
142 }
143};
144
0cbeddf8 145static void *OnClient(void *data) {
b24eb750
JF
146 CYClient *client(reinterpret_cast<CYClient *>(data));
147 client->Handle();
148 delete client;
149 return NULL;
150}
151
3429e25c
JF
152extern "C" void CYHandleClient(int socket) {
153 // XXX: this leaks memory... really?
154 CYPool *pool(new CYPool());
155 CYClient *client(new(*pool) CYClient(socket));
63129b67 156 _assert(pthread_create(&client->thread_, NULL, &OnClient, client) == 0);
b24eb750 157}
994434e5
JF
158
159extern "C" void CYHandleServer(pid_t pid) {
09eee478 160 CYInitializeDynamic();
994434e5
JF
161
162 int socket(_syscall(::socket(PF_UNIX, SOCK_STREAM, 0))); try {
163 struct sockaddr_un address;
164 memset(&address, 0, sizeof(address));
165 address.sun_family = AF_UNIX;
166 sprintf(address.sun_path, "/tmp/.s.cy.%u", pid);
167
168 _syscall(connect(socket, reinterpret_cast<sockaddr *>(&address), SUN_LEN(&address)));
3429e25c 169 CYHandleClient(socket);
994434e5
JF
170 } catch (const CYException &error) {
171 CYPool pool;
172 fprintf(stderr, "%s\n", error.PoolCString(pool));
173 }
174}
666eedb9
JF
175
176struct CYServer {
177 pthread_t thread_;
178 uint16_t port_;
179 int socket_;
180
181 CYServer(uint16_t port) :
182 port_(port),
183 socket_(-1)
184 {
185 }
186
187 ~CYServer() {
188 if (socket_ != -1)
189 _syscall(close(socket_));
190 }
191
192 void Listen() {
193 socket_ = _syscall(::socket(PF_INET, SOCK_STREAM, 0)); try {
194 sockaddr_in address;
195 address.sin_family = AF_INET;
196 address.sin_addr.s_addr = INADDR_ANY;
197 address.sin_port = htons(port_);
198 _syscall(::bind(socket_, reinterpret_cast<sockaddr *>(&address), sizeof(address)));
199
200 _syscall(::listen(socket_, -1));
201
202 for (;;) {
203 socklen_t length(sizeof(address));
204 int socket(_syscall(::accept(socket_, reinterpret_cast<sockaddr *>(&address), &length)));
205 CYHandleClient(socket);
206 }
207 } catch (const CYException &error) {
208 CYPool pool;
209 fprintf(stderr, "%s\n", error.PoolCString(pool));
210 }
211 }
212};
213
214static void *OnServer(void *data) {
215 CYServer *server(reinterpret_cast<CYServer *>(data));
216 server->Listen();
217 delete server;
218 return NULL;
219}
220
221extern "C" void CYListenServer(short port) {
222 CYInitializeDynamic();
223
224 CYServer *server(new CYServer(port));
225 _assert(pthread_create(&server->thread_, NULL, &OnServer, server) == 0);
226}