project_files/HedgewarsMobile/Classes/ServerSetup.m
branchhedgeroid
changeset 6328 d14adf1c7721
parent 6236 1998ff75321a
parent 6326 07d83af9d2a8
child 6330 1bde8940e1bb
equal deleted inserted replaced
6236:1998ff75321a 6328:d14adf1c7721
     1 /*
       
     2  * Hedgewars-iOS, a Hedgewars port for iOS devices
       
     3  * Copyright (c) 2009-2011 Vittorio Giovara <vittorio.giovara@gmail.com>
       
     4  *
       
     5  * This program is free software; you can redistribute it and/or modify
       
     6  * it under the terms of the GNU General Public License as published by
       
     7  * the Free Software Foundation; version 2 of the License
       
     8  *
       
     9  * This program is distributed in the hope that it will be useful,
       
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    12  * GNU General Public License for more details.
       
    13  *
       
    14  * You should have received a copy of the GNU General Public License
       
    15  * along with this program; if not, write to the Free Software
       
    16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
       
    17  *
       
    18  * File created on 10/01/2010.
       
    19  */
       
    20 
       
    21 
       
    22 #import "ServerSetup.h"
       
    23 #import <netinet/in.h>
       
    24 #import <SystemConfiguration/SCNetworkReachability.h>
       
    25 
       
    26 #import "hwconsts.h"
       
    27 
       
    28 #define BUFFER_SIZE 256
       
    29 
       
    30 @implementation ServerSetup
       
    31 @synthesize systemSettings;
       
    32 
       
    33 
       
    34 +(NSInteger) randomPort {
       
    35     srandom(time(NULL));
       
    36     NSInteger res = (random() % 64511) + 1024;
       
    37     return (res == NETGAME_DEFAULT_PORT) ? [ServerSetup randomPort] : res;
       
    38 }
       
    39 
       
    40 +(BOOL) isNetworkReachable {
       
    41     // Create zero addy
       
    42     struct sockaddr_in zeroAddress;
       
    43     bzero(&zeroAddress, sizeof(zeroAddress));
       
    44     zeroAddress.sin_len = sizeof(zeroAddress);
       
    45     zeroAddress.sin_family = AF_INET;
       
    46 
       
    47     // Recover reachability flags
       
    48     SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&zeroAddress);
       
    49     SCNetworkReachabilityFlags flags;
       
    50 
       
    51     BOOL didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags);
       
    52     CFRelease(defaultRouteReachability);
       
    53 
       
    54     if (!didRetrieveFlags) {
       
    55         NSLog(@"Error. Could not recover network reachability flags");
       
    56         return NO;
       
    57     }
       
    58 
       
    59     BOOL isReachable = flags & kSCNetworkFlagsReachable;
       
    60     BOOL needsConnection = flags & kSCNetworkFlagsConnectionRequired;
       
    61     BOOL nonWiFi = flags & kSCNetworkReachabilityFlagsTransientConnection;
       
    62 
       
    63     NSURL *testURL = [NSURL URLWithString:@"http://www.apple.com/"];
       
    64     NSURLRequest *testRequest = [NSURLRequest requestWithURL:testURL
       
    65                                                  cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
       
    66                                              timeoutInterval:20.0];
       
    67     NSURLConnection *testConnection = [[NSURLConnection alloc] initWithRequest:testRequest delegate:nil];
       
    68     BOOL testResult = testConnection ? YES : NO;
       
    69     [testConnection release];
       
    70 
       
    71     return ((isReachable && !needsConnection) || nonWiFi) ? testResult : NO;
       
    72 }
       
    73 
       
    74 -(id) init {
       
    75     if (self = [super init]) {
       
    76         self.systemSettings = nil; //nsuserdefault
       
    77     }
       
    78     return self;
       
    79 }
       
    80 
       
    81 -(void) dealloc {
       
    82 
       
    83     [super dealloc];
       
    84 }
       
    85 
       
    86 -(int) sendToServer:(NSString *)command {
       
    87     NSString *message = [[NSString alloc] initWithFormat:@"%@\n\n",command];
       
    88     int result = SDLNet_TCP_Send(sd, [message UTF8String], [message length]);
       
    89     [message release];
       
    90     return result;
       
    91 }
       
    92 
       
    93 -(int) sendToServer:(NSString *)command withArgument:(NSString *)argument {
       
    94     NSString *message = [[NSString alloc] initWithFormat:@"%@\n%@\n\n",command,argument];
       
    95     int result = SDLNet_TCP_Send(sd, [message UTF8String], [message length]);
       
    96     [message release];
       
    97     return result;
       
    98 }
       
    99 
       
   100 -(void) serverProtocol {
       
   101     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
       
   102     IPaddress ip;
       
   103     BOOL clientQuit = NO;
       
   104     char *buffer = (char *)malloc(sizeof(char)*BUFFER_SIZE);
       
   105     int dim = BUFFER_SIZE;
       
   106     uint8_t msgSize;
       
   107 
       
   108     if (SDLNet_Init() < 0) {
       
   109         DLog(@"SDLNet_Init: %s", SDLNet_GetError());
       
   110         clientQuit = YES;
       
   111     }
       
   112 
       
   113     // Resolving the host using NULL make network interface to listen
       
   114     if (SDLNet_ResolveHost(&ip, "netserver.hedgewars.org", NETGAME_DEFAULT_PORT) < 0 && !clientQuit) {
       
   115         DLog(@"SDLNet_ResolveHost: %s\n", SDLNet_GetError());
       
   116         clientQuit = YES;
       
   117     }
       
   118 
       
   119     // Open a connection with the IP provided (listen on the host's port)
       
   120     if (!(sd = SDLNet_TCP_Open(&ip)) && !clientQuit) {
       
   121         DLog(@"SDLNet_TCP_Open: %s %\n", SDLNet_GetError(), NETGAME_DEFAULT_PORT);
       
   122         clientQuit = YES;
       
   123     }
       
   124 
       
   125     DLog(@"Found server on port %d", NETGAME_DEFAULT_PORT);
       
   126     while (!clientQuit) {
       
   127         int index = 0;
       
   128         BOOL exitBufferLoop = NO;
       
   129         memset(buffer, '\0', dim);
       
   130         
       
   131         while (exitBufferLoop != YES) {
       
   132             msgSize = SDLNet_TCP_Recv(sd, &buffer[index], 2);
       
   133             
       
   134             // exit in case of error
       
   135             if (msgSize <= 0) {
       
   136                 DLog(@"SDLNet_TCP_Recv: %s", SDLNet_GetError());
       
   137                 clientQuit = YES;
       
   138                 break;
       
   139             }
       
   140             
       
   141             // update index position and check for End-Of-Message
       
   142             index += msgSize;
       
   143             if (strncmp(&buffer[index-2], "\n\n", 2) == 0) {
       
   144                 exitBufferLoop = YES;
       
   145             }
       
   146             
       
   147             // if message is too big allocate new space
       
   148             if (index >= dim) {
       
   149                 dim += BUFFER_SIZE;
       
   150                 buffer = (char *)realloc(buffer, dim);
       
   151                 if (buffer == NULL) {
       
   152                     clientQuit = YES;
       
   153                     break;
       
   154                 }
       
   155             }
       
   156         }
       
   157 
       
   158         NSString *bufferedMessage = [[NSString alloc] initWithBytes:buffer length:index-2 encoding:NSASCIIStringEncoding];
       
   159         NSArray *listOfCommands = [bufferedMessage componentsSeparatedByString:@"\n"];
       
   160         [bufferedMessage release];
       
   161         NSString *command = [listOfCommands objectAtIndex:0];
       
   162         DLog(@"size = %d, %@", index-2, listOfCommands);
       
   163         if ([command isEqualToString:@"PING"]) {
       
   164             if ([listOfCommands count] > 1)
       
   165                 [self sendToServer:@"PONG" withArgument:[listOfCommands objectAtIndex:1]];
       
   166             else
       
   167                 [self sendToServer:@"PONG"];
       
   168             DLog(@"PONG");
       
   169         }
       
   170         else if ([command isEqualToString:@"NICK"]) {
       
   171             //what is this for?
       
   172         }
       
   173         else if ([command isEqualToString:@"PROTO"]) {
       
   174             //what is this for?
       
   175         }
       
   176         else if ([command isEqualToString:@"ROOM"]) {
       
   177             //TODO: stub
       
   178         }
       
   179         else if ([command isEqualToString:@"LOBBY:LEFT"]) {
       
   180             //TODO: stub
       
   181         }
       
   182         else if ([command isEqualToString:@"LOBBY:JOINED"]) {
       
   183             //TODO: stub
       
   184         }
       
   185         else if ([command isEqualToString:@"ASKPASSWORD"]) {
       
   186             NSString *pwd = [self.systemSettings objectForKey:@"password"];
       
   187             [self sendToServer:@"PASSWORD" withArgument:pwd];
       
   188         }
       
   189         else if ([command isEqualToString:@"CONNECTED"]) {
       
   190             int netProto;
       
   191             char *versionStr;
       
   192             HW_versionInfo(&netProto, &versionStr);
       
   193             NSString *nick = [self.systemSettings objectForKey:@"username"];
       
   194             [self sendToServer:@"NICK" withArgument:nick];
       
   195             [self sendToServer:@"PROTO" withArgument:[NSString stringWithFormat:@"%d",netProto]];
       
   196         }
       
   197         else if ([command isEqualToString:@"SERVER_MESSAGE"]) {
       
   198             DLog(@"%@", [listOfCommands objectAtIndex:1]);
       
   199         }
       
   200         else if ([command isEqualToString:@"WARNING"]) {
       
   201             if ([listOfCommands count] > 1)
       
   202                 DLog(@"Server warning - %@", [listOfCommands objectAtIndex:1]);
       
   203             else
       
   204                 DLog(@"Server warning - unknown");
       
   205         }
       
   206         else if ([command isEqualToString:@"ERROR"]) {
       
   207             DLog(@"Server error - %@", [listOfCommands objectAtIndex:1]);
       
   208         }
       
   209         else if ([command isEqualToString:@"BYE"]) {
       
   210             //TODO: handle "Reconnected too fast"
       
   211             DLog(@"Server disconnected, reason: %@", [listOfCommands objectAtIndex:1]);
       
   212             clientQuit = YES;
       
   213         }
       
   214         else {
       
   215             DLog(@"Unknown/Unsupported message received: %@", command);
       
   216         }
       
   217     }
       
   218     DLog(@"Server closed connection, ending thread");
       
   219 
       
   220     free(buffer);
       
   221     SDLNet_TCP_Close(sd);
       
   222     SDLNet_Quit();
       
   223 
       
   224     [pool release];
       
   225 }
       
   226 
       
   227 @end