VLCHTTPUploaderController.m 7.38 KB
Newer Older
1 2 3 4
/*****************************************************************************
 * VLCHTTPUploaderViewController.m
 * VLC for iOS
 *****************************************************************************
5
 * Copyright (c) 2013-2015 VideoLAN. All rights reserved.
6 7 8 9 10 11 12 13 14
 * $Id$
 *
 * Authors: Jean-Baptiste Kempf <jb # videolan.org>
 *          Gleb Pinigin <gpinigin # gmail.com>
 *          Felix Paul Kühne <fkuehne # videolan.org>
 *          Jean-Romain Prévost <jr # 3on.fr>
 *
 * Refer to the COPYING file of the official project for license.
 *****************************************************************************/
15

16
#import "VLCAppDelegate.h"
17 18
#import "VLCHTTPUploaderController.h"
#import "VLCHTTPConnection.h"
19 20 21

#import "HTTPServer.h"

22 23 24
#import <ifaddrs.h>
#import <arpa/inet.h>

25
@implementation VLCHTTPUploaderController
26 27 28
{
    UIBackgroundTaskIdentifier _backgroundTaskIdentifier;
}
29

30 31
- (id)init
{
32
    if (self = [super init]) {
33 34
        NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
        [center addObserver:self selector:@selector(applicationDidBecomeActive:)
35
            name:UIApplicationDidBecomeActiveNotification object:nil];
36
        [center addObserver:self selector:@selector(applicationDidEnterBackground:)
37 38
            name:UIApplicationDidEnterBackgroundNotification object:nil];
    }
39 40

    return self;
41 42 43 44
}

- (void)applicationDidBecomeActive: (NSNotification *)notification
{
45 46 47 48 49 50 51
    if (!self.httpServer.isRunning)
        [self changeHTTPServerState:[[NSUserDefaults standardUserDefaults] boolForKey:kVLCSettingSaveHTTPUploadServerStatus]];

    if (_backgroundTaskIdentifier && _backgroundTaskIdentifier != UIBackgroundTaskInvalid) {
        [[UIApplication sharedApplication] endBackgroundTask:_backgroundTaskIdentifier];
        _backgroundTaskIdentifier = 0;
    }
52 53 54 55
}

- (void)applicationDidEnterBackground: (NSNotification *)notification
{
56 57
    if (self.httpServer.isRunning) {
        if (!_backgroundTaskIdentifier || _backgroundTaskIdentifier == UIBackgroundTaskInvalid) {
58
            dispatch_block_t expirationHandler = ^{
59 60 61
                [self changeHTTPServerState:NO];
                [[UIApplication sharedApplication] endBackgroundTask:_backgroundTaskIdentifier];
                _backgroundTaskIdentifier = 0;
62 63 64 65 66 67
            };
            if ([[UIApplication sharedApplication] respondsToSelector:@selector(beginBackgroundTaskWithName:expirationHandler:)]) {
                _backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithName:@"VLCUploader" expirationHandler:expirationHandler];
            } else {
                _backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:expirationHandler];
            }
68 69
        }
    }
70 71
}

72
- (BOOL)changeHTTPServerState:(BOOL)state
73
{
74 75 76 77
    if (!state) {
        [self.httpServer stop];
        return true;
    }
78 79 80
    // clean cache before accepting new stuff
    [(VLCAppDelegate *)[UIApplication sharedApplication].delegate cleanCache];

81 82 83
    // Initialize our http server
    _httpServer = [[HTTPServer alloc] init];
    [_httpServer setInterface:WifiInterfaceName];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
84

85 86 87
    [_httpServer setIPv4Enabled:YES];
    [_httpServer setIPv6Enabled:[[[NSUserDefaults standardUserDefaults] objectForKey:kVLCSettingWiFiSharingIPv6] boolValue]];

88 89 90
    // Tell the server to broadcast its presence via Bonjour.
    // This allows browsers such as Safari to automatically discover our service.
    [self.httpServer setType:@"_http._tcp."];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
91

92 93
    // Serve files from the standard Sites folder
    NSString *docRoot = [[[NSBundle mainBundle] pathForResource:@"index" ofType:@"html"] stringByDeletingLastPathComponent];
94

95
    APLog(@"Setting document root: %@", docRoot);
96

97 98
    [self.httpServer setDocumentRoot:docRoot];
    [self.httpServer setPort:80];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
99

100
    [self.httpServer setConnectionClass:[VLCHTTPConnection class]];
101

102 103
    NSError *error = nil;
    if (![self.httpServer start:&error]) {
104
        if (error.code == EACCES) {
105 106 107 108 109
            APLog(@"Port forbidden by OS, trying another one");
            [self.httpServer setPort:8888];
            if(![self.httpServer start:&error])
                return true;
        }
110

111
        /* Address already in Use, take a random one */
112
        if (error.code == EADDRINUSE) {
113 114 115 116
            APLog(@"Port already in use, trying another one");
            [self.httpServer setPort:0];
            if(![self.httpServer start:&error])
                return true;
117
        }
118

119
        if (error) {
120
            APLog(@"Error starting HTTP Server: %@", error.localizedDescription);
121 122
            [self.httpServer stop];
        }
123
        return false;
124
    }
125
    return true;
126 127
}

