/Volumes/Plantain/MyDocuments/Projects/MacTrek/MacTrek/Comm/Communication.m

00001 //
00002 //  Communication.m
00003 //  MacTrek
00004 //
00005 //  Created by Aqua on 23/04/2006.
00006 //  Copyright 2006 __MyCompanyName__. All rights reserved.
00007 //
00008 
00009 #import "Communication.h"
00010 #import "ServerReaderTcp.h"
00011 #import "ServerReaderUdp.h"
00012 #import "ServerSenderTcp.h"
00013 #import "ServerSenderUdp.h"
00014 #import <Math.h>
00015 
00016 @implementation Communication
00017 
00018 // multithreaded?
00019 bool multiThreaded = NO;
00020 
00021 // use ping?
00022 bool ping = NO;
00023 
00024 // force state and weapons
00025 // only if force is YES
00026 bool forceState = NO;
00027 
00028 int fSpeed = -1;
00029 int fShield = -1;
00030 int fOrbit = -1;
00031 int fRepair = -1;
00032 int fBeamup = -1;
00033 int fBeamdown = -1;
00034 int fCloak = -1;
00035 int fBomb = -1;
00036 int fDockperm = -1;
00037 int fPhaser = -1;
00038 int fPlasma = -1;
00039 int fPlayLock = -1; 
00040 int fPlanLock = -1;
00041 int fTractor = -1;
00042 int fRepressor = -1;
00043 
00044 // privates
00045 int baseLocalUdpPort = 0;
00046 int localUdpPort = 0;
00047 int updatesPerSecond = COMM_UPDATES_PER_SECOND;
00048 char buffer;           // maintain a static sendbuffer
00049 
00050 // network stuff
00051 int nextPort = 0;           // remember the ports we already tried
00052 ServerReaderTcp *tcpReader;
00053 ServerReaderUdp *udpReader;
00054 ServerSenderTcp *tcpSender;
00055 ServerSenderUdp *udpSender;
00056 
00057 // thread vars
00058 bool isRunning;
00059 bool keepRunning;
00060 
00061 - (id) init {
00062     self = [super init];
00063     if (self != nil) {
00064         ghostSlot = -1;  
00065         commMode = COMM_TCP;         // COMM_TCP or COMM_UDP
00066         commStatus = 0;
00067         commModeRequest;
00068         shortVersion = COMM_SHORTVERSION;
00069         receiveShort = NO;
00070         fList = [[FeatureList alloc] init]; 
00071         pStats = [[PingStats alloc] init];
00072         udpStats = [[UdpStats alloc] init];   
00073         notificationCenter = [LLNotificationCenter defaultCenter];
00074         tcpReader = nil;
00075         udpReader = nil;
00076         [self subscribeToNotifications];
00077         isRunning = NO;
00078         keepRunning = YES;
00079    }
00080     return self;
00081 }
00082 
00083 - (id)initWithUniverse:(Universe*)newUniverse baseUdpPort:(int)basePort {
00084     self = [self init];
00085     if (self != nil) {
00086         [universe release];
00087         universe = newUniverse;
00088         [universe retain];
00089         baseLocalUdpPort = basePort;
00090     }
00091     return self;
00092 }
00093 
00094 - (void) setMultiThreaded:(bool) multi {
00095     multiThreaded = multi;
00096 }
00097 
00098 - (void)subscribeToNotifications {
00099     
00100     // tie [self selector] to a common event so it can be remotely invoked
00101     // this is thread safe because of the locks
00102     // i will respond to anyone (nil)                                                           // expect parameter
00103     [notificationCenter addObserver:self selector:@selector(readFromServer:) 
00104                                name:@"COMM_READ_FROM_SERVER" object:nil useLocks:multiThreaded];                   // --
00105     [notificationCenter addObserver:self selector:@selector(cleanUp:) 
00106                                name:@"COMM_CLEAN_UP" object:nil useLocks:multiThreaded];                   // --
00107     [notificationCenter addObserver:self selector:@selector(readFromServer:) 
00108                                name:@"COMM_READ_FROM_SERVER" object:nil useLocks:multiThreaded];           // --
00109     [notificationCenter addObserver:self selector:@selector(sendSpeedReq:) 
00110                                name:@"COMM_SEND_SPEED_REQ"  object:nil useLocks:multiThreaded];            // NSNumber intValue
00111     [notificationCenter addObserver:self selector:@selector(sendDockingReq:) 
00112                                name:@"COMM_SEND_DOCK_REQ" object:nil useLocks:multiThreaded];              // NSNumber boolValue
00113     [notificationCenter addObserver:self selector:@selector(sendCloakReq:) 
00114                                name:@"COMM_SEND_CLOAK_REQ" object:nil useLocks:multiThreaded];             // NSNumber boolValue
00115     [notificationCenter addObserver:self selector:@selector(sendRefitReq:) 
00116                                name:@"COMM_SEND_REFIT_REQ" object:nil useLocks:multiThreaded];             // NSNumber charValue
00117     [notificationCenter addObserver:self selector:@selector(sendDirReq:) 
00118                                name:@"COMM_SEND_DIR_REQ" object:nil useLocks:multiThreaded];               // NSNumber charValue
00119     [notificationCenter addObserver:self selector:@selector(sendPhaserReq:) 
00120                                name:@"COMM_SEND_PHASER_REQ" object:nil useLocks:multiThreaded];            // NSNumber charValue
00121     [notificationCenter addObserver:self selector:@selector(sendTorpReq:) 
00122                                name:@"COMM_SEND_TORPS_REQ" object:nil useLocks:multiThreaded];             // NSNumber charValue
00123     [notificationCenter addObserver:self selector:@selector(sendPlasmaReq:) 
00124                                name:@"COMM_SEND_PLASMA_REQ" object:nil useLocks:multiThreaded];            // NSNumber charValue
00125     [notificationCenter addObserver:self selector:@selector(sendShieldReq:) 
00126                                name:@"COMM_SEND_SHIELD_REQ" object:nil useLocks:multiThreaded];            // NSNumber boolValue
00127     [notificationCenter addObserver:self selector:@selector(sendBombReq:) 
00128                                name:@"COMM_SEND_BOMB_REQ" object:nil useLocks:multiThreaded];              // NSNumber boolValue
00129     [notificationCenter addObserver:self selector:@selector(sendBeamReq:) 
00130                                name:@"COMM_SEND_BEAM_REQ" object:nil useLocks:multiThreaded];              // NSNumber boolValue
00131     [notificationCenter addObserver:self selector:@selector(sendRepairReq:) 
00132                                name:@"COMM_SEND_REPAIR_REQ" object:nil useLocks:multiThreaded];            // NSNumber boolValue
00133     [notificationCenter addObserver:self selector:@selector(sendOrbitReq:) 
00134                                name:@"COMM_SEND_ORBIT_REQ" object:nil useLocks:multiThreaded];             // NSNumber boolValue
00135     [notificationCenter addObserver:self selector:@selector(sendQuitReq:) 
00136                                name:@"COMM_SEND_QUIT_REQ" object:nil useLocks:multiThreaded];              // --
00137     [notificationCenter addObserver:self selector:@selector(sendCoupReq:) 
00138                                name:@"COMM_SEND_COUP_REQ" object:nil useLocks:multiThreaded];              // --
00139     [notificationCenter addObserver:self selector:@selector(sendByeReq:) 
00140                                name:@"COMM_SEND_BYE_REQ" object:nil useLocks:multiThreaded];               // --
00141     [notificationCenter addObserver:self selector:@selector(sendPractrReq:) 
00142                                name:@"COMM_SEND_PRACTICE_REQ" object:nil useLocks:multiThreaded];          // --
00143     [notificationCenter addObserver:self selector:@selector(sendDetonateReq:) 
00144                                name:@"COMM_SEND_DETONATE_REQ" object:nil useLocks:multiThreaded];          // --
00145     [notificationCenter addObserver:self selector:@selector(sendDetMineReq:)
00146                                name:@"COMM_SEND_DET_MINE_REQ" object:nil useLocks:multiThreaded];          // NSNumber intValue
00147     [notificationCenter addObserver:self selector:@selector(sendDetonateMyTorpsReq:)
00148                                name:@"COMM_SEND_DET_MINE_ALL_REQ" object:nil useLocks:multiThreaded];      // --
00149     [notificationCenter addObserver:self selector:@selector(sendPlaylockReq:) 
00150                                name:@"COMM_SEND_PLAYER_LOCK_REQ" object:nil useLocks:multiThreaded];       // NSNumber intValue
00151     [notificationCenter addObserver:self selector:@selector(sendPlanlockReq:) 
00152                                name:@"COMM_SEND_PLANET_LOCK_REQ" object:nil useLocks:multiThreaded];       // NSNumber intValue 
00153     [notificationCenter addObserver:self selector:@selector(sendResetStatsReq:)
00154                                name:@"COMM_SEND_RESET_STATS_REQ" object:nil useLocks:multiThreaded];       // NSNumber charValue
00155     [notificationCenter addObserver:self selector:@selector(sendWarReq:)
00156                                name:@"COMM_SEND_WAR_REQ" object:nil useLocks:multiThreaded];               // NSNumber charValue
00157     [notificationCenter addObserver:self selector:@selector(sendTractorOnReq:)
00158                                name:@"COMM_SEND_TRACTOR_ON_REQ" object:nil useLocks:multiThreaded];        // NSNumber charValue
00159     [notificationCenter addObserver:self selector:@selector(sendTractorOffReq:)
00160                                name:@"COMM_SEND_TRACTOR_OFF_REQ" object:nil useLocks:multiThreaded];       // NSNumber charValue
00161     [notificationCenter addObserver:self selector:@selector(sendRepressorOnReq:)
00162                                name:@"COMM_SEND_REPRESSOR_ON_REQ" object:nil useLocks:multiThreaded];      // NSNumber charValue
00163     [notificationCenter addObserver:self selector:@selector(sendRepressorOffReq:)
00164                                name:@"COMM_SEND_REPRESSOR_OFF_REQ" object:nil useLocks:multiThreaded];     // NSNumber charValue
00165     [notificationCenter addObserver:self selector:@selector(sendTeamReq:)
00166                                name:@"COMM_SEND_TEAM_REQ" object:nil useLocks:multiThreaded];              // NSDictionary with team, ship
00167     [notificationCenter addObserver:self selector:@selector(sendFeatureReq:)
00168                                name:@"COMM_SEND_FEATURE_REQ" object:nil useLocks:multiThreaded];           // NSDictionary with type, arg1, arg2, name
00169     [notificationCenter addObserver:self selector:@selector(sendLoginReq:)
00170                                name:@"COMM_SEND_LOGIN_REQ" object:nil useLocks:multiThreaded];             // NSDictionary with query,name,pass,login
00171     [notificationCenter addObserver:self selector:@selector(sendPingReq:)
00172                                name:@"COMM_SEND_PING_REQ" object:nil useLocks:multiThreaded];              // NSNumber bool
00173     [notificationCenter addObserver:self selector:@selector(sendServerPingResponse:)
00174                                name:@"COMM_SEND_PING_RESPONSE" object:nil useLocks:multiThreaded];         // NSNumber char
00175     [notificationCenter addObserver:self selector:@selector(sendMessage:)
00176                                name:@"COMM_SEND_MESSAGE" object:nil useLocks:multiThreaded];               // NSDictionary with group, indiv, message
00177     [notificationCenter addObserver:self selector:@selector(sendUpdatePacket:)
00178                                name:@"COMM_SEND_UPDATE_PACKET" object:nil useLocks:multiThreaded];         // NSNumber int
00179     [notificationCenter addObserver:self selector:@selector(sendUpdatePacket:)
00180                                name:@"COMM_SEND_TRESHOLD" object:nil useLocks:multiThreaded];              // NSNumber int
00181     [notificationCenter addObserver:self selector:@selector(sendOptionsPacket:)
00182                                name:@"COMM_SEND_OPTIONS_PACKET" object:nil useLocks:multiThreaded];        // --
00183     [notificationCenter addObserver:self selector:@selector(sendPickSocketReq:)
00184                                name:@"COMM_SEND_PICK_SOCKET" object:nil useLocks:multiThreaded];           // NSNumber int
00185     [notificationCenter addObserver:self selector:@selector(sendUdpReq:)
00186                                name:@"COMM_SEND_UDP_REQ" object:nil useLocks:multiThreaded];               // NSNumber char
00187     [notificationCenter addObserver:self selector:@selector(sendShortReq:)
00188                                name:@"COMM_SEND_SHORT_REQ" object:nil useLocks:multiThreaded];             // NSNumber char
00189     [notificationCenter addObserver:self selector:@selector(sendUdpVerify:)
00190                                name:@"COMM_SEND_VERIFY" object:nil useLocks:multiThreaded];                // --
00191      
00192     // implementation of serverReader events
00193     [notificationCenter addObserver:self selector:@selector(closeUdpConn:)
00194                                name:@"SP_SWITCHED_DENIED" object:nil useLocks:multiThreaded];     // close connection if switch denied
00195         [notificationCenter addObserver:self selector:@selector(closeUdpConn:)
00196                                name:@"SP_UDP_SWITCHED_TO_TCP" object:nil useLocks:multiThreaded];          // close the connection 
00197         [notificationCenter addObserver:self selector:@selector(sendUdpVerify:)
00198                                name:@"SP_TCP_SWITCHED_TO_UDP" object:nil useLocks:multiThreaded];          // when switched to UDP verify
00199     [notificationCenter addObserver:self selector:@selector(sendShortReq:)
00200                                name:@"SP_S_REPLY_SPK_OLD" object:nil useLocks:multiThreaded];              // switch ot old version
00201     [notificationCenter addObserver:self selector:@selector(sendUdpReq:)
00202                                name:@"SP_S_REPLY_SPK_VOFF" object:nil useLocks:multiThreaded];             // UDP off
00203     [notificationCenter addObserver:self selector:@selector(sendShortReq:)
00204                                name:@"SP_S_REPLY_SPK_VON" object:nil useLocks:multiThreaded];              // switch ot short pkt    
00205     // and comm events
00206     [notificationCenter addObserver:self selector:@selector(stopCommunicationThread)
00207                                name:@"COMM_RESURRECT_FAILED" object:nil useLocks:multiThreaded]; 
00208 }
00209 
00210 -(char*) bigEndianInteger:(int) value inBuffer:(char*) dst withOffset:(int)dst_begin {
00211     dst   = (char)((value >> 24) & 0xFF);
00212     dst = (char)((value >> 16) & 0xFF);
00213     dst = (char)((value >> 8 ) & 0xFF);
00214     dst = (char)(value & 0xFF);
00215     return dst;
00216 }
00217 
00218 -(PingStats*) pingStats {
00219     return pStats;
00220 }
00221 
00222 -(UdpStats*)udpStats {
00223     return udpStats;
00224 }
00225 
00226 - (int) updatesPerSecond {      // private var ?
00227     return updatesPerSecond;
00228 }
00229 
00230 - (int) ghostSlot {
00231     return ghostSlot;
00232 }
00233 
00234 - (void) setGhostSlot:(int) slot {
00235     ghostSlot = slot;
00236 }
00237 
00238 -(int)commMode {
00239     return commMode;
00240 }
00241 
00242 -(void)setCommMode:(int)mode {
00243     commMode = mode;
00244 }
00245 -(int)commModeRequest {
00246     return commModeRequest;
00247 }
00248 
00249 -(void)setCommModeRequest:(int)mode {
00250     commModeRequest = mode;
00251 }
00252 
00253 -(FeatureList*) featureList {
00254     return fList;
00255 }
00256 
00257 -(int)commStatus {
00258     return commStatus;
00259 }
00260 
00261 -(void)setCommStatus:(int)status {
00262     commStatus = status;
00263 }
00264 
00265 -(int)shortVersion {
00266     return shortVersion;
00267 }
00268 
00269 -(void)setShortVersion:(int)ver {
00270     shortVersion = ver;
00271 }
00272 
00273 -(bool)receiveShort {
00274     return receiveShort;
00275 }
00276 
00277 -(void)setReceiveShort:(bool)rs {
00278     receiveShort = rs;
00279 }
00280 
00281 -(void) setPing:(bool) received withResponse:(int)response {
00282     // i have no idea $$
00283 }
00284 
00285 -(int) packetsReceived {
00286     return [udpStats packetsReceived];
00287 }
00288 
00289 -(void)increasePacketsReceived {
00290     [udpStats setPacketsReceived: [udpStats packetsReceived] + 1];
00291 }
00292 
00293 -(void)decreasePacketsReceived {
00294     [udpStats setPacketsReceived: [udpStats packetsReceived] - 1];
00295 }
00296 
00297 -(char *) insertString:(NSString *)str inBuffer:(char*)buffer offset:(int)offset maxLength:(int)max {
00298         // max is either the max or the length of the string we try to copy
00299         max = (max > [str length] ? [str length] : max);
00300         // get it as a cstring
00301         const char *input = [str cString];
00302         // perform the copy
00303         strncpy(buffer+offset, input, max);
00304         // close the string
00305         buffer[offset+max] = 0;
00306         return buffer;
00307 }
00308 
00309 // some generic send messages, internal use only
00310 - (void) sendShortPacketWithId:(char) type {
00311         [self sendShortPacketWithId:type state: 0];
00312 }
00313 
00314 - (void) sendShortPacketNoForceWithId:(char) type state:(char) state {
00315         buffer = type;
00316         buffer = state;
00317         [self sendServerPacketWithBuffer:buffer length:4];
00318 }
00319 
00320 - (void) sendShortPacketWithId:(char) type boolState:(bool) state {
00321     [self sendShortPacketWithId:type state: (state ? 1 :0 ) ];
00322 }
00323 
00324     // state is a boolean, 1 means on, 0 means off
00325 - (void) sendShortPacketWithId:(char) type state:(char) state {    
00326         // same as without forceStat
00327         [self sendShortPacketNoForceWithId:type state:state];
00328     
00329         // if we're sending in UDP mode, be prepared to forceStat it
00330         // currently disabled $$$
00331         if (commMode == COMM_UDP && forceState) {
00332                 switch (type) {
00333             case CP_SPEED:
00334                 fSpeed = state | 0x100;
00335                 break;
00336             case CP_SHIELD:
00337                 fShield = state | 0xA00;
00338                 break;
00339             case CP_ORBIT:
00340                 fOrbit = state | 0xA00;
00341                 break;
00342             case CP_REPAIR:
00343                 fRepair = state | 0xA00;
00344                 break;
00345             case CP_CLOAK:
00346                 fCloak = state | 0xA00;
00347                 break;
00348             case CP_BOMB:
00349                 fBomb = state | 0xA00;
00350                 break;
00351             case CP_DOCKPERM:
00352                 fDockperm = state | 0xA00;
00353                 break;
00354             case CP_PLAYLOCK:
00355                 fPlayLock = state | 0xA00;
00356                 break;
00357             case CP_PLANLOCK:
00358                 fPlanLock = state | 0xA00;
00359                 break;
00360             case CP_BEAM:
00361                 if (state == 1)
00362                     fBeamup = 1 | 0x500;
00363                 else
00364                     fBeamdown = 2 | 0x500;
00365                 break;
00366             case CP_PHASER:
00367                 fPhaser = state | 0x100;
00368                 break;
00369             case CP_PLASMA:
00370                 fPlasma = state | 0x100;
00371                 break;
00372                 }
00373         }
00374 }
00375 
00376 - (void) sendServerPacketWithBuffer:(char*)buffer length:(int) size {
00377         if(commMode == COMM_UDP) {
00378                 // UDP stuff
00379                 switch (buffer[0]) {
00380                         case CP_SPEED:
00381                         case CP_DIRECTION:
00382                         case CP_PHASER:
00383                         case CP_PLASMA:
00384                         case CP_TORP:
00385                         case CP_QUIT:
00386                         case CP_PRACTR:
00387                         case CP_SHIELD:
00388                         case CP_REPAIR:
00389                         case CP_ORBIT:
00390                         case CP_PLANLOCK:
00391                         case CP_PLAYLOCK:
00392                         case CP_BOMB:
00393                         case CP_BEAM:
00394                         case CP_CLOAK:
00395                         case CP_DET_TORPS:
00396                         case CP_DET_MYTORP:
00397                         case CP_REFIT:
00398                         case CP_TRACTOR:
00399                         case CP_REPRESS:
00400                         case CP_COUP:
00401                         case CP_DOCKPERM:
00402                         case CP_PING_RESPONSE:
00403                                 // non-critical stuff, use UDP
00404                                 [udpStats increasePacketsSendBy:1];
00405                                 if ((udpSender == nil) || (![udpSender sendBuffer:buffer length:size])) {
00406                                     [notificationCenter postNotificationName:@"COMM_UDP_LINK_SEVERED" object:self 
00407                                                     userInfo:@"UDP link severed"];
00408                                     commModeRequest = commMode;
00409                                     commStatus = STAT_CONNECTED;
00410                                     [self sendUdpReq:COMM_TCP]; // should switch to TCP? $$$ not in orig code
00411                                     [self closeUdpConn];
00412                                 }
00413                 return;
00414                 break;
00415                         default:
00416                                 NSLog(@"Communications.sendServerPacketWithBuffer unknown UDP packet");
00417                                 break;
00418                 }
00419         } 
00420     
00421     // either TCP mode or critical packet
00422     if ((tcpSender == nil) || (![tcpSender sendBuffer:buffer length:size])) {
00423         NSLog(@"Communications.sendServerPacketWithBuffer TCP write error");
00424         [notificationCenter postNotificationName:@"COMM_TCP_WRITE_ERROR" object:self 
00425                                         userInfo:@"TCP write error"];
00426     }
00427 }
00428 
00429 - (void) resetForce {
00430         fSpeed = fShield = fOrbit = fRepair = fBeamup = fBeamdown = fCloak 
00431     = fBomb = fDockperm = fPhaser = fPlasma = fPlayLock = fPlanLock 
00432     = fTractor = fRepressor = -1;
00433 }
00434 
00441 - (int) forceCheckFlags:(int) flag force:(int) force type:(char)type {
00442         if (force > 0) {
00443                 if (([[universe playerThatIsMe] flags] & flag) != (force & 0xFF)) {
00444                         [self sendShortPacketNoForceWithId:type state: (force & 0xFF)];
00445                         force -= 0x100;
00446                         if (force < 0x100) {
00447                                 force = -1;  // give up
00448                         }
00449                 } 
00450                 else {
00451                         force = -1;
00452                 }
00453         }
00454         return force;
00455 }
00456 
00457 - (int) forceCheckValue:(int) value force:(int) force type:(char) type {
00458         if (force > 0) {
00459                 if (value != (force & 0xFF)) {
00460                         [self sendShortPacketNoForceWithId:type state:(force & 0xFF)];
00461                         force -= 0x100;
00462                         if (force < 0x100) {
00463                                 force = -1;     // give up
00464                         }
00465                 } 
00466                 else {
00467                         force = -1; 
00468                 }
00469         }
00470         return force;
00471 }
00472 
00473 - (int) forceCheckTractFlag:(int) flag force:(int) force type:(char) type {
00474         if (force > 0) {
00475                 if ((([[universe playerThatIsMe] flags] & flag) != 0) ^ ((force & 0xFF) != 0)) {
00476                         int state = ((force & 0xFF) >= 0x40) ? 1 : 0;
00477                         int pnum = (force & 0xFF) & (~0x40);
00478                         buffer = type;
00479                         buffer = (char)state;
00480                         buffer = (char)pnum;
00481                         [self sendServerPacketWithBuffer:buffer length:4];
00482                         force -= 0x100;
00483                         if (force < 0x100) {
00484                                 force = -1;     // give up
00485                         }
00486                 }
00487                 else {
00488                         force = -1;
00489                 }
00490         }
00491         return force;
00492 }
00493 
00494 - (void) checkForce {
00495         
00496         // speed almost always repeats because it takes a while to accelerate/decelerate
00497         // to the desired value
00498         Player *me= [universe playerThatIsMe];
00499         fSpeed    = [self forceCheckValue: [me speed] force:fSpeed type: CP_SPEED];
00500         fShield   = [self forceCheckFlags: PLAYER_SHIELD force:fShield type:CP_SHIELD];
00501         fOrbit    = [self forceCheckFlags: PLAYER_ORBIT force:fOrbit type:CP_ORBIT];
00502         fRepair   = [self forceCheckFlags: PLAYER_REPAIR force:fRepair type:CP_REPAIR];
00503         fBeamup   = [self forceCheckFlags: PLAYER_BEAMUP force:fBeamup type:CP_BEAM];
00504         fBeamdown = [self forceCheckFlags: PLAYER_BEAMDOWN force:fBeamdown type:CP_BEAM];
00505         fCloak    = [self forceCheckFlags: PLAYER_CLOAK force:fCloak type:CP_CLOAK];
00506         fBomb     = [self forceCheckFlags: PLAYER_BOMB force:fBomb type:CP_BOMB];
00507         fDockperm = [self forceCheckFlags: PLAYER_DOCKOK force:fDockperm type:CP_DOCKPERM];
00508         fPhaser   = [self forceCheckValue: [[universe phaserWithId:[me phaserId]] status] force:fPhaser type:CP_PHASER];
00509         fPlasma   = [self forceCheckValue: [[universe plasmaWithId:[me plasmaId]] status] force:fPlasma type:CP_PLASMA];
00510         fPlayLock = [self forceCheckFlags: PLAYER_PLOCK force:fPlayLock type:CP_PLAYLOCK];
00511         fPlanLock = [self forceCheckFlags: PLAYER_PLLOCK force:fPlanLock type:CP_PLANLOCK];
00512         fTractor  = [self forceCheckTractFlag: PLAYER_TRACT force:fTractor type:CP_TRACTOR];
00513         fRepressor= [self forceCheckTractFlag: PLAYER_PRESS force:fRepressor type:CP_REPRESS];
00514 }
00515 
00516 // server packets
00517 // these routines can be invoked by sending a notification
00518 // see the header file for the proper invokation
00519 // alternativly you can call them directly on the Communication object.
00520 //
00521 -(void)cleanUp:(id)sender {
00522     if (tcpReader != nil) {
00523         [self sendByeReq:self];
00524         [tcpReader close];
00525         [tcpReader release];
00526         tcpReader = nil;
00527     }
00528     if (udpReader != nil) {
00529         [udpReader close];
00530         [udpReader release];
00531         udpReader = nil;
00532     }
00533     if (udpSender != nil) {
00534         [udpSender close];
00535         [udpSender release];
00536         udpSender = nil;
00537     }
00538     if (tcpSender != nil) {
00539         [tcpSender close];
00540         [tcpSender release];
00541         tcpSender = nil;
00542     }
00543     // remove all subscriptions
00544     // run - (void)subscribeToNotifications to reconnect
00545     //[notificationCenter removeObserver:self name:nil];
00546 }
00547 
00548 -(void)readFromServer {
00549     //static NSTimeInterval start, stop;
00550     
00551     //start = [NSDate timeIntervalSinceReferenceDate]; 
00552     //NSLog(@"Communication.readFromServer(slept): %f sec", (start-stop)); 
00553     //NSLog(@"Communication.readFromServer entered");
00554     
00555     // read from UDP connection
00556     if(udpReader != nil && commStatus != STAT_SWITCH_TCP) {
00557         @try {
00558             [udpReader readFromServer];
00559         }
00560         @catch(NSException *e) {
00561             [notificationCenter postNotificationName:@"COMM_UDP_LINK_SEVERED" object:self 
00562                                             userInfo:@"UDP link severed"];
00563             [self sendUdpReq:COMM_TCP];
00564             [self closeUdpConn];
00565         }
00566         
00567         if (commStatus == STAT_VERIFY_UDP) {
00568             [notificationCenter postNotificationName:@"COMM_UDP_LINK_ESTABLISHED" object:self 
00569                                             userInfo:@"UDP link established"];
00570             [udpStats setSequence:0];// reset sequence #s
00571                 [self resetForce];
00572                 
00573                 commMode = COMM_UDP;
00574                 commStatus = STAT_CONNECTED;
00575         }
00576         
00577         [self checkForce];
00578     }
00579     
00580     // read from TCP connection
00581     @try {
00582         if(tcpReader != nil) {
00583             [tcpReader readFromServer];
00584         }
00585     }
00586     @catch(NSException *e) {
00587         NSLog(@"Communication.readFromServer exception %@: %@", [e name], [e reason] );
00588         [notificationCenter postNotificationName:@"COMM_GHOSTBUSTED" object:self 
00589                                         userInfo:@"Whoops!  We've been ghostbusted!"];
00590         if (commMode == COMM_UDP) {
00591             [self closeUdpConn];
00592         }
00593         commMode = commModeRequest = COMM_TCP;
00594         
00595         if([self connectToServerUsingNextPort]) {
00596             [notificationCenter postNotificationName:@"COMM_RESURRECTED" object:self 
00597                                             userInfo:@"Yea!  We've been resurrected!"];
00598         }
00599         else {
00600             [notificationCenter postNotificationName:@"COMM_RESURRECT_FAILED" object:self 
00601                                             userInfo:@"Sorry,  We could not be resurrected!"];
00602         }
00603     }
00604     
00605     //stop = [NSDate timeIntervalSinceReferenceDate];  
00606     //NSLog(@"Communication.readFromServer(spent): %f sec", (stop-start));
00607 }
00608 
00609 // convieniance function
00610 -(void)readFromServer:(id)sender {
00611     [self readFromServer];
00612 }
00613 
00614 - (void) sendSpeedReq:(NSNumber*) speed {
00615     [self sendShortPacketWithId:CP_SPEED state: (char)[speed intValue]];                
00616 }
00617 
00618 - (void) sendDockingReq:(NSNumber*) on {
00619     [self sendShortPacketWithId:CP_DOCKPERM boolState:[on boolValue]];
00620 }
00621 
00622 - (void) sendCloakReq:(NSNumber*) on {
00623     [self sendShortPacketWithId:CP_CLOAK boolState:[on  boolValue]];
00624 }
00625 
00626 - (void) sendRefitReq:(NSNumber *) ship {
00627     [self sendShortPacketWithId:CP_REFIT state:[ship charValue]];
00628 }
00629 
00630 - (void) sendDirReq:(NSNumber *) dir {
00631     [self sendShortPacketWithId:CP_DIRECTION state:[dir charValue]];
00632 }
00633 
00634 - (void) sendPhaserReq:(NSNumber *) dir {
00635     [self sendShortPacketWithId:CP_PHASER state:[dir charValue]];
00636 }
00637 
00638 - (void) sendTorpReq:(NSNumber *) dir {
00639     [self sendShortPacketWithId:CP_TORP state:[dir charValue]];
00640 }
00641 
00642 - (void) sendPlasmaReq:(NSNumber *) dir {
00643     [self sendShortPacketWithId:CP_PLASMA state:[dir charValue]];
00644 }
00645 
00646 - (void) sendShieldReq:(NSNumber*) on {
00647     [self sendShortPacketWithId:CP_SHIELD boolState:[on boolValue]];
00648 }
00649 
00650 - (void) sendBombReq:(NSNumber*) bomb {
00651     [self sendShortPacketWithId:CP_BOMB boolState:[bomb boolValue]];
00652 }
00653 
00654 - (void) sendBeamReq:(NSNumber*) up {
00655     [self sendShortPacketWithId:CP_BEAM state:(char)([up boolValue] ? 1 : 2)];
00656 }
00657 
00658 - (void) sendRepairReq:(NSNumber*) on {
00659     [self sendShortPacketWithId:CP_REPAIR boolState:[on boolValue]];
00660 }
00661 
00662 - (void) sendOrbitReq:(NSNumber*) orbit {
00663     [self sendShortPacketWithId:CP_ORBIT boolState:[orbit boolValue]];
00664 }
00665 
00666 - (void) sendQuitReq:(id)sender {
00667     [self sendShortPacketWithId:CP_QUIT];
00668 }
00669 
00670 - (void) sendCoupReq:(id)sender {
00671     [self sendShortPacketWithId:CP_COUP];
00672 }
00673 
00674 - (void) sendByeReq:(id)sender {
00675     [self sendShortPacketWithId:CP_BYE];
00676 }
00677 
00678 - (void) sendPractrReq:(id)sender {
00679     [self sendShortPacketWithId:CP_PRACTR];
00680 }
00681 
00682 - (void) sendDetonateReq:(id)sender {
00683     [self sendShortPacketWithId:CP_DET_TORPS];
00684 }
00685 
00686 - (void) sendPlaylockReq:(NSNumber *) player {
00687     [self sendShortPacketWithId:CP_PLAYLOCK state:(char)[player intValue]];
00688 }
00689 
00690 - (void) sendPlanlockReq:(NSNumber *) planet {
00691     [self sendShortPacketWithId:CP_PLANLOCK state:(char)[planet intValue]];
00692 }
00693 
00694 - (void) sendResetStatsReq:(NSNumber *) verify {
00695     [self sendShortPacketWithId:CP_RESETSTATS state:[verify charValue]];
00696 }
00697 
00698 - (void) sendWarReq:(NSNumber *) mask {
00699     [self sendShortPacketWithId:CP_WAR state:[mask charValue]];
00700 }
00701 
00702 - (void) sendTractorOnReq:(NSNumber *) player {
00703         buffer = CP_TRACTOR;
00704         buffer = 1; // on
00705         buffer = [player charValue];
00706         [self sendServerPacketWithBuffer:buffer length:4];
00707         // stop force
00708         fRepressor = 0;
00709         fTractor = [player charValue] | 0x40;
00710 }
00711 
00712 - (void) sendTractorOffReq:(NSNumber *) player {
00713         buffer = CP_TRACTOR;
00714         buffer = 0; // off
00715         buffer = [player charValue];
00716         [self sendServerPacketWithBuffer:buffer length:4];
00717         fTractor = 0;
00718 }
00719 
00720 - (void) sendRepressorOnReq:(NSNumber *) player {
00721         buffer = CP_REPRESS;
00722         buffer = 1; // on
00723         buffer = [player charValue];
00724         [self sendServerPacketWithBuffer:buffer length:4];
00725         // stop force
00726         fTractor = 0;
00727         fRepressor = [player charValue] | 0x40;
00728 }
00729 
00730 - (void) sendRepressorOffReq:(NSNumber *) player {
00731         buffer = CP_REPRESS;
00732         buffer = 0; // off
00733         buffer = [player charValue];
00734         [self sendServerPacketWithBuffer:buffer length:4];
00735         fRepressor = 0;
00736 }
00737 
00738 - (void) sendTeamReq:(NSDictionary *)newTeam {
00739         buffer = CP_OUTFIT;
00740         buffer = [[newTeam valueForKey:@"team"] charValue];
00741         buffer = [[newTeam valueForKey:@"ship"] charValue];
00742         [self sendServerPacketWithBuffer:buffer length:4];
00743 }
00744 
00745 -(void) sendDetMineReq:(NSNumber *) torpId {
00746         buffer = CP_DET_MYTORP;
00747         buffer = (char)(([torpId intValue] >> 8) & 0xFF);
00748         buffer = (char)([torpId intValue] & 0xFF);
00749         [self sendServerPacketWithBuffer:buffer length:4];
00750 }
00751 
00752 - (void) sendFeature:(NSDictionary *)newFeature {
00753         buffer= CP_FEATURE; 
00754         buffer = [[newFeature valueForKey:@"type"] charValue];
00755         buffer = [[newFeature valueForKey:@"arg1"] charValue];
00756         buffer = [[newFeature valueForKey:@"arg2"] charValue];
00757         [self bigEndianInteger:[[newFeature valueForKey:@"value"] intValue] inBuffer:buffer withOffset:4];
00758         NSString *name = [newFeature valueForKey:@"name"];
00759         [self insertString:name inBuffer:buffer offset:8 maxLength:79];
00760         [self sendServerPacketWithBuffer:buffer length:88];
00761 }
00762 
00763 - (void) sendLoginReq:(NSDictionary *)login {
00764         buffer= CP_LOGIN; 
00765         buffer = (char)([login valueForKey:@"query"] ? 1 : 0);
00766         NSString *name = [login valueForKey:@"name"];
00767         NSString *pass = [login valueForKey:@"pass"];
00768         NSString *log  = [login valueForKey:@"login"];
00769     [self insertString:name inBuffer:buffer offset:4 maxLength:15];
00770     [self insertString:pass inBuffer:buffer offset:20 maxLength:15];
00771     [self insertString:log  inBuffer:buffer offset:36 maxLength:15];
00772         [self sendServerPacketWithBuffer:buffer length:52];
00773 }
00774 
00807 - (void) sendPingReq:(NSNumber *)start {
00808         buffer = CP_PING_RESPONSE;
00809         buffer = (char)([start boolValue] ? 1 : 0); // on or off
00810                                                    // strange, i would expect length 3
00811                                                    // but code sais 12 prob a copy error from response
00812                                                    // checked with server: should be 12
00813         [self sendServerPacketWithBuffer:buffer length:12];
00814 }
00815 
00816 - (void) sendServerPingResponse:(NSNumber *) number {
00817         buffer = CP_PING_RESPONSE;
00818         buffer = [number charValue];
00819         buffer = (char)(ping ? 1 : 0);
00820         [self bigEndianInteger:[udpStats packetsSent] + (commMode == COMM_UDP ? 1 : 0) inBuffer:buffer withOffset:4];
00821     [self bigEndianInteger:[udpStats packetsReceived] inBuffer:buffer withOffset:8];
00822     [self sendServerPacketWithBuffer:buffer length:12];
00823 }
00824 
00825 - (void) sendMessage:(NSDictionary *)mess {
00826         buffer = CP_MESSAGE;
00827         buffer = [[mess valueForKey:@"group"] charValue];
00828         buffer = [[mess valueForKey:@"indiv"] charValue];
00829         NSString *message = [mess valueForKey:@"message"];
00830     [self insertString:message inBuffer:buffer offset:4 maxLength:79];
00831         [self sendServerPacketWithBuffer:buffer length:84];
00832 }
00833 
00834 - (void) sendUpdatePacket:(NSNumber *) updates_per_second {
00835         // avoid sending unnecairy packets
00836         if(updatesPerSecond == [updates_per_second intValue]) {
00837                 return;
00838         }
00839         updatesPerSecond = [updates_per_second intValue];
00840         buffer= CP_UPDATES;
00841         [self bigEndianInteger:1000000 / [updates_per_second intValue] inBuffer:buffer withOffset:4];
00842         [self sendServerPacketWithBuffer:buffer length:8];
00843 }
00844 
00845 - (void) sendShortReq:(NSNumber *) state {
00846         buffer = CP_S_REQ;
00847         buffer = [state charValue];
00848         buffer = shortVersion;
00849         [self sendServerPacketWithBuffer:buffer length:4];
00850     
00851         // generate proper events
00852         switch ([state charValue]) {
00853         case SPK_VON :
00854                 [notificationCenter postNotificationName:@"COMM_PACKET_REQUEST_SHORT_SENT" object:self 
00855                                             userInfo:@"Sending short packet request"];
00856             break;
00857         case SPK_VOFF :
00858                 [notificationCenter postNotificationName:@"COMM_PACKET_REQUEST_OLD_SENT" object:self 
00859                                             userInfo:@"Sending old style packet request"];
00860             break;
00861         }
00862     
00863         // reset torps if needed
00864         if(receiveShort && ([state charValue] == SPK_SALL || [state charValue] == SPK_ALL)) {
00865                 // Let the client do the work, and not the network :-)
00866                 [universe setAllTorpsStatus:TORP_FREE];
00867                 [universe setAllPlasmasStatus:PLASMA_FREE];
00868                 [universe setAllPhasersStatus:PHASER_FREE];
00869         
00870         [notificationCenter postNotificationName:@"COMM_PACKET_REQUEST_SMALL_UPDATE" object:self 
00871                                         userInfo:@"Sending small update request"];
00872         }
00873 }
00874 
00875 - (void) sendThreshold:(NSNumber*) threshold {
00876         buffer = CP_S_THRS;
00877         buffer = (char)(([threshold intValue] >> 8) & 0xFF);
00878         buffer = (char)( [threshold intValue] & 0xFF);
00879         [self sendServerPacketWithBuffer:buffer length:4];
00880 }
00881 
00882 - (void) sendDetonateMyTorpsReq:(id)sender {
00883         Torp *torp;
00884         NSArray *torps = [[universe playerThatIsMe] torps];
00885         for (int t = 0; t < [torps count]; t++) {
00886                 torp = [torps objectAtIndex:t];
00887                 if ([torp status] == TORP_MOVE || [torp status] == TORP_STRAIGHT) {
00888                         [self sendDetMineReq: [NSNumber numberWithChar:(char)[torp weaponId]]];
00889                         if (receiveShort) {
00890                                 // Let the server det for me
00891                                 // it needs only one....
00892                                 break;
00893                         }
00894                 }
00895         }
00896 }
00897 
00898 - (void) sendOptionsPacket:(id)sender {
00899     buffer = CP_OPTIONS;
00900     
00901     int flags = 
00902         (STATS_MAPMODE                          
00903          + STATS_NAMEMODE
00904          + STATS_SHOWSHIELDS                    
00905          + STATS_KEEPPEACE
00906          + STATS_SHOWLOCAL
00907          + STATS_SHOWGLOBAL);
00908     [self bigEndianInteger:flags inBuffer:buffer withOffset:4];
00909     
00910     // insert a blank string as the keymap
00911     [self insertString:@"" inBuffer:buffer offset:8 maxLength:96];
00912     [self sendServerPacketWithBuffer:buffer length:104];
00913 }
00914 
00916 - (int) sendSocketVersionAndNumberReq:(int)port {
00917     return [self sendPickSocketReq:[NSNumber numberWithInt:port]];
00918 }
00919 
00920 - (int) sendPickSocketReq {
00921     return [self sendPickSocketReq:[NSNumber numberWithInt:nextPort]];
00922 }
00923 
00924 - (int) sendPickSocketReq:(NSNumber*) startAtPort {
00925     int old_port = [startAtPort intValue];
00926     
00927     nextPort = (int)(random() * 32767);
00928     while (nextPort < 2048 || nextPort == old_port) {
00929         nextPort = ((nextPort + 10687) & 32767);
00930     }
00931     buffer = CP_SOCKET;
00932     buffer = SOCKVERSION;
00933     buffer = UDPVERSION;
00934     [self bigEndianInteger:nextPort inBuffer:buffer withOffset:4];
00935     [self sendServerPacketWithBuffer:buffer length:8];
00936     
00937     // tell everyone about our new port
00938     [notificationCenter postNotificationName:@"COMM_PICK_SOCKET_SENT" object:self 
00939                                     userInfo:[NSNumber numberWithInt:nextPort]];
00940     
00941     return nextPort;
00942 }
00943 
00944 - (void) sendUdpReq:(NSNumber*) request {
00945     char req = [request charValue];
00946     
00947     buffer = CP_UDP_REQ;
00948     buffer = (char)(req & 0xFF);
00949     
00950     // first handle the special cases    
00951     if (req >= COMM_MODE) {
00952         buffer[1] = COMM_MODE;
00953         buffer = (char)((req - COMM_MODE) & 0xFF);
00954         [self sendServerPacketWithBuffer:buffer length:8];
00955         return;
00956     }
00957     
00958     if (req == COMM_UPDATE) {
00959         if (receiveShort) {
00960             // Let the client do the work, and not the network
00961             [universe resetWeaponInfo];
00962         }
00963         
00964         [self sendServerPacketWithBuffer:buffer length:8];
00965         [notificationCenter postNotificationName:@"COMM_UPDATE_REQ_SENT" object:self 
00966                                         userInfo:@"Sent request for full update"];
00967         return;
00968     }
00969     
00970     if (req == commModeRequest) {
00971         [notificationCenter postNotificationName:@"COMM_UPDATE_REQ_DUPLICATE" object:self 
00972                                         userInfo:@"Request is in progress, do not disturb"];
00973         return;
00974     }
00975     
00976     // handle the normal cases
00977     // start by opening the connection
00978     if (req == COMM_UDP) {
00979         // open UDP port
00980         if([self openUdpConn]) {
00981             NSLog([NSString stringWithFormat:@"Communication.sendUdpReq: bind to local port %d success", localUdpPort]);
00982             [notificationCenter postNotificationName:@"COMM_UDP_REQ_SUCCESS" object:self 
00983                                             userInfo:@"UDP connection established"];
00984         }
00985         else {
00986             NSLog([NSString stringWithFormat:@"Communication.sendUdpReq: bind to local port %d failed", localUdpPort]);
00987             commModeRequest = COMM_TCP;
00988             commStatus = STAT_CONNECTED;
00989             [notificationCenter postNotificationName:@"COMM_UDP_REQ_FAILED" object:self 
00990                                             userInfo:@"Unable to establish UDP connection"];
00991             return;
00992         }
00993     }
00994     //
00995     // send the actual request
00996     buffer = CP_UDP_REQ;
00997     buffer = req;
00998     buffer = CONNMODE_PORT; // we get addr from packet
00999     [self bigEndianInteger:localUdpPort inBuffer:buffer withOffset:4];
01000     [self sendServerPacketWithBuffer:buffer length:8];
01001     
01002     // update internal state stuff
01003     commModeRequest = req;
01004     if (req == COMM_TCP) {
01005         commStatus = STAT_SWITCH_TCP;
01006     }
01007     else {
01008         commStatus = STAT_SWITCH_UDP;
01009     }
01010     
01011     NSString *message = [NSString stringWithFormat:@"UDP: Sent request for %@ mode", (req == COMM_TCP ? @"TCP" : @"UDP")];
01012     NSLog([NSString stringWithFormat:@"Communication.sendUdpReq: %@", message]);
01013     
01014     [notificationCenter postNotificationName:@"COMM_UDP_REQ_FOR_MODE" object:self 
01015                                     userInfo:message];
01016 }
01017 
01018 - (void) sendUdpVerify:(id)sender {
01019     buffer = CP_UDP_REQ;
01020     buffer = COMM_VERIFY;
01021     buffer = (char)0;
01022     [self bigEndianInteger:0 inBuffer:buffer withOffset:4];
01023     if (![udpSender sendBuffer:buffer length:8]) {
01024         NSLog(@"Communication.sendUdpVerify: UDP: send failed.  Closing UDP connection");  
01025        
01026         [notificationCenter postNotificationName:@"COMM_UDP_LINK_SEVERED" object:self 
01027                                         userInfo:@"UDP link severed"];
01028         // update vars
01029         commModeRequest = commMode;
01030         commStatus = STAT_CONNECTED;
01031         
01032         // loop back 
01033         [self sendUdpReq:COMM_TCP];
01034         [self closeUdpConn];
01035     }
01036 }
01037 
01038 //------------------------------------------------------------------------------
01039 // setup communication
01040 //------------------------------------------------------------------------------
01041 - (bool) callServer:(NSString *)server port:(int) port {
01042     
01043     ONTCPSocket *socket;
01044     ONHost *hostName;
01045     
01046     NSLog([NSString stringWithFormat:@"Communication.callServer: %@ at %d", server, port]);
01047     @try {
01048         // try this
01049         hostName = [ONHost hostForHostname:server];
01050 
01051     }
01052     @catch (NSException * e) {
01053         NSLog([NSString stringWithFormat:@"Communication.callServer: %@", [e reason]]);
01054         return NO;
01055     }    
01056    
01057     @try {
01058         // connect and create a stream
01059         socket = [ONTCPSocket tcpSocket];
01060         [socket connectToHost:hostName port:port];
01061         NSLog(@"Communication.callServer: got connection parameters");
01062         // create a sender and receiver
01063         [tcpSender release];
01064         tcpSender = [[ServerSenderTcp alloc] initWithSocket:socket];
01065         [tcpReader release];
01066         tcpReader = [[ServerReaderTcp alloc] initWithUniverse:universe communication:self socket:socket];
01067         // pickSocket() is required here to send which version we are useing of Sockets
01068         [self sendSocketVersionAndNumberReq:port];
01069     }
01070     @catch (NSException * e) {
01071         NSLog([NSString stringWithFormat:@"Communication.callServer: error connecting to %@", hostName]);
01072         return NO;
01073     }
01074     
01075     // get the server features
01076     [self sendFeature:[NSDictionary dictionaryWithObjectsAndKeys:
01077         @"FEATURE_PACKETS", @"name", 
01078         [NSNumber numberWithChar:'S'], @"type", 
01079         [NSNumber numberWithInt:1] ,   @"value", 
01080         [NSNumber numberWithInt:0],    @"arg1", 
01081         [NSNumber numberWithInt:0],    @"arg2", nil]];
01082     
01083     return YES;
01084 }
01085 
01086 // the connectToServer routines are only used when starting up with a socket on the prompt and autologin
01087 // otherwise use callServer
01088 - (bool) connectToServerUsingNextPort {
01089     // tell the server to pick a port and use it ourself
01090     return [self connectToServerUsingPort:[self sendPickSocketReq]];
01091 }
01092 
01093 - (bool) connectToServerUsingPort:(int) port {
01094     return [self connectToServerUsingPort:port expectedHost:nil];
01095 }
01096 
01097 // not sure if we need the hostname at all? it is only used in log statements
01098 - (bool) connectToServerUsingPort:(int) port expectedHost:(NSString *) host {
01099     
01100     ONHost *hostName;
01101     
01102     NSLog([NSString stringWithFormat:@"Communication.connectToServer: (%@) Waiting for connection at port %d", host, port]);
01103     
01104     // setup a TCP server, and accept the first incomming connection
01105     ONTCPSocket *serverTCPSocket, *connectionTCPSocket;
01106     
01107     @try {        
01108         serverTCPSocket = (ONTCPSocket *)[ONTCPSocket tcpSocket];
01109         [serverTCPSocket startListeningOnLocalPort:port allowingAddressReuse:YES];    
01110     }
01111     @catch (NSException * e) {
01112         NSLog(@"Communication.connectToServer: error creating socket %d", port);
01113         return false;
01114     }
01115     
01116     @try {
01117         [serverTCPSocket setTimeOut:240000]; // should set timeout to 4 min
01118         connectionTCPSocket = [serverTCPSocket acceptConnectionOnNewSocket];
01119         NSLog(@"Communication.connectToServer: got connection");
01120     }
01121     @catch (NSException * e) {
01122         NSLog(@"Communication.connectToServer: error accepting connection on socket %d", port);
01123         return false;
01124     }
01125     
01126     // use the passed hostname or else get it from the connection
01127     // (why not always get it from the connection?)
01128     if(host == nil) {
01129         hostName = [connectionTCPSocket remoteAddressHost];
01130     } else {
01131         hostName = [ONHost hostForHostname:host];
01132     }
01133     
01134     @try {
01135         // create a sender and receiver
01136         [tcpSender release];
01137         tcpSender = [[ServerSenderTcp alloc] initWithSocket:connectionTCPSocket];
01138         [tcpReader release];
01139         tcpReader = [[ServerReaderTcp alloc] initWithUniverse:universe communication:self socket:connectionTCPSocket];
01140         // pickSocket() is required here to send which version we are useing of Sockets
01141         [self sendSocketVersionAndNumberReq:port];
01142     }
01143     @catch (NSException * e) {
01144         NSLog([NSString stringWithFormat:@"Communication.connectToServer: error connecting to %@", hostName]);
01145         return false;
01146     }
01147     NSLog([NSString stringWithFormat:@"Communication.connectToServer: got connection to %@ at %d", hostName, port]);
01148     return YES;
01149 }
01150 
01151 // private UDP routine
01152 - (bool) openUdpConn {
01153     
01154     // if baseLocalUdpPort is defined, we want to start from that
01155     if(baseLocalUdpPort > 0)  {
01156         localUdpPort = baseLocalUdpPort;
01157         NSLog([NSString stringWithFormat:@"Communication.openUdp: UDP: using base port %d", baseLocalUdpPort]);
01158     }
01159     else {
01160         localUdpPort = (int)(random() * 32767);
01161     }
01162     
01163     for(int attempts = 0; attempts < MAX_PORT_RETRY; ++attempts) {
01164         while(localUdpPort < 2048) {
01165             localUdpPort = ((localUdpPort + 10687) & 32767);
01166         }
01167         
01168         @try {
01169             // connect and create a socket
01170             ONUDPSocket *udpSocket = (ONUDPSocket *)[ONUDPSocket socket];
01171             [udpSocket setLocalPortNumber: localUdpPort allowingAddressReuse: YES];
01172             [udpSocket setAllowsBroadcast: YES]; // In  case we are sending to the broadcast address
01173             
01174             [udpSocket setTimeOut:5000]; // $$ should really do this !!
01175             NSLog([NSString stringWithFormat:@"Communication.openUdp: UDP: port is %d", localUdpPort]);
01176             
01177             // setup the reader and writer
01178             [udpReader release];
01179             udpReader = [[ServerReaderUdp alloc] initWithUniverse:universe communication:self socket:udpSocket udpStats:udpStats];
01180             [udpSender release];
01181             udpSender = [[ServerSenderTcp alloc] initWithSocket:udpSocket];
01182             
01183             return true;
01184         }
01185         @catch(NSException *e) {
01186             // bind() failed, so find another port.  If we're tunneling through a
01187             // router-based firewall, we just increment; otherwise we try to mix it
01188             // up a little.  The check for ports < 2048 is done above.
01189             if(baseLocalUdpPort > 0) {
01190                 ++localUdpPort;
01191             }
01192             else {
01193                 localUdpPort = ((localUdpPort + 10687) & 32767);
01194             }
01195         }
01196     }
01197     NSLog(@"Communication.openUdp: UDP: Unable to find a local port to bind to");
01198     return false;
01199 }
01200 
01201 - (void) closeUdpConn {
01202     NSLog(@"Communication.closeUdpConn: UDP: Closing UDP socket");
01203     [udpReader close];
01204     [udpReader release];
01205     [udpSender close];
01206     [udpSender release];
01207 }
01208 
01209 - (void) forceResetToTCP {
01210     NSLog(@"Communication.forceResetToTCP: UDP: FORCE RESET REQUESTED"); 
01211     [self sendUdpReq:[NSNumber numberWithChar:COMM_TCP]];
01212 
01213     commMode = commModeRequest = COMM_TCP;
01214     commStatus = STAT_CONNECTED;
01215     [self closeUdpConn];
01216 }
01217 
01218 // THREAD stuff
01219 - (void) setUpAndRunThread:(id)sender {
01220    
01221     // create a private pool for this thread
01222     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
01223     
01224     NSLog(@"Communication.setUpAndRunThread: start running");
01225     [notificationCenter postNotificationName:@"COMM_STARTED_THREAD" object:self userInfo:nil];
01226     
01227     // add this thread to the main run loop..
01228     [[NSRunLoop currentRunLoop] run];
01229     
01230     NSLog(@"Communication.setUpAndRunThread: stop running");
01231     isRunning = NO;
01232     [notificationCenter postNotificationName:@"COMM_STOPPED_THREAD" object:self userInfo:nil];
01233     
01234     // release the pool
01235     [pool release];
01236 }
01237 
01238 - (void) run {
01239     [self run:self];
01240 }
01241 
01242 - (void) run:(id)sender {
01243     NSLog(@"Communication.run started");
01244     // keep reading in blocked mode from the server
01245     // despatch event of what we got. Some reads may result in writes within the same
01246     // thread, therefor all access to the sendXXX methods are synchronized using locks
01247     
01248     if (multiThreaded) {        
01249         //NSTimeInterval start, stop;
01250         while (keepRunning) {
01251             //start = [NSDate timeIntervalSinceReferenceDate]; 
01252             //NSLog(@"Communication.run(slept): %f sec", (start-stop));        
01253             [self readFromServer];
01254             //stop = [NSDate timeIntervalSinceReferenceDate];  
01255             //NSLog(@"Communication.run(blocking): %f sec", (stop-start));            
01256         }
01257         NSLog(@"Communication.run stopped");
01258         isRunning = NO;
01259     } else {
01260         // try a timer every 10ms when running in the main loop
01261         [NSTimer scheduledTimerWithTimeInterval: 0.001
01262                                          target:self selector:@selector(readFromServer)
01263                                        userInfo:nil 
01264                                         repeats:YES];  
01265     }
01266 }
01267 
01268 // must be called periodically if we are not in a seperate thread.
01269 - (void) periodicReadFromServer {
01270     if (isRunning && keepRunning) {
01271         [self readFromServer];
01272     }
01273 }
01274 
01275 - (bool) startCommunicationThread {
01276     // spawns seperate thread that listens to the server
01277     if (isRunning) {
01278         NSLog(@"Communication.startCommunicationThread: already running");
01279         return NO;
01280     }
01281     // detatch a new thread and start listening
01282     isRunning = YES;
01283     keepRunning = YES;
01284     //[NSThread detachNewThreadSelector:@selector(setUpAndRunThread:) toTarget:self withObject:nil];
01285     
01287     [LLThreadWorker workOn:self 
01288               withSelector:@selector(run:) 
01289                 withObject:nil
01290             didEndSelector:nil];
01291      
01292     return YES;
01293 }
01294 
01295 - (bool) stopCommunicationThread {
01296     if (!isRunning) {
01297         NSLog(@"Communication.stopCommunicationThread: not running");
01298         return NO;
01299     }  
01300     NSLog(@"Communication.stopCommunicationThread: asking thread to stop wait for notification");
01301     keepRunning = NO;   
01302     
01303     return YES;
01304 }
01305 
01306 
01307 @end

Generated on Fri Jul 28 19:15:15 2006 for MacTrek by  doxygen 1.4.7