]> git.saurik.com Git - cycript.git/blame_incremental - Server.mm
Improved lexical syntax errors and added not-isatty detection for selecting the parse...
[cycript.git] / Server.mm
... / ...
CommitLineData
1/* Cycript - Remove Execution Server and Disassembler
2 * Copyright (C) 2009 Jay Freeman (saurik)
3*/
4
5/* Modified BSD License {{{ */
6/*
7 * Redistribution and use in source and binary
8 * forms, with or without modification, are permitted
9 * provided that the following conditions are met:
10 *
11 * 1. Redistributions of source code must retain the
12 * above copyright notice, this list of conditions
13 * and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the
15 * above copyright notice, this list of conditions
16 * and the following disclaimer in the documentation
17 * and/or other materials provided with the
18 * distribution.
19 * 3. The name of the author may not be used to endorse
20 * or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
25 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
34 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
36 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37*/
38/* }}} */
39
40#include <CFNetwork/CFNetwork.h>
41
42struct Client {
43 CFHTTPMessageRef message_;
44 CFSocketRef socket_;
45};
46
47static void OnData(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *value, void *info) {
48 switch (type) {
49 case kCFSocketDataCallBack:
50 CFDataRef data(reinterpret_cast<CFDataRef>(value));
51 Client *client(reinterpret_cast<Client *>(info));
52
53 if (client->message_ == NULL)
54 client->message_ = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, TRUE);
55
56 if (!CFHTTPMessageAppendBytes(client->message_, CFDataGetBytePtr(data), CFDataGetLength(data)))
57 CFLog(kCFLogLevelError, CFSTR("CFHTTPMessageAppendBytes()"));
58 else if (CFHTTPMessageIsHeaderComplete(client->message_)) {
59 CFURLRef url(CFHTTPMessageCopyRequestURL(client->message_));
60 Boolean absolute;
61 CFStringRef path(CFURLCopyStrictPath(url, &absolute));
62 CFRelease(client->message_);
63
64 CFStringRef code(CFURLCreateStringByReplacingPercentEscapes(kCFAllocatorDefault, path, CFSTR("")));
65 CFRelease(path);
66
67 JSStringRef script(JSStringCreateWithCFString(code));
68 CFRelease(code);
69
70 JSValueRef result(JSEvaluateScript(CYGetJSContext(), script, NULL, NULL, 0, NULL));
71 JSStringRelease(script);
72
73 CFHTTPMessageRef response(CFHTTPMessageCreateResponse(kCFAllocatorDefault, 200, NULL, kCFHTTPVersion1_1));
74 CFHTTPMessageSetHeaderFieldValue(response, CFSTR("Content-Type"), CFSTR("application/json; charset=utf-8"));
75
76 CFStringRef json(CYCopyJSONString(CYGetJSContext(), result, NULL));
77 CFDataRef body(CFStringCreateExternalRepresentation(kCFAllocatorDefault, json, kCFStringEncodingUTF8, NULL));
78 CFRelease(json);
79
80 CFStringRef length(CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%u"), CFDataGetLength(body)));
81 CFHTTPMessageSetHeaderFieldValue(response, CFSTR("Content-Length"), length);
82 CFRelease(length);
83
84 CFHTTPMessageSetBody(response, body);
85 CFRelease(body);
86
87 CFDataRef serialized(CFHTTPMessageCopySerializedMessage(response));
88 CFRelease(response);
89
90 CFSocketSendData(socket, NULL, serialized, 0);
91 CFRelease(serialized);
92
93 CFRelease(url);
94 }
95 break;
96 }
97}
98
99static void OnAccept(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *value, void *info) {
100 switch (type) {
101 case kCFSocketAcceptCallBack:
102 Client *client(new Client());
103
104 client->message_ = NULL;
105
106 CFSocketContext context;
107 context.version = 0;
108 context.info = client;
109 context.retain = NULL;
110 context.release = NULL;
111 context.copyDescription = NULL;
112
113 client->socket_ = CFSocketCreateWithNative(kCFAllocatorDefault, *reinterpret_cast<const CFSocketNativeHandle *>(value), kCFSocketDataCallBack, &OnData, &context);
114
115 CFRunLoopAddSource(CFRunLoopGetCurrent(), CFSocketCreateRunLoopSource(kCFAllocatorDefault, client->socket_, 0), kCFRunLoopDefaultMode);
116 break;
117 }
118}
119
120MSInitialize {
121 pid_t pid(getpid());
122
123 struct sockaddr_in address;
124 address.sin_len = sizeof(address);
125 address.sin_family = AF_INET;
126 address.sin_addr.s_addr = INADDR_ANY;
127 address.sin_port = htons(10000 + pid);
128
129 CFDataRef data(CFDataCreate(kCFAllocatorDefault, reinterpret_cast<UInt8 *>(&address), sizeof(address)));
130
131 CFSocketSignature signature;
132 signature.protocolFamily = AF_INET;
133 signature.socketType = SOCK_STREAM;
134 signature.protocol = IPPROTO_TCP;
135 signature.address = data;
136
137 CFSocketRef socket(CFSocketCreateWithSocketSignature(kCFAllocatorDefault, &signature, kCFSocketAcceptCallBack, &OnAccept, NULL));
138 CFRunLoopAddSource(CFRunLoopGetCurrent(), CFSocketCreateRunLoopSource(kCFAllocatorDefault, socket, 0), kCFRunLoopDefaultMode);
139}