Changeset 112

Show
Ignore:
Timestamp:
08/20/07 04:11:47 (1 year ago)
Author:
eric
Message:

Misc cleanup. Rewite how ssh-agent launch and termination are handles to reduce threads. No need for nspools on new threads

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/eric/Libs/SSHAgent.h

    r93 r112  
    99        NSString *agentSocketPath; 
    1010        NSArray *keysOnAgent; 
     11        NSTask *agentTask; 
    1112 
    1213        NSLock *agentLock; 
     
    3132- (void)handleAgentConnections; 
    3233- (void)inputFromClient:(id)object; 
    33 - (void)checkAgent
     34- (void)agentFailed:(NSNotification *)notification
    3435 
    3536- (NSArray *)currentKeysOnAgent; 
  • branches/eric/Libs/SSHAgent.m

    r93 r112  
    114114- (BOOL)isRunning 
    115115{ 
    116         return [self PID] > 0
     116        return [agentTask isRunning]
    117117} 
    118118 
     
    153153} 
    154154 
     155 
     156/* eric - 20070819 - Tried several variations before settling on this.  It gives us notification 
     157    of task termination and unfortunatly NSPipe is very bad about dealing with libc apps that don't 
     158        flush at the end of every line.  The sleep is a hack, but it works and will only happen one */ 
     159         
    155160/* Start the agent. */ 
    156161- (BOOL)start 
    157162{ 
    158         NSString *line; 
    159  
    160163        if ([self isRunning]) 
    161164        { 
     
    165168 
    166169        [self setAgentSocketPath:nil]; 
    167  
    168         if (![self socketPath]) 
    169         { 
    170                 NSLog(@"DEBUG: start: socketPath not set"); 
     170        [self setPID:-1]; 
     171         
     172        /* Create temporary path for ssh-agent */ 
     173        char template[] = "/tmp/ssh-XXXXXXXXXX/agent.XXXXX"; 
     174        char *retVal = mktemp(template); 
     175        if ( (long)retVal == -1 ) { 
     176                NSLog(@"SSHAgent start: temp path could not be generated."); 
    171177                return NO; 
    172178        } 
    173  
    174         /* Initialize a ssh-agent SSHTool, set the arguments to -c for c-shell output. */ 
    175         SSHTool *theTool = [SSHTool toolWithName:@"ssh-agent"]; 
    176         [theTool setArgument:@"-c"]; 
    177  
    178         /* Launch the agent and retrieve stdout. */ 
    179         NSString *theOutput = [theTool launchForStandardOutput]; 
    180         if (!theOutput) 
    181         { 
    182                 NSLog(@"ssh-agent didn't launch"); 
    183                 return NO; 
    184         } 
    185  
    186         /* Split the lines with delimiter ";\n". */ 
    187         NSArray *lines = [theOutput componentsSeparatedByString:@";\n"]; 
    188         NSEnumerator *e = [lines objectEnumerator]; 
    189         while (line = [e nextObject]) 
    190         { 
    191                 /* Split the line with delimiter " ". */ 
    192                 NSArray *columns = [line componentsSeparatedByString:@" "]; 
    193                 if ([columns count] != 3) 
    194                         continue; 
    195  
    196                 NSString *key = [columns objectAtIndex:1]; 
    197                 /* If 2nd column matches "SSH_AUTH_SOCK", then 3rd column is the socket path. */ 
    198                 if ([key isEqualToString:@"SSH_AUTH_SOCK"]) 
    199                         [self setAgentSocketPath:[columns objectAtIndex:2]]; 
    200  
    201                 /* If 2nd column matches "SSH_AGENT_PID", then 3rd column is the PID. */ 
    202                 else if ([key isEqualToString:@"SSH_AGENT_PID"]) 
    203                         [self setPID:[[columns objectAtIndex:2] intValue]]; 
    204         } 
     179        NSString *tempPath = [NSString stringWithCString:retVal]; 
     180 
     181        /* Setup the agentTask and launch */ 
     182        agentTask = [[[NSTask alloc] init] retain]; 
     183        [agentTask setLaunchPath:@"/usr/bin/ssh-agent"]; 
     184        [agentTask setArguments:[NSArray arrayWithObjects:@"-c",@"-d",@"-a", tempPath, nil]]; 
     185        [agentTask launch]; 
     186 
     187        /* set paths and PID's... we already know them in advance */ 
     188        [self setAgentSocketPath: tempPath]; 
     189        [self setPID:[agentTask processIdentifier]]; 
    205190 
    206191        /* If the agent is not running, or the socket path is empty then stop the agent and fail */ 
     
    211196                return NO; 
    212197        } 
     198         
     199        /* We need to give ssh-agent time to startup, it's an ugly hack but NSPipes wen't cutting it */ 
     200        sleep(1); 
    213201 
    214202        /* Handle connections in a seperate thread. */ 
    215203        [NSThread detachNewThreadSelector:@selector(handleAgentConnections) toTarget:self withObject:nil]; 
    216  
    217         /* Check if agent is alive in a seperate thread. */ 
    218         [NSThread detachNewThreadSelector:@selector(checkAgent) toTarget:self withObject:nil]; 
     204         
     205        /* Watch for terminaton of the agent */ 
     206        [[NSNotificationCenter defaultCenter] addObserver:self 
     207                selector:@selector(agentFailed:)  
     208                name:NSTaskDidTerminateNotification  
     209                object:agentTask]; 
     210 
    219211        [[NSNotificationCenter defaultCenter]  postNotificationName:@"AgentStarted" object:nil]; 
    220212 
     
    230222 
    231223        /* We don't need to check if this fails. We clean up the variables either way. */ 
     224        [agentTask terminate]; 
    232225        kill([self PID], SIGTERM); 
    233226 
     
    253246- (void)handleAgentConnections 
    254247{ 
    255         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]
     248        NSTask *currentAgent = agentTask
    256249 
    257250        /* Fill the sockaddr_un structs. */ 
     
    271264                NSLog(@"handleAgentConnections: socket() failed"); 
    272265                [self stop]; 
    273                 [pool release]; 
    274266                return; 
    275267        } 
     
    283275                        NSLog(@"handleAgentConnections: bind() failed"); 
    284276                        [self stop]; 
    285                         [pool release]; 
    286277                        return; 
    287278                } 
     
    293284                NSLog(@"handleAgentConnections: listen() failed"); 
    294285                [self stop]; 
    295                 [pool release]; 
    296286                return; 
    297287        } 
     
    305295                NSLog(@"handleAgentConnections: malloc() failed"); 
    306296                [self stop]; 
    307                 [pool release]; 
    308297                return; 
    309298        } 
     
    322311        while ((result = select(largestFileDescriptor + 1, &readFileDescriptors, NULL, NULL, NULL))) 
    323312        { 
     313                if (agentTask != currentAgent) { 
     314                        NSLog(@"handleAgentConnections: Hmmm our agent has gone away, close shop and hope the next one is up and running"); 
     315                        [self stop]; 
     316                        free(allFileDescriptors); 
     317                        return; 
     318                } 
    324319                if (result == -1 && errno == EINTR) 
    325320                        continue; 
     
    331326                        [self stop]; 
    332327                        free(allFileDescriptors); 
    333                         [pool release]; 
    334328                        return; 
    335329                } 
     
    349343                                        NSLog(@"handleAgentConnections: realloc() failed"); 
    350344                                        [self stop]; 
    351                                         [pool release]; 
    352345                                        return; 
    353346                                } 
     
    366359                                [self stop]; 
    367360                                free(allFileDescriptors); 
    368                                 [pool release]; 
    369361                                return; 
    370362                        } 
     
    379371                                [self stop]; 
    380372                                free(allFileDescriptors); 
    381                                 [pool release]; 
    382373                                return; 
    383374                        } 
     
    475466 
    476467        free(allFileDescriptors); 
    477         [pool release]; 
    478468} 
    479469 
     
    481471- (void)inputFromClient:(id)object 
    482472{ 
    483         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    484  
    485473        int destinationFileDescriptor = [[object objectAtIndex:0] intValue]; 
    486474        const char *readBuffer = [[object objectAtIndex:1] cString]; 
     
    516504                                write(sourceFileDescriptor, "\0\0\0\5\2\0\0\0\0", 9); 
    517505 
    518                                 [pool release]; 
    519506                                return; 
    520507                        } 
     
    525512                                write(sourceFileDescriptor, "\0\0\0\5\f\0\0\0\0", 9); 
    526513 
    527                                 [pool release]; 
    528514                                return; 
    529515                        } 
     
    540526        /* Write the buffer to the agent. */ 
    541527        write(destinationFileDescriptor, readBuffer, len); 
    542         [pool release]; 
    543 
    544  
    545 /* This method is called in a separate thread. It periodically checks if the ssh-agent is still alive. */ 
    546 - (void)checkAgent 
    547 
    548         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    549         int currentPID = [self PID]; 
    550         while (getpgid(currentPID) != -1) 
    551         { 
    552                 /* The agent is still alive, so sleep for a while before checking again */ 
    553                 sleep(30); 
    554                  
    555                 /* If the PID has changed while we were sleeping then the agent has been stopped and restarted. 
    556                    In this instance a new thread would have been spawned to monitor the new agent, and the agent 
    557                    we were monitoring will no longer exist.  Exit early to avoid notifying the user that the old 
    558                    agent is gone */ 
    559                 if (currentPID != [self PID]) 
    560                 { 
    561                         [pool release]; 
    562                         return; 
    563                 } 
    564         } 
    565                  
    566         [self stop]; 
    567  
     528
     529 
     530/* this method is called from a NSTask notification when the agent dies out from underneath us */ 
     531- (void)agentFailed:(NSNotification *)notification 
     532
     533        /* do nothing if the notification is not for out current agent */ 
     534        if ( [notification object] != agentTask ) { 
     535                return; 
     536        } 
     537         
    568538        /* Dictionary for the panel. */ 
    569539        NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 
     
    581551        SInt32 error; 
    582552        CFOptionFlags response; 
    583         CFUserNotificationRef notification = CFUserNotificationCreate(nil, 30, CFUserNotificationSecureTextField(0), &error, (CFDictionaryRef)dict); 
     553        CFUserNotificationRef notificationRef = CFUserNotificationCreate(nil, 30, CFUserNotificationSecureTextField(0), &error, (CFDictionaryRef)dict); 
    584554 
    585555        /* If we couldn't receive a response, return nil. */ 
    586         if (error || CFUserNotificationReceiveResponse(notification, 0, &response)) 
    587         { 
    588                 [pool release]; 
     556        if (error || CFUserNotificationReceiveResponse(notificationRef, 0, &response)) 
     557        { 
    589558                return; 
    590559        } 
     
    593562        if ((response & 0x3) == kCFUserNotificationDefaultResponse) 
    594563                [self start]; 
    595  
    596         [pool release]; 
    597564} 
    598565