Created
October 31, 2010 18:18
-
-
Save DylanLukes/656934 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// MHProxy.m | |
// MineHelmet | |
// | |
// Created by Dylan Lukes on 10/24/10. | |
// Copyright 2010 Dylan Lukes. All rights reserved. | |
// | |
#import "MHProxy.h" | |
#import "sys/socket.h" | |
#import "netdb.h" | |
#define MAX_DATA_SIZE 1024 | |
@interface MHProxy (PrivateMethods) | |
- (void)handleClientInputEvent:(NSStreamEvent)event; | |
- (void)handleClientOutputEvent:(NSStreamEvent)event; | |
- (void)handleServerInputEvent:(NSStreamEvent)event; | |
- (void)handleServerOutputEvent:(NSStreamEvent)event; | |
@end | |
@implementation MHProxy | |
- (id)initWithClientDescriptor:(int)clientfd serverDescriptor:(int)serverfd { | |
if (self = [super init]) { | |
struct sockaddr sa; | |
socklen_t sa_len = sizeof(sa); | |
getpeername(clientfd, &sa, &sa_len); | |
char host[NI_MAXHOST], serv[NI_MAXSERV]; | |
getnameinfo(&sa, sa_len, host, NI_MAXHOST, serv, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV); | |
NSLog(@"HOST: %s SERV: %s", host, serv); | |
sa_len = sizeof(sa); | |
getpeername(serverfd, &sa, &sa_len); | |
getnameinfo(&sa, sa_len, host, NI_MAXHOST, serv, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV); | |
NSLog(@"HOST: %s SERV: %s", host, serv); | |
clientDataQueue = [[DataQueue alloc] init]; | |
serverDataQueue = [[DataQueue alloc] init]; | |
CFStreamCreatePairWithSocket(NULL, | |
clientfd, | |
(CFReadStreamRef *)&fromClient, | |
(CFWriteStreamRef *)&toClient); | |
CFStreamCreatePairWithSocket(NULL, | |
serverfd, | |
(CFReadStreamRef *)&fromServer, | |
(CFWriteStreamRef *)&toServer); | |
[fromClient setDelegate:self]; | |
[toClient setDelegate:self]; | |
[fromServer setDelegate:self]; | |
[toServer setDelegate:self]; | |
[fromClient scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; | |
[toClient scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; | |
[fromServer scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; | |
[toServer scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; | |
if ([fromClient streamStatus] == NSStreamStatusNotOpen) | |
[fromClient open]; | |
if ([toClient streamStatus] == NSStreamStatusNotOpen) | |
[toClient open]; | |
if ([fromServer streamStatus] == NSStreamStatusNotOpen) | |
[fromServer open]; | |
if ([toServer streamStatus] == NSStreamStatusNotOpen) | |
[toServer open]; | |
int flags = fcntl(clientfd ,F_GETFL); | |
if (flags & O_NONBLOCK) | |
fcntl(clientfd, F_SETFL, flags & ~O_NONBLOCK); | |
flags = fcntl(serverfd ,F_GETFL); | |
if (flags & O_NONBLOCK) | |
fcntl(serverfd, F_SETFL, flags & ~O_NONBLOCK); | |
} | |
return self; | |
} | |
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)streamEvent { | |
// Check for errors: | |
if (streamEvent == NSStreamEventErrorOccurred) { | |
[NSApp presentError:[stream streamError]]; | |
goto Failure; | |
} | |
if (streamEvent == NSStreamEventEndEncountered) { | |
NSLog(@"End of %@ reached", stream); | |
goto Failure; | |
} | |
// Dispatch events | |
if (stream == fromClient && streamEvent == NSStreamEventHasBytesAvailable) { | |
NSLog(@"1"); | |
[self handleClientInputEvent:streamEvent]; | |
} | |
if (stream == fromServer && streamEvent == NSStreamEventHasBytesAvailable) { | |
NSLog(@"2"); | |
[self handleServerInputEvent:streamEvent]; | |
} | |
if (stream == toClient && streamEvent == NSStreamEventHasSpaceAvailable) { | |
NSLog(@"3"); | |
[self handleClientOutputEvent:streamEvent]; | |
} | |
if (stream == toServer && streamEvent == NSStreamEventHasSpaceAvailable) { | |
NSLog(@"4"); | |
[self handleServerOutputEvent:streamEvent]; | |
} | |
Failure: | |
[fromClient close]; | |
[fromServer close]; | |
[toClient close]; | |
[toServer close]; | |
CFRunLoopStop(CFRunLoopGetCurrent()); | |
} | |
- (void)handleClientInputEvent:(NSStreamEvent)event{ | |
uint8_t bytes[MAX_DATA_SIZE]; | |
NSInteger bytesRead = [fromClient read:bytes maxLength:MAX_DATA_SIZE]; | |
if (bytesRead == -1) { | |
return; | |
} | |
[serverDataQueue enqueueBytes:bytes length:bytesRead]; | |
} | |
- (void)handleClientOutputEvent:(NSStreamEvent)event{ | |
const void *bytes; | |
NSUInteger length; | |
NSInteger bytesWritten; | |
[clientDataQueue peekBytes:&bytes length:&length]; | |
if (length > 0) { | |
bytesWritten = [toClient write:bytes maxLength:length]; | |
[clientDataQueue dequeueBytes:bytesWritten]; | |
} | |
} | |
- (void)handleServerInputEvent:(NSStreamEvent)event{ | |
uint8_t bytes[MAX_DATA_SIZE]; | |
NSInteger bytesRead = [fromClient read:bytes maxLength:MAX_DATA_SIZE]; | |
if (bytesRead == -1) { | |
return; | |
} | |
[clientDataQueue enqueueBytes:bytes length:bytesRead]; | |
} | |
- (void)handleServerOutputEvent:(NSStreamEvent)event{ | |
const void *bytes; | |
NSUInteger length; | |
NSInteger bytesWritten; | |
[serverDataQueue peekBytes:&bytes length:&length]; | |
if (length > 0) { | |
bytesWritten = [toServer write:bytes maxLength:length]; | |
[serverDataQueue dequeueBytes:bytesWritten]; | |
} | |
} | |
- (void)dealloc { | |
[toClient release]; | |
[fromClient release]; | |
[toServer release]; | |
[fromServer release]; | |
[clientDataQueue release]; | |
[serverDataQueue release]; | |
[super dealloc]; | |
} | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// MHProxyFactory.m | |
// MineHelmet | |
// | |
// Created by Dylan Lukes on 10/22/10. | |
// Copyright 2010 Dylan Lukes. All rights reserved. | |
// | |
#import "MHProxyManager.h" | |
#import "APELite.h" | |
#include <sys/socket.h> | |
#include <netinet/in.h> | |
#include <netdb.h> | |
typedef struct{ | |
int client; | |
int server; | |
} MHProxyDescriptorPair; | |
@interface MHProxyManager (PrivateMethods) | |
- (int)handleConnectAttempt:(int)socket addr:(const struct sockaddr *)addr addrlen:(socklen_t)addrlen; | |
- (void)proxyThreadMain:(NSValue *)pairValue; | |
@end | |
static MHProxyManager *instance_pointer; | |
static int connect_override(int socket, const struct sockaddr *address, socklen_t addrlen){ | |
return [instance_pointer handleConnectAttempt:socket addr:address addrlen:addrlen]; | |
} | |
@implementation MHProxyManager | |
+ (id)sharedInstance { | |
static dispatch_once_t pred; | |
static MHProxyManager *instance = nil; | |
dispatch_once(&pred, ^{ instance = [[self alloc] init]; }); | |
return instance; | |
} | |
- (id)init { | |
if (self = [super init]) { | |
connectReentry = APEPatchCreate(connect, connect_override); | |
instance_pointer = self; | |
} | |
return self; | |
} | |
- (int)handleConnectAttempt:(int)socket addr:(const struct sockaddr *)addr addrlen:(socklen_t)addrlen { | |
static BOOL javaStackTestConnect = NO; | |
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; | |
// Ignore the first connect() attempt (java test) | |
static dispatch_once_t pred; | |
dispatch_once(&pred, ^{javaStackTestConnect = YES;}); | |
if (javaStackTestConnect) { | |
javaStackTestConnect = NO; | |
return connectReentry(socket, addr, addrlen); | |
} | |
char serv[NI_MAXSERV]; | |
// If the socket is not for minecraft, return without doing anything... | |
getnameinfo(addr, addrlen, NULL, 0, serv, NI_MAXSERV, NI_NUMERICSERV); | |
int port = atoi(serv); | |
if (port == 80) { | |
return connectReentry(socket, addr, addrlen); | |
} | |
// if socket is non-blocking... | |
BOOL wasNonBlocking = NO; | |
int flags = fcntl(socket,F_GETFL); | |
if (flags & O_NONBLOCK){ | |
wasNonBlocking = YES; | |
fcntl(socket, F_SETFL, flags & ~O_NONBLOCK); | |
} | |
// Call the original connect() | |
int retval = connectReentry(socket, addr, addrlen); | |
// Steal the original file descriptor (to server) | |
int original_fd = dup(socket); | |
// Redirect socket to sockpair[0] | |
int sockpair[2]; | |
socketpair(AF_UNIX, SOCK_STREAM, 0, sockpair); | |
dup2(sockpair[0], socket); | |
// If the socket was non-blocking... | |
if (wasNonBlocking) { | |
// ...fix the socket to its original state | |
fcntl(socket, F_SETFL, O_NONBLOCK); | |
} | |
// Set up proxy | |
MHProxyDescriptorPair pair = {sockpair[1], original_fd}; | |
NSValue *pairValue = [NSValue value:&pair withObjCType:@encode(MHProxyDescriptorPair)]; | |
[NSThread detachNewThreadSelector:@selector(proxyThreadMain:) toTarget:self withObject:pairValue]; | |
[pool drain]; | |
return retval; | |
} | |
- (void)proxyThreadMain:(NSValue *)pairValue{ | |
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; | |
[[NSThread currentThread] setName:@"MineHelmet Proxy Thread"]; | |
MHProxyDescriptorPair pair; | |
[pairValue getValue:&pair]; | |
proxy = [[MHProxy alloc] initWithClientDescriptor:pair.client serverDescriptor:pair.server]; | |
// Run loop | |
CFRunLoopRun(); | |
// When the proxy stops the loop, release it | |
[proxy release]; | |
[pool drain]; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment