Skip to content

Instantly share code, notes, and snippets.

@DylanLukes
Created October 28, 2010 15:33
Show Gist options
  • Save DylanLukes/651600 to your computer and use it in GitHub Desktop.
Save DylanLukes/651600 to your computer and use it in GitHub Desktop.
//
// MHProxy.m
// MineHelmet
//
// Created by Dylan Lukes on 10/24/10.
// Copyright 2010 Dylan Lukes. All rights reserved.
//
#import "MHProxy.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]) {
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];
}
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(@"Reading from client");
[self handleClientInputEvent:streamEvent];
}
if (stream == fromServer && streamEvent == NSStreamEventHasBytesAvailable) {
NSLog(@"Reading from server");
[self handleServerInputEvent:streamEvent];
}
if (stream == toClient && streamEvent == NSStreamEventHasSpaceAvailable) {
NSLog(@"Writing to client");
[self handleClientOutputEvent:streamEvent];
}
if (stream == toServer && streamEvent == NSStreamEventHasSpaceAvailable) {
NSLog(@"Writing to server");
[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) {
NSLog(@"READ -1 BYTES");
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) {
NSLog(@"READ -1 BYTES");
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
//
// 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 {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
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);
NSLog(@"CONNECTION FROM PORT: %d", port);
if (port == 80 || port != 25565) {
return connectReentry(socket, addr, addrlen);
}
// if socket is non-blocking...
BOOL wasNonBlocking = NO; int flags;
if ((flags = fcntl(socket,F_GETFL)) == -1) {
NSLog(@"FCNTL FAILED");
}
if ((flags & O_NONBLOCK) != 0){
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);
// Splice the client's socket onto sockpair[0]
int sockpair[2];
socketpair(AF_UNIX, SOCK_STREAM, 0, sockpair);
dup2(socket, sockpair[0]);
//dup2(original_fd, sockpair[1]);
// 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];
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