screendump/screendump/ScreenDumpVNC.m

174 lines
5.2 KiB
Objective-C

#import "ScreenDumpVNC.h"
#import "FrameUpdater.h"
#import "utils.h"
#import "vnc.h"
#import <UIKit/UIKit.h>
#import <rfb/rfb.h>
#import "IOMobileFramebuffer.h"
@implementation ScreenDumpVNC {
int _prefsHeight;
int _prefsWidth;
bool _enabled;
NSString *_password;
rfbScreenInfoPtr _rfbScreenInfo;
bool _vncIsRunning;
// sent to FrameUpdater
IOSurfaceRef _screenSurface;
size_t _sizeImage;
IOSurfaceAcceleratorRef _accelerator;
IOSurfaceRef _staticBuffer;
size_t _width;
size_t _height;
FrameUpdater *_frameUpdater;
}
+(void)load {
ScreenDumpVNC* sharedInstance = [self sharedInstance];
if (![sharedInstance enabled]) return;
[sharedInstance setupScreenInfo];
[sharedInstance startVNCServer];
}
+(instancetype)sharedInstance {
static dispatch_once_t onceToken = 0;
__strong static ScreenDumpVNC* sharedInstance = nil;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
-(instancetype)init {
if ((self = [super init])) {
// TODO: init procedures
[self loadPrefs];
}
return self;
}
-(void)loadPrefs {
NSDictionary* defaults = getPrefsForAppId(@"ru.mostmodest.screendump");
NSNumber *height = [defaults objectForKey:@"height"];
_prefsHeight = height ? [height intValue] : 0;
NSNumber *width = [defaults objectForKey:@"width"];
_prefsWidth = width ? [width intValue] : 0;
NSNumber *enabled = [defaults objectForKey:@"enabled"];
_enabled = enabled ? [enabled boolValue] : NO;
_password = [defaults objectForKey:@"password"];
}
-(void)setupVNCAuthentication {
if (_rfbScreenInfo == nil) return;
_rfbScreenInfo->authPasswdData = nil;
if (_password && _password.length) {
_rfbScreenInfo->authPasswdData = (void *)_password;
}
}
-(void)startVNCServer {
if (_rfbScreenInfo == nil || _vncIsRunning == YES) return;
[self setupVNCAuthentication];
rfbInitServer(_rfbScreenInfo);
rfbRunEventLoop(_rfbScreenInfo, -1, YES);
[_frameUpdater startFrameLoop];
}
-(void)shutdownVNCServer {
// unused
if (_rfbScreenInfo == nil || _vncIsRunning == NO) return;
[_frameUpdater stopFrameLoop];
rfbShutdownServer(_rfbScreenInfo, YES);
}
-(void)setupScreenInfo {
size_t bytesPerPixel;
size_t bitsPerSample;
if (!_screenSurface) {
IOMobileFramebufferRef framebufferConnection;
IOSurfaceAcceleratorCreate(kCFAllocatorDefault, 0, &_accelerator);
IOMobileFramebufferGetMainDisplay(&framebufferConnection);
IOMobileFramebufferGetLayerDefaultSurface(framebufferConnection, 0, &_screenSurface);
if (_screenSurface == NULL) IOMobileFramebufferCopyLayerDisplayedSurface(framebufferConnection, 0, &_screenSurface);
_width = _prefsWidth == 0 ? IOSurfaceGetWidth(_screenSurface) : _prefsWidth;
_height = _prefsHeight == 0 ? IOSurfaceGetHeight(_screenSurface) : _prefsHeight;
_sizeImage = IOSurfaceGetAllocSize(_screenSurface);
// TODO: do these change at all? this might have been done for perf reasons
// bytesPerRow = IOSurfaceGetBytesPerRow(_screenSurface);
// pixelF = IOSurfaceGetPixelFormat(_screenSurface);
bytesPerPixel = 4; // IOSurfaceGetBytesPerElement(_screenSurface);
bitsPerSample = 8;
_staticBuffer = IOSurfaceCreate((CFDictionaryRef) [NSDictionary dictionaryWithObjectsAndKeys:
@"PurpleEDRAM", kIOSurfaceMemoryRegion,
// [NSNumber numberWithBool:YES], kIOSurfaceIsGlobal,
[NSNumber numberWithInt:bytesPerPixel*_width], kIOSurfaceBytesPerRow,
[NSNumber numberWithInt:bytesPerPixel], kIOSurfaceBytesPerElement,
[NSNumber numberWithInt:_width], kIOSurfaceWidth,
[NSNumber numberWithInt:_height], kIOSurfaceHeight,
[NSNumber numberWithInt:'BGRA'], kIOSurfacePixelFormat,
[NSNumber numberWithInt:(_width*_height*bytesPerPixel)], kIOSurfaceAllocSize,
nil]);
}
int argc = 1;
char *arg0 = strdup(kVNCServerName);
char *argv[] = {arg0, NULL};
int samplesPerPixel = 3;
_rfbScreenInfo = rfbGetScreen(&argc, argv, _width, _height, bitsPerSample, samplesPerPixel, bytesPerPixel);
_rfbScreenInfo->frameBuffer = (char *)IOSurfaceGetBaseAddress((IOSurfaceRef)CFRetain(_staticBuffer));
_rfbScreenInfo->serverFormat.redShift = bitsPerSample * 2;
_rfbScreenInfo->serverFormat.greenShift = bitsPerSample * 1;
_rfbScreenInfo->serverFormat.blueShift = bitsPerSample * 0;
_rfbScreenInfo->kbdAddEvent = &handleVNCKeyboard;
_rfbScreenInfo->ptrAddEvent = &handleVNCPointer;
_rfbScreenInfo->passwordCheck = &handleVNCAuthorization;
free(arg0);
_frameUpdater = [[FrameUpdater alloc] initWithSurfaceInfo:_screenSurface rfbScreenInfo:_rfbScreenInfo accelerator:_accelerator staticBuffer:_staticBuffer width:_width height:_height];
}
-(rfbBool)handleVNCAuthorization:(rfbClientPtr)client data:(const char *)data size:(int)size {
NSString *password = (__bridge NSString *)(_rfbScreenInfo->authPasswdData);
if (!password) {
return TRUE;
}
if ([password length] == 0) {
return TRUE;
}
rfbEncryptBytes(client->authChallenge, (char *)[password UTF8String]);
bool good = (memcmp(client->authChallenge, data, size) == 0);
return good;
}
-(size_t)width {
return _width;
}
-(size_t)height {
return _height;
}
-(bool)enabled {
return _enabled;
}
@end