128 129 130 131 132 133
- (NSString *)currentIPAddress
{
    NSString *address = @"";
    struct ifaddrs *interfaces = NULL;
    struct ifaddrs *temp_addr = NULL;
    int success = getifaddrs(&interfaces);
134

135
    if (success != 0) {
136 137 138 139 140 141 142 143 144
        freeifaddrs(interfaces);
        return address;
    }

    temp_addr = interfaces;
    while (temp_addr != NULL) {
        if (temp_addr->ifa_addr->sa_family == AF_INET) {
            if([@(temp_addr->ifa_name) isEqualToString:WifiInterfaceName])
                address = @(inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr));
145
        }
146
        temp_addr = temp_addr->ifa_next;
147
    }
148

149 150 151 152
    freeifaddrs(interfaces);
    return address;
}

153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
- (NSString *)hostname
{
    char baseHostName[256];
    int success = gethostname(baseHostName, 255);
    if (success != 0)
        return nil;
    baseHostName[255] = '\0';

#if !TARGET_IPHONE_SIMULATOR
    return [NSString stringWithFormat:@"%s.local", baseHostName];
#else
    return [NSString stringWithFormat:@"%s", baseHostName];
#endif
}

168 169 170 171 172 173 174 175 176 177 178 179 180 181
- (void)moveFileFrom:(NSString *)filepath
{
    NSString *fileName = [filepath lastPathComponent];
    NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *libraryPath = searchPaths[0];
    NSString *finalFilePath = [libraryPath stringByAppendingPathComponent:fileName];
    NSFileManager *fileManager = [NSFileManager defaultManager];

    if ([fileManager fileExistsAtPath:finalFilePath]) {
        /* we don't want to over-write existing files, so add an integer to the file name */
        NSString *potentialFilename;
        NSString *fileExtension = [fileName pathExtension];
        NSString *rawFileName = [fileName stringByDeletingPathExtension];
        for (NSUInteger x = 1; x < 100; x++) {
182
            potentialFilename = [NSString stringWithFormat:@"%@ %lu.%@", rawFileName, (unsigned long)x, fileExtension];
183 184 185 186 187 188 189 190 191
            if (![[NSFileManager defaultManager] fileExistsAtPath:[libraryPath stringByAppendingPathComponent:potentialFilename]])
                break;
        }
        finalFilePath = [libraryPath stringByAppendingPathComponent:potentialFilename];
    }

    NSError *error;
    [fileManager moveItemAtPath:filepath toPath:finalFilePath error:&error];
    if (error) {
192
        APLog(@"Moving received media %@ to library folder failed (%li), deleting", fileName, (long)error.code);
193 194 195
        [fileManager removeItemAtPath:filepath error:nil];
    }

196
    [(VLCAppDelegate*)[UIApplication sharedApplication].delegate networkActivityStopped];
197 198 199 200
    [(VLCAppDelegate*)[UIApplication sharedApplication].delegate activateIdleTimer];

    /* update media library when file upload was completed */
    VLCAppDelegate* appDelegate = [UIApplication sharedApplication].delegate;
201
    [appDelegate performSelectorOnMainThread:@selector(updateMediaList) withObject:nil waitUntilDone:NO];
202 203
}

204
@end