2

I'm using NMSSH to try to upload a file. I am able to connect and authenticate successfully however the upload hangs and I get the EXC_BAD_ACCESS error on the uploadFile() function call.

I know that it usually means that I'm trying to access an object that doesn't exist but I tried using the Zombies profiler and I could see anything that stood out. In addition, I've implemented the didDisconnectWithError() and didReadError() functions but I never get any errors. Am I missing a step before uploading? Here is the code:

- (IBAction)sendPressed:(UIButton *)sender
{

    NMSSHSession *session = [NMSSHSession connectToHost:@"***.com:22" withUsername:@"***"];

    if (session.isConnected) {
        NSLog(@"Connection suceeded");

        [session authenticateByPassword:@"***"];

        if (session.isAuthorized) {
            NSLog(@"Authentication succeeded");

            NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Archive-Small" ofType:@"zip"];
            [session.channel uploadFile:filePath to:@"/test/" progress:^BOOL(NSUInteger value) {

                NSLog(@"Progress: %d", (int)value);

                return YES;
            }];
        }
    }

    [session disconnect];
}

* UPDATE *

@interface SFTPVC ()
{
    NMSSHSession *session;
}
@end

@implementation SFTPVC

- (void)viewDidLoad {
    [super viewDidLoad];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}



- (IBAction)connectPressed:(UIButton *)sender
{
    session = [NMSSHSession connectToHost:@"***:22" withUsername:@"***"];

    if (session.isConnected) {
        NSLog(@"Connection suceeded");

        [session authenticateByPassword:@"***"];

        if (session.isAuthorized) {
            NSLog(@"Authentication succeeded");
        }
    }
}

- (IBAction)sendPressed:(UIButton *)sender
{
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Archive-Small" ofType:@"zip"];
    [session.channel uploadFile:filePath to:@"/test/" progress:^BOOL(NSUInteger value) {

        NSLog(@"Progress: %d", (int)value);

        return YES;
    }];
}

- (IBAction)disconnectPressed:(UIButton *)sender
{
    [session disconnect];
}

// Session delegates
- (void)session:(NMSSHSession *)session didDisconnectWithError:(NSError *)error
{
    NSLog(@"didDisconnectWithError: %@", [error description]);
}

// Channel delegates
- (void)channel:(NMSSHChannel *)channel didReadError:(NSString *)error
{
    NSLog(@"didReadError: %@", [error description]);
}
Przemek Lach
  • 1,348
  • 2
  • 19
  • 42

2 Answers2

2

Turns out I have to use the sessions' sftp rather than the channel. Here is the full working source code.

- (IBAction)connectPressed:(UIButton *)sender
{

    self.session = [NMSSHSession connectToHost:@"***:22" withUsername:@"***"];

    if (self.session.isConnected) {
        NSLog(@"Connection suceeded");

        [self.session authenticateByPassword:@"***"];

        if (self.session.isAuthorized) {
            NSLog(@"Authentication succeeded");

            self.sftp = [NMSFTP connectWithSession:self.session];
        }
    } else {
        NSLog(@"Failed to connect to service");
    }
}

- (IBAction)sendPressed:(UIButton *)sender
{
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"10000000-b" ofType:nil];
    NSData *fileData = [[NSFileManager defaultManager] contentsAtPath:filePath];

    [self.sftp writeContents:fileData toFileAtPath:@"/test/10MB.test" progress:^BOOL(NSUInteger sent) {
        NSLog(@"%d", (int)sent);

        return YES;
    }];
}

- (IBAction)disconnectPressed:(UIButton *)sender
{
    if (self.sftp) {
        [self.sftp disconnect];
        self.sftp = nil;
    }

    if (self.session) {
        [self.session disconnect];
        self.session = nil;
    }

    NSLog(@"Disconnecting");
}
Przemek Lach
  • 1,348
  • 2
  • 19
  • 42
  • Are you still using this code? If so, what happens if you disconnect before the upload is complete? Your code uses `writeContents` which calls `writeStream` in NMSFTP.m. My code uses `resumeStream`, but it crashes with a EXC_BAD_ACCESS when I do a sftp disconnect before the upload is complete. The offending line `libssh2_sftp_close(handle)`. Fix was to call this only after a complete upload: `if (success) libssh2_sftp_close(handle)`. – Jan Ehrhardt May 27 '20 at 15:10
1

I'm not familiar with this library but it looks like you are calling uploadFile:to:progress: which runs asynchronously, then immediately disconnecting with [session disconnect].

This is probably causing the session object to be deallocated and subsequently crashing when the upload queue tries to inform it of its progress.

At a guess you need to check for the value of NSUInteger value inside your block and once it reaches 100% only then you can safely disconnect.

Rog
  • 18,602
  • 6
  • 76
  • 97
  • I separated the connection, sending, and disconnect into three different functions which map to three different buttons. Problem still exists. I've updated the code in original question. – Przemek Lach Feb 26 '15 at 03:05
  • 1
    You need to retain your `session` instance in a `@property`. Try declaring `@property (nonatomic, strong) NHSSHSession *session` and then initialising it in `connectPressed:` with `self.session = [NMSSHSession connectToHost...]`. You session object is getting deallocated at the end of the `connectPressed:` function. – Rog Feb 26 '15 at 03:16
  • So I created session as a property in my .h file. Problem persists. If I connect and then just disconnect, without trying to send anything, I get no error. So the session object is not being deallocated right after creation otherwise disconnect would fail in the same way. There must be something different about uploadFile(). I think I'm following the demo example on the website correctly [https://github.com/Lejdborg/NMSSH]. It seems straight forward so I must be missing something obvious. – Przemek Lach Feb 26 '15 at 04:04
  • Bummer maybe try the `uploadFile:to:` method just to see if it makes any difference. See http://docs.9muses.se/nmssh/Classes/NMSSHChannel.html#//api/name/uploadFile:to: – Rog Feb 26 '15 at 04:22
  • Ya that was the first one I tried with same result. I'm not really tied to this particular library. I just need a library in iOS that can upload files over SFTP. If you are familiar with another one please let me know. – Przemek Lach Feb 26 '15 at 04:28